Fix eql-specializer dispatch caching.
authorStas Boukarev <stassats@gmail.com>
Fri, 26 Sep 2014 20:46:35 +0000 (00:46 +0400)
committerStas Boukarev <stassats@gmail.com>
Fri, 26 Sep 2014 20:46:50 +0000 (00:46 +0400)
When the EQL specializer is a class it may clash with a class
specializer, since the class specializer is cached as a class object.
Use twice as much space for cache, the cache entry itself and a bit, 1
if it's an eql-specializer, 0 if it's a class specializer.

Fixes #295

src/c/gfun.d
src/c/main.d

index 165fb54..140fc72 100644 (file)
@@ -129,11 +129,17 @@ fill_spec_vector(cl_object vector, cl_object frame, cl_object gf)
                        FEwrong_num_arguments(gf);
                unlikely_if (spec_no >= vector->vector.dim)
                        ecl_internal_error("Too many arguments to fill_spec_vector()");
-               argtype[spec_no++] =
-                       (!ECL_LISTP(spec_type) ||
-                        Null(ecl_memql(args[spec_position], spec_type))) ?
-                       cl_class_of(args[spec_position]) :
-                       args[spec_position];
+                /* Need to differentiate between EQL specializers and
+                   class specializers, because the EQL value can be a
+                   class, and may classh with a class specializer. */
+                if (ECL_LISTP(spec_type) && ecl_memql(args[spec_position], spec_type)) {
+                        argtype[spec_no++] = args[spec_position];
+                        argtype[spec_no++] = 1;
+                } else {
+                        argtype[spec_no++] = cl_class_of(args[spec_position]);
+                        argtype[spec_no++] = 0;
+                }
+                        
        } end_loop_for_on_unsafe(spec_how_list);
        vector->vector.fillp = spec_no;
        return vector;
index 8cbe6e8..53091d1 100755 (executable)
@@ -160,7 +160,9 @@ ecl_init_env(cl_env_ptr env)
 #endif
 
 #ifdef CLOS
-       env->method_cache = ecl_make_cache(64, 4096);
+        /* Needs 128 elements for 64 entries to differentiate between
+           EQL specializers and class specializers */
+       env->method_cache = ecl_make_cache(128, 4096);
        env->slot_cache = ecl_make_cache(3, 4096);
 #endif
         env->pending_interrupt = ECL_NIL;