[Mono-dev] New code to build interface vtables
Paolo Molaro
lupus at ximian.com
Mon Feb 4 09:22:41 EST 2008
On 01/29/08 Massimiliano Mantione wrote:
> Anyway, the patch passes everything here.
Did you run the corlib tests, too?
> --- mono/metadata/class.c (revision 94247)
> +++ mono/metadata/class.c (working copy)
> +#if USE_NEW_INTERFACE_VTABLE_CODE
> + // Loop on all implemented interfaces...
> + for (i = 0; i < class->interface_offsets_count; i++) {
> + MonoClass *parent = class->parent;
> + int ic_offset;
> + gboolean interface_is_explicitly_implemented_by_class;
> + int im_index;
> +
> + ic = class->interfaces_packed [i];
> + ic_offset = mono_class_interface_offset (class, ic);
> +
> + // Check if this interface is explicitly implemented (instead of just inherited)
> + if (parent != NULL) {
> + int implemented_interfaces_index;
> + interface_is_explicitly_implemented_by_class = FALSE;
> + for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
> + if (ic == class->interfaces [implemented_interfaces_index]) {
> + interface_is_explicitly_implemented_by_class = TRUE;
> + break;
> + }
> + }
You likely need to loop other all the hierarchy here, right? Because
this is not restricted to just the immediate parent.
> + } else {
> + interface_is_explicitly_implemented_by_class = TRUE;
> + }
> +
> + // Loop on all interface methods...
> + for (im_index = 0; im_index < ic->method.count; im_index++) {
> + MonoMethod *im = ic->methods [im_index];
> + int im_slot = ic_offset + im->slot;
> + MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
> +
> + // If there is an explicit implementation, just use it right away,
> + // otherwise look for a matching method
> + if (override_im == NULL) {
> + int cm_index;
> +
> + // First look for a suitable method among the class methods
> + for (cm_index = 0; cm_index < class->method.count; cm_index++) {
> + MonoMethod *cm = class->methods [cm_index];
> +
> + TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
> + if ((cm->flags & METHOD_ATTRIBUTE_VIRTUAL) && check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
> + TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
> + vtable [im_slot] = cm;
> + /* Why do we need this? */
> + if (vtable [im_slot]->slot < 0) {
> + vtable [im_slot]->slot = im_slot;
> + }
It's much simpler to use:
if (cm->slot < 0)
cm->slot = im_slot;
> + }
> + TRACE_INTERFACE_VTABLE (printf ("\n"));
> + }
> +
> + // If the slot is still empty, look in all the inherited virtual methods...
> + if ((vtable [im_slot] == NULL) && class->parent != NULL) {
> + MonoClass *parent = class->parent;
I think you need to loop over all the parents here. Please write the
appropriate test cases where the interface method is implemented by
a non-immediate parent.
> + // Reverse order, so that last added methods are preferred
> + for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
> + MonoMethod *cm = parent->vtable [cm_index];
> +
> + TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
> + if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
> + TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
> + vtable [im_slot] = cm;
> + /* Why do we need this? */
> + if (vtable [im_slot]->slot < 0) {
> + vtable [im_slot]->slot = im_slot;
> + }
> + break;
> + }
> + TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
> + }
> + }
> + } else {
> + g_assert (vtable [im_slot] == override_im);
> + }
> + }
> + }
> +
> + // If the class is not abstract, check that all its interface slots are full.
> + // The check is done here and not directly at the end of the loop above because
> + // it can happen (for injected generic array interfaces) that the same slot is
> + // processed multiple times (those interfaces have overlapping slots), and it
> + // will not always be the first pass the one that fills the slot.
> + if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
> + for (i = 0; i < class->interface_offsets_count; i++) {
> + int ic_offset;
> + int im_index;
> +
> + ic = class->interfaces_packed [i];
> + ic_offset = mono_class_interface_offset (class, ic);
> +
> + for (im_index = 0; im_index < ic->method.count; im_index++) {
> + MonoMethod *im = ic->methods [im_index];
> + int im_slot = ic_offset + im->slot;
> +
> + TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
> + im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
> + if (vtable [im_slot] == NULL) {
> + int index;
> + char *method_signature;
> + for (index = 0; index < onum; ++index) {
> + g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
> + overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
> + }
> + method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
> + printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
> + mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name);
> + g_free (method_signature);
> + for (index = 0; index < class->method.count; ++index) {
> + MonoMethod *cm = class->methods [index];
> + method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
> +
> + printf ("METHOD %s(%s)\n", cm->name, method_signature);
> + g_free (method_signature);
> + }
Move this debugging code to it's own external function so it doesn't
clutter the code.
Please make the additional tests I suggested above and adjust the code
if needed.
This looks good, thanks!
lupus
--
-----------------------------------------------------------------
lupus at debian.org debian/rules
lupus at ximian.com Monkeys do it better
More information about the Mono-devel-list
mailing list