} if (del->method_ptr && !del->method) {
/* Delegate created from methodInfo.MethodHandle.GetFunctionPointer() */
del->interp_method = (InterpMethod *)del->method_ptr;
+ if (mono_llvm_only)
+ // FIXME:
+ g_assert_not_reached ();
} else if (del->method) {
/* Delegate created dynamically */
del->interp_method = mono_interp_get_imethod (del->method, error);
}
}
+/* Convert a function pointer for a managed method to an InterpMethod* */
+static InterpMethod*
+ftnptr_to_imethod (gpointer addr)
+{
+ InterpMethod *imethod;
+
+ if (mono_llvm_only) {
+ ERROR_DECL (error);
+ /* Function pointers are represented by a MonoFtnDesc structure */
+ MonoFtnDesc *ftndesc = (MonoFtnDesc*)addr;
+ g_assert (ftndesc);
+ g_assert (ftndesc->method);
+
+ imethod = ftndesc->interp_method;
+ if (!imethod) {
+ imethod = mono_interp_get_imethod (ftndesc->method, error);
+ mono_error_assert_ok (error);
+ mono_memory_barrier ();
+ ftndesc->interp_method = imethod;
+ }
+ } else {
+ /* Function pointers are represented by their InterpMethod */
+ imethod = (InterpMethod*)addr;
+ }
+ return imethod;
+}
+
+static gpointer
+imethod_to_ftnptr (InterpMethod *imethod)
+{
+ if (mono_llvm_only) {
+ ERROR_DECL (error);
+ /* Function pointers are represented by a MonoFtnDesc structure */
+ MonoFtnDesc *ftndesc = imethod->ftndesc;
+ if (!ftndesc) {
+ ftndesc = mini_llvmonly_load_method_ftndesc (imethod->method, FALSE, FALSE, error);
+ mono_error_assert_ok (error);
+ mono_memory_barrier ();
+ imethod->ftndesc = ftndesc;
+ }
+ return ftndesc;
+ } else {
+ return imethod;
+ }
+}
+
static void
interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
{
- /*
- * addr is the result of an LDFTN opcode, i.e. an InterpMethod
- */
- InterpMethod *imethod = (InterpMethod*)addr;
+ /* addr is the result of an LDFTN opcode */
+ InterpMethod *imethod = ftnptr_to_imethod (addr);
if (!(imethod->method->flags & METHOD_ATTRIBUTE_STATIC)) {
MonoMethod *invoke = mono_get_delegate_invoke_internal (mono_handle_class (this_obj));
csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [4]];
- cmethod = LOCAL_VAR (ip [2], InterpMethod*);
+ /* In mixed mode, stay in the interpreter for simplicity even if there is an AOT version of the callee */
+ cmethod = ftnptr_to_imethod (LOCAL_VAR (ip [2], gpointer));
+
if (cmethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
cmethod = mono_interp_get_imethod (mono_marshal_get_native_wrapper (cmethod->method, FALSE, FALSE), error);
mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */
#undef RELOP_FP
#undef RELOP_CAST
- MINT_IN_CASE(MINT_LDFTN) {
+ MINT_IN_CASE(MINT_LDFTN_ADDR) {
LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [2]];
ip += 3;
MINT_IN_BREAK;
}
+ MINT_IN_CASE(MINT_LDFTN) {
+ InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [2]];
+
+ LOCAL_VAR (ip [1], gpointer) = imethod_to_ftnptr (m);
+ ip += 3;
+ MINT_IN_BREAK;
+ }
MINT_IN_CASE(MINT_LDVIRTFTN) {
InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [3]];
MonoObject *o = LOCAL_VAR (ip [2], MonoObject*);
NULL_CHECK (o);
-
- LOCAL_VAR (ip [1], gpointer) = get_virtual_method (m, o->vtable);
+
+ m = get_virtual_method (m, o->vtable);
+ LOCAL_VAR (ip [1], gpointer) = imethod_to_ftnptr (m);
ip += 4;
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_LDFTN_DYNAMIC) {
error_init_reuse (error);
- InterpMethod *m = mono_interp_get_imethod (LOCAL_VAR (ip [2], MonoMethod*), error);
+
+ MonoMethod *cmethod = LOCAL_VAR (ip [2], MonoMethod*);
+
+ InterpMethod *m = mono_interp_get_imethod (cmethod, error);
mono_error_assert_ok (error);
- LOCAL_VAR (ip [1], gpointer) = m;
+ LOCAL_VAR (ip [1], gpointer) = imethod_to_ftnptr (m);
ip += 3;
MINT_IN_BREAK;
}
mono_error_assert_ok (error);
}
g_assert (del->interp_method);
- LOCAL_VAR (ip [1], gpointer) = del->interp_method;
+ LOCAL_VAR (ip [1], gpointer) = imethod_to_ftnptr (del->interp_method);
ip += 3;
MINT_IN_BREAK;
}
OPDEF(MINT_UNBOX, "unbox", 4, 1, 1, MintOpClassToken)
OPDEF(MINT_LDTOKEN, "ldtoken", 3, 1, 0, MintOpShortInt)
OPDEF(MINT_LDFTN, "ldftn", 3, 1, 0, MintOpMethodToken)
+OPDEF(MINT_LDFTN_ADDR, "ldftn_addr", 3, 1, 0, MintOpMethodToken)
OPDEF(MINT_LDFTN_DYNAMIC, "ldftn.dynamic", 3, 1, 1, MintOpMethodToken)
OPDEF(MINT_LDVIRTFTN, "ldvirtftn", 4, 1, 1, MintOpMethodToken)
OPDEF(MINT_CPOBJ, "cpobj", 4, 0, 2, MintOpClassToken)
return code;
}
+/*
+ * get_ftnptr_for_method:
+ *
+ * Return a function pointer for METHOD which is indirectly callable from managed code.
+ * On llvmonly, this returns a MonoFtnDesc, otherwise it returns a normal function pointer.
+ */
+static gpointer
+get_ftnptr_for_method (MonoMethod *method, MonoError *error)
+{
+ if (!mono_llvm_only) {
+ return mono_jit_compile_method (method, error);
+ } else {
+ return mini_llvmonly_load_method_ftndesc (method, FALSE, FALSE, error);
+ }
+}
+
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
static void
invalidated_delegate_trampoline (char *desc)
callbacks.create_jit_trampoline = mono_create_jit_trampoline;
callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
callbacks.free_method = mono_jit_free_method;
+ callbacks.get_ftnptr = get_ftnptr_for_method;
#endif
callbacks.is_interpreter_enabled = mini_is_interpreter_enabled;
callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes;