* from JITted and LLVM compiled code.
*/
static gpointer
-common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp, MonoVTable *vt, gpointer *vtable_slot, gboolean need_rgctx_tramp)
+common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tramp, MonoVTable *vt, gpointer *vtable_slot, gboolean need_rgctx_tramp)
{
gpointer addr, compiled_method;
gboolean generic_shared = FALSE;
- MonoMethod *m;
MonoMethod *declaring = NULL;
MonoMethod *generic_virtual = NULL, *variant_iface = NULL;
int context_used;
gboolean virtual, proxy = FALSE, variance_used = FALSE;
- gpointer *orig_vtable_slot;
+ gpointer *orig_vtable_slot, *imt_vcall_slot = NULL;
MonoJitInfo *ji = NULL;
- /* The first case is for !llvm, the second is for llvm */
- virtual = (arg == MONO_FAKE_VTABLE_METHOD) || ((gpointer)vtable_slot > (gpointer)vt);
-
- m = arg;
+ virtual = (gpointer)vtable_slot > (gpointer)vt;
orig_vtable_slot = vtable_slot;
- if (m == MONO_FAKE_VTABLE_METHOD) {
- int displacement;
- if (!vt) {
- int i;
- MonoJitInfo *ji;
-
- ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
- if (ji)
- printf ("Caller: %s\n", mono_method_full_name (ji->method, TRUE));
- /* Print some debug info */
- for (i = 0; i < 32; ++i)
- printf ("0x%x ", code [-32 + i]);
- printf ("\n");
- g_assert (vt);
- }
- displacement = (guint8*)vtable_slot - (guint8*)vt;
- if (displacement > 0) {
- int slot = (displacement - G_STRUCT_OFFSET (MonoVTable, vtable)) / sizeof (gpointer);
- g_assert (slot >= 0);
-
- /* Avoid loading metadata or creating a generic vtable if possible */
- addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
- if (addr)
- addr = mono_create_ftnptr (mono_domain_get (), addr);
- if (addr && !vt->klass->valuetype) {
- vtable_slot = mono_get_vcall_slot_addr (code, regs);
- if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
- *vtable_slot = mono_get_addr_from_ftnptr (addr);
- }
-
- return addr;
- }
-
- /*
- * Bug #616463 (see
- * is_generic_method_definition() above) also
- * goes away if we do a
- * mono_class_setup_vtable (vt->klass) here,
- * because we then inflate the method
- * correctly, put it in the cache, and the
- * "wrong" inflation invocation still looks up
- * the correctly inflated method.
- *
- * The hack above seems more stable and
- * trustworthy.
- */
- m = mono_class_get_vtable_entry (vt->klass, slot);
- if (mono_method_needs_static_rgctx_invoke (m, FALSE))
- need_rgctx_tramp = TRUE;
-
- /*g_print ("%s with disp %d: %s at %p\n", vt->klass->name, displacement, m->name, code);*/
- } else {
- /* We got here from an interface method: redirect to IMT handling */
- m = MONO_FAKE_IMT_METHOD;
- /*g_print ("vtable with disp %d at %p\n", displacement, code);*/
- }
- }
-
- /* this is the IMT trampoline */
#ifdef MONO_ARCH_HAVE_IMT
- if (m == MONO_FAKE_IMT_METHOD) {
+ /* IMT call */
+ if (vt && (gpointer)vtable_slot < (gpointer)vt) {
MonoMethod *impl_method;
MonoObject *this_arg;
proxy = TRUE;
m = mono_object_get_virtual_method (this_arg, m);
} else {
- vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, &impl_method, &need_rgctx_tramp, &variance_used);
+ imt_vcall_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, &impl_method, &need_rgctx_tramp, &variance_used);
+ vtable_slot = imt_vcall_slot;
/* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
* to be called, so we compile it and go ahead as usual.
*/
vtable_slot = orig_vtable_slot;
if (vtable_slot) {
- gboolean variance_used = FALSE;
if (m->klass->valuetype)
addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr, need_rgctx_tramp);
g_assert (*vtable_slot);
if (!proxy && (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))) {
-#ifdef MONO_ARCH_HAVE_IMT
- vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, NULL, &need_rgctx_tramp, &variance_used);
-#endif
+ if (imt_vcall_slot)
+ /* This is the vcall slot which gets called through the IMT thunk */
+ vtable_slot = imt_vcall_slot;
*vtable_slot = mono_get_addr_from_ftnptr (addr);
}
}
/**
* mono_magic_trampoline:
*
- * This trampoline handles calls from JITted code.
+ * This trampoline handles normal calls from JITted code.
*/
gpointer
mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
{
- gpointer *vtable_slot;
- int displacement;
- MonoVTable *vt;
-
trampoline_calls ++;
- if (code && !mono_use_llvm)
- vt = mono_arch_get_vcall_slot (code, regs, &displacement);
- else
- vt = NULL;
- if (vt)
- vtable_slot = (gpointer*)((char*)vt + displacement);
- else
- vtable_slot = NULL;
-
- return common_call_trampoline (regs, code, arg, tramp, vt, vtable_slot, FALSE);
+ return common_call_trampoline (regs, code, arg, tramp, NULL, NULL, FALSE);
}
-#ifdef MONO_ARCH_LLVM_SUPPORTED
/*
- * mono_llvm_vcall_trampoline:
+ * mono_vcall_trampoline:
*
- * This trampoline handles virtual calls when using LLVM.
+ * This trampoline handles virtual calls.
*/
static gpointer
-mono_llvm_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
+mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
{
MonoObject *this;
MonoVTable *vt;
gpointer *vtable_slot;
MonoMethod *m;
- gboolean need_rgctx_tramp;
+ gboolean need_rgctx_tramp = FALSE;
+ int displacement;
+ gpointer addr;
trampoline_calls ++;
* We need to obtain the following pieces of information:
* - the method which needs to be compiled.
* - the vtable slot.
- * Since disassembly is impossible with LLVM, we use one vtable trampoline per
- * vtable slot index, and obtain the method using this index + the this argument.
- * This requires us to always pass this as the first argument, regardless of the
- * signature.
+ * We use one vtable trampoline per vtable slot index, so we need only the vtable,
+ * the other two can be computed from the vtable + the slot index.
*/
+ if (mono_use_llvm) {
+ /*
+ * Since disassembly is impossible with LLVM, we obtain the vtable using
+ * the this argument. This requires us to always pass this as the first argument,
+ * regardless of the signature.
+ */
#ifndef MONO_ARCH_THIS_AS_FIRST_ARG
- NOT_IMPLEMENTED;
+ NOT_IMPLEMENTED;
#endif
+ this = mono_arch_get_this_arg_from_call (NULL, NULL, regs, code);
+ g_assert (this);
- this = mono_arch_get_this_arg_from_call (NULL, NULL, regs, code);
- g_assert (this);
+ vt = this->vtable;
+ } else {
+ /*
+ * Obtain the vtable pointer in an arch specific manner.
+ */
+ vt = mono_arch_get_vcall_slot (code, regs, &displacement);
- vt = this->vtable;
+ if (!vt) {
+ int i;
+ MonoJitInfo *ji;
- if (slot < 0) {
- m = MONO_FAKE_IMT_METHOD;
- need_rgctx_tramp = FALSE;
- vtable_slot = &(((gpointer*)vt) [slot]);
- } else {
+ ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
+ if (ji)
+ printf ("Caller: %s\n", mono_method_full_name (ji->method, TRUE));
+ /* Print some debug info */
+ for (i = 0; i < 32; ++i)
+ printf ("0x%x ", code [-32 + i]);
+ printf ("\n");
+ g_assert (vt);
+ }
+ }
+
+ if (slot >= 0) {
+ /* Normal virtual call */
+ vtable_slot = &(vt->vtable [slot]);
+
+ /* Avoid loading metadata or creating a generic vtable if possible */
+ addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
+ if (addr && !vt->klass->valuetype) {
+ if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
+ *vtable_slot = addr;
- m = mono_class_get_vtable_entry (this->vtable->klass, slot);
+ return mono_create_ftnptr (mono_domain_get (), addr);
+ }
+
+ /*
+ * Bug #616463 (see
+ * is_generic_method_definition() above) also
+ * goes away if we do a
+ * mono_class_setup_vtable (vt->klass) here,
+ * because we then inflate the method
+ * correctly, put it in the cache, and the
+ * "wrong" inflation invocation still looks up
+ * the correctly inflated method.
+ *
+ * The hack above seems more stable and
+ * trustworthy.
+ */
+ m = mono_class_get_vtable_entry (vt->klass, slot);
need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (m, 0);
+ } else {
+ /* IMT call */
+ vtable_slot = &(((gpointer*)vt) [slot]);
- vtable_slot = &(vt->vtable [slot]);
+ m = NULL;
+ need_rgctx_tramp = FALSE;
}
+ // FIXME:
+ // - get rid of the non-vcall cases in mono_arch_get_vcall_slot
+
return common_call_trampoline (regs, code, m, tramp, vt, vtable_slot, need_rgctx_tramp);
}
-#endif
gpointer
mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
guint32 token;
MonoMethod *method = NULL;
gpointer addr;
- gpointer *vtable_slot;
guint8 *plt_entry;
trampoline_calls ++;
addr = mono_create_ftnptr (mono_domain_get (), addr);
- vtable_slot = mono_get_vcall_slot_addr (code, regs);
- g_assert (!vtable_slot);
-
/* This is a normal call through a PLT entry */
plt_entry = mono_aot_get_plt_entry (code);
g_assert (plt_entry);
return mono_monitor_enter_trampoline;
case MONO_TRAMPOLINE_MONITOR_EXIT:
return mono_monitor_exit_trampoline;
-#ifdef MONO_ARCH_LLVM_SUPPORTED
- case MONO_TRAMPOLINE_LLVM_VCALL:
- return mono_llvm_vcall_trampoline;
-#endif
+ case MONO_TRAMPOLINE_VCALL:
+ return mono_vcall_trampoline;
#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
case MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD:
return mono_handler_block_guard_trampoline;
mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
-#ifdef MONO_ARCH_LLVM_SUPPORTED
- mono_trampoline_code [MONO_TRAMPOLINE_LLVM_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_LLVM_VCALL);
-#endif
+ mono_trampoline_code [MONO_TRAMPOLINE_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_VCALL);
#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
mono_trampoline_code [MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD] = create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
mono_create_handler_block_trampoline ();
}
#ifdef MONO_ARCH_LLVM_SUPPORTED
-/*
- * mono_create_llvm_vcall_trampoline:
- *
- * LLVM emits code for virtual calls which mono_get_vcall_slot is unable to
- * decode, i.e. only the final branch address is available:
- * mov <offset>(%rax), %rax
- * <random code inserted by instruction scheduling>
- * call *%rax
- *
- * To work around this problem, we don't use the common vtable trampoline when
- * llvm is enabled. Instead, we use one trampoline per method.
- */
-gpointer
-mono_create_llvm_vcall_trampoline (MonoMethod *method)
-{
- MonoDomain *domain;
- gpointer res;
-
- domain = mono_domain_get ();
-
- mono_domain_lock (domain);
- res = g_hash_table_lookup (domain_jit_info (domain)->llvm_vcall_trampoline_hash, method);
- mono_domain_unlock (domain);
- if (res)
- return res;
-
- res = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_LLVM_VCALL, domain, NULL);
-
- mono_domain_lock (domain);
- g_hash_table_insert (domain_jit_info (domain)->llvm_vcall_trampoline_hash, method, res);
- mono_domain_unlock (domain);
-
- return res;
-}
-
/*
* mono_create_llvm_imt_trampoline:
*
gpointer
mini_get_vtable_trampoline (int slot_index)
{
- if (!mono_use_llvm) {
- /* Use only one trampoline */
- if (slot_index < 0) {
- static gpointer tramp = NULL;
-
- if (!tramp)
- tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
- return tramp;
- } else {
- static gpointer tramp = NULL;
+ int index = slot_index + MONO_IMT_SIZE;
- if (!tramp)
- tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
- return tramp;
- }
- } else {
- int index = slot_index + MONO_IMT_SIZE;
-
- /* For LLVM, use one trampoline per vtable slot index */
- g_assert (slot_index >= - MONO_IMT_SIZE);
- if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
- mono_jit_lock ();
- if (!vtable_trampolines || index >= vtable_trampolines_size) {
- int new_size;
- gpointer new_table;
-
- new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
- while (new_size <= index)
- new_size *= 2;
- new_table = g_new0 (gpointer, new_size);
-
- if (vtable_trampolines)
- memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
- mono_memory_barrier ();
- vtable_trampolines = new_table;
- vtable_trampolines_size = new_size;
- }
- mono_jit_unlock ();
+ g_assert (slot_index >= - MONO_IMT_SIZE);
+ if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
+ mono_jit_lock ();
+ if (!vtable_trampolines || index >= vtable_trampolines_size) {
+ int new_size;
+ gpointer new_table;
+
+ new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
+ while (new_size <= index)
+ new_size *= 2;
+ new_table = g_new0 (gpointer, new_size);
+
+ if (vtable_trampolines)
+ memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
+ mono_memory_barrier ();
+ vtable_trampolines = new_table;
+ vtable_trampolines_size = new_size;
}
-
-#ifdef MONO_ARCH_LLVM_SUPPORTED
- if (!vtable_trampolines [index])
- vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_LLVM_VCALL, mono_get_root_domain (), NULL);
- return vtable_trampolines [index];
-#else
- g_assert_not_reached ();
-#endif
+ mono_jit_unlock ();
}
+
+ if (!vtable_trampolines [index])
+ vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
+ return vtable_trampolines [index];
}
static gpointer