Nicholas Clark wrote:
To me that feels like a hack. The current rather-too-static dispatch (to me) 
seems to be the bug, and the thing that needs fixing.
Yeah, you're right. So, I decided to try and address this. From what I can see, the problem comes up in building the v-table for the subclass. The v-tables of the parent classes are not searched for any methods that they implement when building the v-table for the subclass. Instead, entries from the deleg_pmc PMC v-table (or the ParrotObject one) are stuck in it's place.

So, in the attached patch I implemented searching v-tables of parent classes. The idea is that if it finds a method that we'd have delegated before but is implemented by a parent, it sticks the parent's method in the v-table. (Well, kinda - what I really needed to do was check that a PMC had over-ridden a method, but there is no v-table for the default PMC, so I just used the Undef PMC's v-table for now - that's *wrong* I know, but I just wanted an approximation to test the idea out with).

Anyway, I discovered two problems as a result of this. First is that a subclass is always really an instance of the ParrotClass PMC, which uses the PMC_data slot. However, Capture.pmc uses that for its data too (and I guess the situation is the same for other PMCs). Obviously both PMCs can't put their data in the same slot, so you just wind up with a segfault.

Second is that PGE segfaults now - somehow the exists_keyed of the Hash PMC is getting called now where it wasn't before. But if it wasn't before, then I'm not quite sure what *was* being called (well, it was exists_keyed in deleg_pmc, but that appears to call exists_keyed on attribute 0 (which looks me to mean whatever's in PMC_data, which would be the array of parents?! I must have misunderstood something here...)

Either way, seems problem 1 is the real issue, and problem 2 is probably just me being confused (though I'd love an explanation, from @leo ;-)).

Jonathan
Index: src/objects.c
===================================================================
--- src/objects.c       (revision 15108)
+++ src/objects.c       (working copy)
@@ -290,21 +290,41 @@
 #endif
         }
         else if (full) {
-            /*
-             * the method doesn't exist; put in the deleg_pmc vtable,
-             * but only if ParrotObject hasn't overridden the method
-             */
-            if (((void **)delegate_vtable)[i] == ((void**)object_vtable)[i]) {
-                if (ro_vtable)
-                    ((void **)ro_vtable)[i] = ((void**)deleg_pmc_vtable)[i];
-                ((void **)vtable)[i] = ((void**)deleg_pmc_vtable)[i];
+            /* See if a parent PMC has already provided an implementation of
+             * the method, and in that case put that in the v-table slot.
+             * Otherwise, stick in a delegate PMC entry or, if ParrotObject
+             * overrides it, a ParrotObject v-table entry. */
+            int num_parents = VTABLE_elements(interpreter, class->vtable->mro);
+            int p;
+            VTABLE* const default_vtable = 
+                interpreter->vtables[enum_class_Undef]; /* XXX want 
enum_class_default, but abstract. */
+            void* parent_meth = NULL;
+            for (p = 1; p < num_parents && parent_meth == NULL; p++) {
+                PMC* cur_parent = VTABLE_get_pmc_keyed_int(interpreter, 
+                    class->vtable->mro, p);
+                VTABLE* parent_vtable = cur_parent->vtable;
+                if (((void **)parent_vtable)[i] != ((void**)default_vtable)[i])
+                    parent_meth = ((void **)parent_vtable)[i];
             }
-            else {
+            
+            if (((void **)delegate_vtable)[i] != ((void**)object_vtable)[i]) {
+                /* Overridden in ParrotObject. */
                 ((void **)vtable)[i] = ((void**)object_vtable)[i];
                 if (ro_vtable)
                     ((void **)ro_vtable)[i] = ((void**)ro_object_vtable)[i];
-
             }
+            else if (parent_meth != NULL) {
+                /* We found a parent method. Use that.*/
+                if (ro_vtable)
+                    ((void **)ro_vtable)[i] = parent_meth;
+                ((void **)vtable)[i] = parent_meth;
+            }
+            else {
+                /* Not overridden in ParrotObject. */
+                if (ro_vtable)
+                    ((void **)ro_vtable)[i] = ((void**)deleg_pmc_vtable)[i];
+                ((void **)vtable)[i] = ((void**)deleg_pmc_vtable)[i];
+            }
         }
     }
 }

Reply via email to