mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr) { MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code); MonoVTable *vt = this_argument->vtable; int displacement = slot - ((gpointer*)vt); if (displacement > 0) { /* slot is in the vtable, not in the IMT */ #if DEBUG_IMT printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot); #endif return slot; } else { MonoMethod *imt_method = mono_arch_find_imt_method (regs, code); MonoMethod *impl; int interface_offset; int imt_slot = MONO_IMT_SIZE + displacement; /*This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement*/ interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, variance_used); if (interface_offset < 0) { g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, 0), mono_type_get_name_full (&imt_method->klass->byval_arg, 0)); } mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method)); if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) { MonoGenericContext context = { NULL, NULL }; /* * Generic virtual method, imt_method contains the inflated interface * method, need to get the inflated impl method. */ /* imt_method->slot might not be set */ impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot); if (impl->klass->generic_class) context.class_inst = impl->klass->generic_class->context.class_inst; context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst; impl = mono_class_inflate_generic_method (impl, &context); } else { /* Avoid loading metadata or creating a generic vtable if possible */ if (!vt->klass->valuetype) *aot_addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method)); else *aot_addr = NULL; if (*aot_addr) impl = NULL; else impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_vtable_slot (imt_method)); } if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE)) *need_rgctx_tramp = TRUE; if (impl && impl->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) { WrapperInfo *info = mono_marshal_get_wrapper_info (impl); if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) { // FIXME: This needs a gsharedvt-out trampoline, since the caller uses the gsharedvt calling conv, but the // wrapper is a normal non-generic method. *need_rgctx_tramp = TRUE; //g_assert_not_reached (); } } *impl_method = impl; #if DEBUG_IMT printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n", method->klass->name_space, method->klass->name, method->name, imt_method->klass->name_space, imt_method->klass->name, imt_method->name); #endif g_assert (imt_slot < MONO_IMT_SIZE); if (vt->imt_collisions_bitmap & (1 << imt_slot)) { int slot = mono_method_get_vtable_index (imt_method); int vtable_offset; gpointer *vtable_slot; g_assert (slot != -1); vtable_offset = interface_offset + slot; vtable_slot = & (vt->vtable [vtable_offset]); #if DEBUG_IMT printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, and colliding becomes %p[%d] (interface_offset = %d, method->slot = %d)\n", slot, imt_slot, vtable_slot, vtable_offset, interface_offset, imt_method->slot); #endif return vtable_slot; } else { #if DEBUG_IMT printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot); #endif return slot; } } }
/* * mini_add_method_trampoline: * * Add static rgctx/gsharedvt_in/unbox trampolines to M/COMPILED_METHOD if needed. Return the trampoline address, or * COMPILED_METHOD if no trampoline is needed. * ORIG_METHOD is the method the caller originally called i.e. an iface method, or NULL. */ gpointer mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp) { gpointer addr = compiled_method; gboolean callee_gsharedvt, callee_array_helper; MonoMethod *jmethod = NULL; MonoJitInfo *ji; // FIXME: This loads information from AOT (perf problem) ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method), NULL); callee_gsharedvt = mini_jit_info_is_gsharedvt (ji); callee_array_helper = FALSE; if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) { WrapperInfo *info = mono_marshal_get_wrapper_info (m); /* * generic array helpers. * Have to replace the wrappers with the original generic instances. */ if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) { callee_array_helper = TRUE; m = info->d.generic_array_helper.method; } } else if (m->wrapper_type == MONO_WRAPPER_UNKNOWN) { WrapperInfo *info = mono_marshal_get_wrapper_info (m); /* Same for synchronized inner wrappers */ if (info && info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) { m = info->d.synchronized_inner.method; } } if (!orig_method) orig_method = m; if (callee_gsharedvt) g_assert (m->is_inflated); addr = compiled_method; if (add_unbox_tramp) { /* * The unbox trampolines call the method directly, so need to add * an rgctx tramp before them. */ if (mono_aot_only) { addr = mono_aot_get_unbox_trampoline (m); } else { unbox_trampolines ++; addr = mono_arch_get_unbox_trampoline (m, addr); } } if (ji) jmethod = jinfo_get_method (ji); if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) { MonoGenericSharingContext *gsctx; MonoMethodSignature *sig, *gsig; /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */ /* Call from normal/gshared code to gsharedvt code with variable signature */ gsctx = mono_jit_info_get_generic_sharing_context (ji); sig = mono_method_signature (m); gsig = mono_method_signature (jmethod); addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, gsctx, -1, FALSE); //printf ("IN: %s\n", mono_method_full_name (m, TRUE)); } if (callee_array_helper) { add_static_rgctx_tramp = FALSE; if (ji && ji->from_aot) { /* In AOT mode, compiled_method points to one of the InternalArray methods in Array. */ if (mono_method_needs_static_rgctx_invoke (jinfo_get_method (ji), TRUE)) add_static_rgctx_tramp = TRUE; } } if (add_static_rgctx_tramp) addr = mono_create_static_rgctx_trampoline (m, addr); return addr; }