Skip to content

Commit

Permalink
[jit] Return the compiled method and an unbox trampoline from ldvirtf…
Browse files Browse the repository at this point in the history
…tn when calling ldvirtftn on a valuetype method. (#36736)

Fixes #34379.

<!--
Thank you for your Pull Request!

If you are new to contributing to Mono, please try to do your best at conforming to our coding guidelines http://www.mono-project.com/community/contributing/coding-guidelines/ but don't worry if you get something wrong. One of the project members will help you to get things landed.

Does your pull request fix any of the existing issues? Please use the following format: Fixes #issue-number
-->

Co-authored-by: vargaz <[email protected]>
  • Loading branch information
monojenkins and vargaz authored May 23, 2020
1 parent ba728d9 commit 1ed5476
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 102 deletions.
3 changes: 0 additions & 3 deletions src/mono/mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -828,9 +828,6 @@ mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *
gpointer
mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);

gpointer
mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error);

gpointer
mono_runtime_create_delegate_trampoline (MonoClass *klass);

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 @@ -7310,7 +7310,7 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionTypeHandle ref_
return_val_if_nok (error, NULL_HANDLE);
}

mono_delegate_ctor_with_method (delegate, target, NULL, method, error);
mono_delegate_ctor (delegate, target, NULL, method, error);
return_val_if_nok (error, NULL_HANDLE);
return delegate;
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/marshal.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ mono_ftnptr_to_delegate_impl (MonoClass *klass, gpointer ftn, MonoError *error)
gpointer compiled_ptr = mono_compile_method_checked (wrapper, error);
goto_if_nok (error, leave);

mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject, d), this_obj, compiled_ptr, wrapper, error);
mono_delegate_ctor (MONO_HANDLE_CAST (MonoObject, d), this_obj, compiled_ptr, wrapper, error);
goto_if_nok (error, leave);
}

Expand Down
10 changes: 3 additions & 7 deletions src/mono/mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -820,10 +820,9 @@ typedef struct {
void (*set_cast_details) (MonoClass *from, MonoClass *to);
void (*debug_log) (int level, MonoString *category, MonoString *message);
gboolean (*debug_log_is_enabled) (void);
void (*init_delegate) (MonoDelegateHandle delegate, MonoError *error);
void (*init_delegate) (MonoDelegateHandle delegate, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error);
MonoObject* (*runtime_invoke) (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error);
void* (*compile_method) (MonoMethod *method, MonoError *error);
gpointer (*create_jump_trampoline) (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error);
gpointer (*create_jit_trampoline) (MonoDomain *domain, MonoMethod *method, MonoError *error);
/* used to free a dynamic method */
void (*free_method) (MonoDomain *domain, MonoMethod *method);
Expand Down Expand Up @@ -881,11 +880,8 @@ mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *
void
mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error);

gboolean
mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error);

gboolean
mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error);
void
mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error);

MonoMethod *
mono_get_delegate_invoke_checked (MonoClass *klass, MonoError *error);
Expand Down
86 changes: 7 additions & 79 deletions src/mono/mono/metadata/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -802,18 +802,6 @@ mono_compile_method_checked (MonoMethod *method, MonoError *error)
return res;
}

gpointer
mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
{
gpointer res;

MONO_REQ_GC_NEUTRAL_MODE;

error_init (error);
res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
return res;
}

gpointer
mono_runtime_create_delegate_trampoline (MonoClass *klass)
{
Expand Down Expand Up @@ -8714,7 +8702,7 @@ mono_print_unhandled_exception (MonoObject *exc)
}

/**
* mono_delegate_ctor_with_method:
* mono_delegate_ctor:
* \param this pointer to an uninitialized delegate object
* \param target target object
* \param addr pointer to native code
Expand All @@ -8724,82 +8712,22 @@ mono_print_unhandled_exception (MonoObject *exc)
* associated with \p addr. This is useful when sharing generic code.
* In that case \p addr will most probably not be associated with the
* correct instantiation of the method.
* On failure returns FALSE and sets \p error.
* If \method is NULL, it is looked up using \addr in the JIT info tables.
*/
gboolean
mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
void
mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;

error_init (error);
MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);

g_assert (!MONO_HANDLE_IS_NULL (this_obj));
UnlockedIncrement (&mono_stats.delegate_creations);

MonoClass *klass = mono_handle_class (this_obj);
g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));

if (method)
MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);

UnlockedIncrement (&mono_stats.delegate_creations);

if (addr)
MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);

