1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

de-inline goops dispatch from the evaluator

* libguile/eval.i.c: De-inline goops dispatch from the evaluator. Part
  of a refactor.
This commit is contained in:
Andy Wingo 2009-10-30 22:21:29 +01:00
parent cb65f76c74
commit ee7ef600b9

View file

@ -744,139 +744,10 @@ dispatch:
* (c.f. objects.c:scm_mcache_compute_cmethod) since that
* cuts down execution time for type dispatch to 50%. */
type_dispatch: /* inputs: x, arg1 */
/* Type dispatch means to determine from the types of the function
* arguments (i. e. the 'signature' of the call), which method from
* a generic function is to be called. This process of selecting
* the right method takes some time. To speed it up, guile uses
* caching: Together with the macro call to dispatch the signatures
* of some previous calls to that generic function from the same
* place are stored (in the code!) in a cache that we call the
* 'method cache'. This is done since it is likely, that
* consecutive calls to dispatch from that position in the code will
* have the same signature. Thus, the type dispatch works as
* follows: First, determine a hash value from the signature of the
* actual arguments. Second, use this hash value as an index to
* find that same signature in the method cache stored at this
* position in the code. If found, you have also found the
* corresponding method that belongs to that signature. If the
* signature is not found in the method cache, you have to perform a
* full search over all signatures stored with the generic
* function. */
{
unsigned long int specializers;
unsigned long int hash_value;
unsigned long int cache_end_pos;
unsigned long int mask;
SCM method_cache;
{
SCM z = SCM_CDDR (x);
SCM tmp = SCM_CADR (z);
specializers = scm_to_ulong (SCM_CAR (z));
/* Compute a hash value for searching the method cache. There
* are two variants for computing the hash value, a (rather)
* complicated one, and a simple one. For the complicated one
* explained below, tmp holds a number that is used in the
* computation. */
if (scm_is_simple_vector (tmp))
{
/* This method of determining the hash value is much
* simpler: Set the hash value to zero and just perform a
* linear search through the method cache. */
method_cache = tmp;
mask = (unsigned long int) ((long) -1);
hash_value = 0;
cache_end_pos = SCM_SIMPLE_VECTOR_LENGTH (method_cache);
}
else
{
/* Use the signature of the actual arguments to determine
* the hash value. This is done as follows: Each class has
* an array of random numbers, that are determined when the
* class is created. The integer 'hashset' is an index into
* that array of random numbers. Now, from all classes that
* are part of the signature of the actual arguments, the
* random numbers at index 'hashset' are taken and summed
* up, giving the hash value. The value of 'hashset' is
* stored at the call to dispatch. This allows to have
* different 'formulas' for calculating the hash value at
* different places where dispatch is called. This allows
* to optimize the hash formula at every individual place
* where dispatch is called, such that hopefully the hash
* value that is computed will directly point to the right
* method in the method cache. */
unsigned long int hashset = scm_to_ulong (tmp);
unsigned long int counter = specializers + 1;
SCM tmp_arg = arg1;
hash_value = 0;
while (!scm_is_null (tmp_arg) && counter != 0)
{
SCM class = scm_class_of (SCM_CAR (tmp_arg));
hash_value += SCM_INSTANCE_HASH (class, hashset);
tmp_arg = SCM_CDR (tmp_arg);
counter--;
}
z = SCM_CDDR (z);
method_cache = SCM_CADR (z);
mask = scm_to_ulong (SCM_CAR (z));
hash_value &= mask;
cache_end_pos = hash_value;
}
}
{
/* Search the method cache for a method with a matching
* signature. Start the search at position 'hash_value'. The
* hashing implementation uses linear probing for conflict
* resolution, that is, if the signature in question is not
* found at the starting index in the hash table, the next table
* entry is tried, and so on, until in the worst case the whole
* cache has been searched, but still the signature has not been
* found. */
SCM z;
do
{
SCM args = arg1; /* list of arguments */
z = SCM_SIMPLE_VECTOR_REF (method_cache, hash_value);
while (!scm_is_null (args))
{
/* More arguments than specifiers => CLASS != ENV */
SCM class_of_arg = scm_class_of (SCM_CAR (args));
if (!scm_is_eq (class_of_arg, SCM_CAR (z)))
goto next_method;
args = SCM_CDR (args);
z = SCM_CDR (z);
}
/* Fewer arguments than specifiers => CAR != CLASS */
if (!scm_is_pair (z))
goto apply_vm_cmethod;
else if (!SCM_CLASSP (SCM_CAR (z))
&& !scm_is_symbol (SCM_CAR (z)))
goto apply_memoized_cmethod;
next_method:
hash_value = (hash_value + 1) & mask;
} while (hash_value != cache_end_pos);
/* No appropriate method was found in the cache. */
z = scm_memoize_method (x, arg1);
if (scm_is_pair (z))
goto apply_memoized_cmethod;
apply_vm_cmethod:
proc = z;
PREP_APPLY (proc, arg1);
goto apply_proc;
apply_memoized_cmethod: /* inputs: z, arg1 */
{
SCM formals = SCM_CMETHOD_FORMALS (z);
env = SCM_EXTEND_ENV (formals, arg1, SCM_CMETHOD_ENV (z));
x = SCM_CMETHOD_BODY (z);
goto nontoplevel_begin;
}
}
{
proc = scm_mcache_compute_cmethod (x, arg1);
PREP_APPLY (proc, arg1);
goto apply_proc;
}