Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mono][wasm] Fix the usage of function pointers in mixed mode. #54098

Merged
merged 3 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public static bool IsCharacterAllowed(this TextEncoderSettings settings, char ch
}
}

[ActiveIssue("https://github.com/dotnet/runtime/issues/50965", TestPlatforms.Browser)]
public class TextEncoderSettingsTests
{
[Fact]
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/icall.c
Original file line number Diff line number Diff line change
Expand Up @@ -6635,7 +6635,7 @@ ves_icall_System_Environment_get_TickCount64 (void)
gpointer
ves_icall_RuntimeMethodHandle_GetFunctionPointer (MonoMethod *method, MonoError *error)
{
return mono_compile_method_checked (method, error);
return mono_get_runtime_callbacks ()->get_ftnptr (method, error);
}

MonoBoolean
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ typedef struct {
void (*metadata_update_published) (MonoAssemblyLoadContext *alc, uint32_t generation);
void (*get_jit_stats)(gint64 *methods_compiled, gint64 *cil_code_size_bytes, gint64 *native_code_size_bytes);
void (*get_exception_stats)(guint32 *exception_count);
// Same as compile_method, but returns a MonoFtnDesc in llvmonly mode
gpointer (*get_ftnptr)(MonoMethod *method, MonoError *error);
} MonoRuntimeCallbacks;

typedef gboolean (*MonoInternalStackWalk) (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data);
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/interp/interp-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ struct InterpMethod {
MonoType *rtype;
MonoType **param_types;
MonoJitInfo *jinfo;
MonoFtnDesc *ftndesc;

guint32 locals_size;
guint32 alloca_size;
Expand Down
82 changes: 71 additions & 11 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,9 @@ interp_init_delegate (MonoDelegate *del, MonoError *error)
} 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);
Expand Down Expand Up @@ -1659,13 +1662,57 @@ interp_init_delegate (MonoDelegate *del, MonoError *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));
Expand Down Expand Up @@ -3420,7 +3467,9 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs

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));
vargaz marked this conversation as resolved.
Show resolved Hide resolved

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 */
Expand Down Expand Up @@ -6455,25 +6504,36 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
#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;
}
Expand Down Expand Up @@ -6655,7 +6715,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); 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;
}
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/interp/mintops.def
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ OPDEF(MINT_BOX_NULLABLE_PTR, "box.nullable.ptr", 4, 1, 1, MintOpShortInt)
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)
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -6859,7 +6859,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
td->ip += 5;
const gconstpointer func = mono_find_jit_icall_info ((MonoJitICallId)token)->func;

interp_add_ins (td, MINT_LDFTN);
interp_add_ins (td, MINT_LDFTN_ADDR);
push_simple_type (td, STACK_TYPE_I);
interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
td->last_ins->data [0] = get_data_item_index (td, (gpointer)func);
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/mini/llvmonly-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,10 @@ mini_llvmonly_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
MonoFtnDesc*
mini_llvmonly_create_ftndesc (MonoMethod *m, gpointer addr, gpointer arg)
{
MonoFtnDesc *ftndesc = (MonoFtnDesc*)m_method_alloc0 (m, 2 * sizeof (gpointer));
MonoFtnDesc *ftndesc = (MonoFtnDesc*)m_method_alloc0 (m, sizeof (MonoFtnDesc));
ftndesc->addr = addr;
ftndesc->arg = arg;
ftndesc->method = m;

return ftndesc;
}
Expand Down
5 changes: 4 additions & 1 deletion src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -7155,7 +7155,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
goto calli_end;
}
}
ins = (MonoInst*)mini_emit_calli_full (cfg, fsig, sp, addr, NULL, NULL, tailcall);
if (cfg->llvm_only && !(cfg->method->wrapper_type && cfg->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD))
ins = mini_emit_llvmonly_calli (cfg, fsig, sp, addr);
else
ins = (MonoInst*)mini_emit_calli_full (cfg, fsig, sp, addr, NULL, NULL, tailcall);
goto calli_end;
}
case MONO_CEE_CALL:
Expand Down
17 changes: 17 additions & 0 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -2687,6 +2687,22 @@ mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
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)
Expand Down Expand Up @@ -4326,6 +4342,7 @@ mini_init (const char *filename, const char *runtime_version)
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;
Expand Down
3 changes: 3 additions & 0 deletions src/mono/mono/mini/mini.h
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,9 @@ typedef struct
{
gpointer addr;
gpointer arg;
MonoMethod *method;
/* InterpMethod* */
gpointer interp_method;
} MonoFtnDesc;

typedef enum {
Expand Down