#ifndef DISABLE_REMOTING
if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
if (callbacks.interp_get_remoting_invoke) {
MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, callbacks.interp_get_remoting_invoke (method, addr, error));
} else {
g_assert (method);
method = mono_marshal_get_remoting_invoke (method, error);
return_val_if_nok (error, FALSE);
MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
}
return_val_if_nok (error, FALSE);
}
#endif

MONO_HANDLE_SET (delegate, target, target);
MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
g_assert (callbacks.init_delegate);
callbacks.init_delegate (delegate, error);
return_val_if_nok (error, FALSE);
return TRUE;
}

/**
* mono_delegate_ctor:
* \param this pointer to an uninitialized delegate object
* \param target target object
* \param addr pointer to native code
* \param error set on error.
* This is used to initialize a delegate.
* On failure returns FALSE and sets \p error.
*/
gboolean
mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
{
MONO_REQ_GC_UNSAFE_MODE;

error_init (error);
MonoDomain *domain = mono_domain_get ();
MonoJitInfo *ji;
MonoMethod *method = NULL;

g_assert (addr);

ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
/* Shared code */
if (!ji && domain != mono_get_root_domain ())
ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
if (ji) {
method = mono_jit_info_get_method (ji);
g_assert (!mono_class_is_gtd (method->klass));
}

return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
/* Done by the EE */
callbacks.init_delegate (delegate, target, addr, method, error);
}

/**
Expand Down
27 changes: 26 additions & 1 deletion src/mono/mono/mini/aot-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ struct MonoAotModule {
guint32 *unbox_trampolines_end;
guint32 *unbox_trampoline_addresses;
guint8 *unwind_info;
/* Maps method index -> unbox tramp */
gpointer *unbox_tramp_per_method;

/* Points to the mono EH data created by LLVM */
guint8 *mono_eh_frame;
Expand Down Expand Up @@ -6050,6 +6052,16 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr)
return mono_aot_get_unbox_arbitrary_trampoline (addr);
}

if (!amodule->unbox_tramp_per_method) {
gpointer arr = g_new0 (gpointer, amodule->info.nmethods);
mono_memory_barrier ();
gpointer old_arr = mono_atomic_cas_ptr ((volatile gpointer*)&amodule->unbox_tramp_per_method, arr, NULL);
if (old_arr)
g_free (arr);
}
if (amodule->unbox_tramp_per_method [method_index])
return amodule->unbox_tramp_per_method [method_index];

if (amodule->info.llvm_unbox_tramp_indexes) {
int unbox_tramp_idx;

Expand All @@ -6068,15 +6080,23 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr)
g_assert (unbox_tramp_idx < amodule->info.llvm_unbox_tramp_num);
code = ((gpointer*)(amodule->info.llvm_unbox_trampolines))[unbox_tramp_idx];
g_assert (code);

mono_memory_barrier ();
amodule->unbox_tramp_per_method [method_index] = code;

return code;
}

if (amodule->info.llvm_get_unbox_tramp) {
gpointer (*get_tramp) (int) = (gpointer (*)(int))amodule->info.llvm_get_unbox_tramp;
code = get_tramp (method_index);

if (code)
if (code) {
mono_memory_barrier ();
amodule->unbox_tramp_per_method [method_index] = code;

return code;
}
}

ut = amodule->unbox_trampolines;
Expand Down Expand Up @@ -6113,9 +6133,14 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr)
return FALSE;
}

tinfo->method = method;
tinfo->code_size = *(guint32*)symbol_addr;
tinfo->unwind_ops = mono_arch_get_cie_program ();
mono_aot_tramp_info_register (tinfo, NULL);

mono_memory_barrier ();
amodule->unbox_tramp_per_method [method_index] = code;

/* The caller expects an ftnptr */
return mono_create_ftnptr (mono_domain_get (), code);
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1658,7 +1658,7 @@ interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpoint

MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod);

mono_delegate_ctor (this_obj, target, entry, error);
mono_delegate_ctor (this_obj, target, entry, imethod->method, error);
}

/*
Expand Down
25 changes: 23 additions & 2 deletions src/mono/mono/mini/jit-icalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
{
ERROR_DECL (error);
MonoMethod *res;
gpointer addr;

if (obj == NULL) {
mono_error_set_null_reference (error);
Expand All @@ -93,8 +94,28 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
}

/* An rgctx wrapper is added by the trampolines no need to do it here */
gboolean need_unbox = m_class_is_valuetype (res->klass) && !m_class_is_valuetype (method->klass);
if (need_unbox) {
/*
* We can't return a jump trampoline here, because the trampoline code
* can't determine whenever to add an unbox trampoline (ldvirtftn) or
* not (ldftn). So compile the method here.
*/
addr = mono_compile_method_checked (res, error);
if (!is_ok (error)) {
mono_error_set_pending_exception (error);
return NULL;
}

if (mono_llvm_only && mono_method_needs_static_rgctx_invoke (res, FALSE))
// FIXME:
g_assert_not_reached ();

return mono_ldftn (res);
addr = mini_add_method_trampoline (res, addr, mono_method_needs_static_rgctx_invoke (res, FALSE), TRUE);
} else {
addr = mono_ldftn (res);
}
return addr;
}

