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];
+ }
}
}
}