Пример #1
0
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;
		}
	}
}
Пример #2
0
/*
 * 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;
}