void*
Expand Down Expand Up @@ -1463,7 +1484,7 @@ ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw,
mono_error_set_pending_exception (error);
goto leave;
}
mono_delegate_ctor (this_obj, target, addr, error);
mono_delegate_ctor (this_obj, target, addr, NULL, error);
mono_error_set_pending_exception (error);

leave:
Expand Down
10 changes: 10 additions & 0 deletions src/mono/mono/mini/mini-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,16 @@ mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
return (MonoVTable*)regs [MONO_ARCH_RGCTX_REG];
}

GSList*
mono_arch_get_cie_program (void)
{
GSList *l = NULL;

mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ARMREG_SP, 0);

return l;
}

host_mgreg_t
mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
{
Expand Down
53 changes: 48 additions & 5 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo
copy->code = info->code;
copy->code_size = info->code_size;
copy->name = g_strdup (info->name);
copy->method = info->method;

if (info->unwind_ops) {
copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, &copy->uw_info_len);
Expand Down Expand Up @@ -546,8 +547,8 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo
mono_jit_lock ();
tramp_infos = g_slist_prepend (tramp_infos, copy);
mono_jit_unlock ();
} else if (copy->uw_info) {
/* Only register trampolines that have unwind infos */
} else if (copy->uw_info || info->method) {
/* Only register trampolines that have unwind info */
register_trampoline_jit_info (domain, copy);
}

Expand Down Expand Up @@ -3748,17 +3749,60 @@ create_delegate_method_ptr (MonoMethod *method, MonoError *error)
func = mono_compile_method_checked (method, error);
return_val_if_nok (error, NULL);
} else {
gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
gpointer trampoline = mono_create_jump_trampoline (mono_domain_get (), method, TRUE, error);
return_val_if_nok (error, NULL);
func = mono_create_ftnptr (mono_domain_get (), trampoline);
}
return func;
}

static void
mini_init_delegate (MonoDelegateHandle delegate, MonoError *error)
mini_init_delegate (MonoDelegateHandle delegate, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
{
MonoDelegate *del = MONO_HANDLE_RAW (delegate);
MonoDomain *domain = MONO_HANDLE_DOMAIN (delegate);

if (!method) {
MonoJitInfo *ji;

g_assert (addr);
ji = mono_jit_info_table_find_internal (domain, mono_get_addr_from_ftnptr (addr), TRUE, TRUE);
/* Shared code */
if (!ji && domain != mono_get_root_domain ())
ji = mono_jit_info_table_find_internal (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr), TRUE, TRUE);
if (ji) {
if (ji->is_trampoline) {
/* Could be an unbox trampoline etc. */
method = ji->d.tramp_info->method;
} else {
method = mono_jit_info_get_method (ji);
g_assert (!mono_class_is_gtd (method->klass));
}
}
}

if (method)
MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);

if (addr)
MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);

#ifndef DISABLE_REMOTING
if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
if (mono_use_interpreter) {
MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, mini_get_interp_callbacks ()->get_remoting_invoke (method, addr, error));
} else {
g_assert (method);
method = mono_marshal_get_remoting_invoke (method, error);
return_if_nok (error);
MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
}
return_if_nok (error);
}
#endif

MONO_HANDLE_SET (delegate, target, target);
MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, mono_create_delegate_trampoline (domain, mono_handle_class (delegate)));

if (mono_use_interpreter) {
mini_get_interp_callbacks ()->init_delegate (del, error);
Expand Down Expand Up @@ -4377,7 +4421,6 @@ mini_init (const char *filename, const char *runtime_version)
#define JIT_TRAMPOLINES_WORK
#ifdef JIT_TRAMPOLINES_WORK
callbacks.compile_method = mono_jit_compile_method;
callbacks.create_jump_trampoline = mono_create_jump_trampoline;
callbacks.create_jit_trampoline = mono_create_jit_trampoline;
callbacks.create_delegate_trampoline = mono_create_delegate_trampoline;
callbacks.free_method = mono_jit_free_method;
Expand Down
Loading

0 comments on commit 1ed5476

Please sign in to comment.