+
+#ifdef ENABLE_LLVM
+/*
+ * mono_llvm_vcall_trampoline:
+ *
+ * This trampoline handles virtual calls when using LLVM.
+ */
+static gpointer
+mono_llvm_vcall_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
+{
+ MonoObject *this;
+ gpointer addr;
+ MonoVTable *vt;
+ gpointer *vtable_slot;
+ gboolean proxy = FALSE;
+
+ /*
+ * We have the method which is called, we need to obtain the vtable slot without
+ * disassembly which is impossible with LLVM.
+ * So we use the this argument.
+ */
+ this = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (m), regs, code);
+ g_assert (this);
+
+ vt = this->vtable;
+
+ /* This is a simplified version of mono_magic_trampoline () */
+ /* FIXME: Avoid code duplication */
+
+ if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+ MonoJitInfo *ji;
+
+ if (code)
+ ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
+ else
+ ji = NULL;
+
+ /* Avoid recursion */
+ if (!(ji && ji->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED))
+ m = mono_marshal_get_synchronized_wrapper (m);
+ }
+
+ addr = mono_compile_method (m);
+ g_assert (addr);
+
+ if (m->klass->valuetype)
+ addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr);
+
+ vtable_slot = &(vt->vtable [mono_method_get_vtable_slot (m)]);
+ 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, (gpointer*)regs, code, m, NULL);
+#endif
+ *vtable_slot = mono_get_addr_from_ftnptr (addr);
+ }
+
+ mono_debugger_trampoline_compiled (m, addr);
+
+ return addr;
+}
+#endif
+
+gpointer
+mono_generic_virtual_remoting_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
+{
+ MonoGenericContext context = { NULL, NULL };
+ MonoMethod *imt_method, *declaring;
+ gpointer addr;
+
+ g_assert (m->is_generic);
+
+ if (m->is_inflated)
+ declaring = mono_method_get_declaring_generic_method (m);
+ else
+ declaring = m;
+
+ if (m->klass->generic_class)
+ context.class_inst = m->klass->generic_class->context.class_inst;
+ else
+ g_assert (!m->klass->generic_container);
+
+#ifdef MONO_ARCH_HAVE_IMT
+ imt_method = mono_arch_find_imt_method ((gpointer*)regs, code);
+ if (imt_method->is_inflated)
+ context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
+#endif
+ m = mono_class_inflate_generic_method (declaring, &context);
+ m = mono_marshal_get_remoting_invoke_with_check (m);
+
+ addr = mono_compile_method (m);
+ g_assert (addr);
+
+ mono_debugger_trampoline_compiled (m, addr);
+
+ return addr;
+}