Skip to content

Commit

Permalink
[mono][jit] Fix and optimize llvmonly+gsharedvt code generation (dotn…
Browse files Browse the repository at this point in the history
…et#61117)

* [mono][jit] Revert parts of 62eafc1.

The new approach doesn't work because it requires gsharedvt out
wrappers with signatures which might not exist in the program.

* Fix interp->aot calls to gsharedvt methods, they don't need a gsharedvt out wrapper.

* Fix the initialization of info->invoke_impl in mini_llvmonly_init_delegate (). Also initialize del->method there instead of doing it in generated code.

* Fix interp entry for gsharedvt methods.

* Extract vtable.interp_vtable into a MonoVTableEEData structure so more per-vtable ee data can be added later.

* Enable gsharedvt on wasm as an experiment.

* Add a fastpath for gsharedvt virtual calls.

* Fix/optimize interp entries for methods which cannot be AOTed.

* Instead of obtaining the interp entry wrapper using a JIT icall,
  store it as an AOT constant/rgctx entry.
* For gsharedvt methods, collect the arguments and call into
  the interpreter directly instead of using a gsharedvt out
  + interp entry wrapper.

* [mono][jit] Avoid computing a vtable arg for ctors which don't need it.

This can happen if the ctor is implemented as an intrinsics like
System.ByReference ().

* [mono][jit] Allow inline rgctx fetches during some parts of the decompose pass.

* [mono][jit] Add more specialized imt functions in llvmonly mode.

* [mono][aot] Fix the addition of generic methods from profiles.

Same as 0666ebc but for generic methods.

* Disable gsharedvt on wasm.
  • Loading branch information
vargaz authored Dec 8, 2021
1 parent 8c02da5 commit c79e093
Show file tree
Hide file tree
Showing 18 changed files with 402 additions and 114 deletions.
4 changes: 2 additions & 2 deletions src/mono/mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,8 @@ struct MonoVTable {

guint32 imt_collisions_bitmap;
MonoRuntimeGenericContext *runtime_generic_context;
/* interp virtual method table */
gpointer *interp_vtable;
/* Maintained by the Execution Engine */
gpointer ee_data;
/* do not add any fields after vtable, the structure is dynamically extended */
/* vtable contains function pointers to methods or their trampolines, at the
end there may be a slot containing the pointer to the static fields */
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/icall-signatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ ICALL_SIG (3, (object, ptr, ptr)) \
ICALL_SIG (3, (object, ptr, sizet)) \
ICALL_SIG (3, (ptr, int32, ptrref)) \
ICALL_SIG (3, (ptr, object, ptr)) \
ICALL_SIG (3, (ptr, object, int)) \
ICALL_SIG (3, (ptr, ptr, int)) \
ICALL_SIG (3, (ptr, ptr, int32)) \
ICALL_SIG (3, (ptr, ptr, ptr)) \
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/metadata/jit-icall-reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,11 @@ MONO_JIT_ICALL (mini_llvmonly_resolve_generic_virtual_call) \
MONO_JIT_ICALL (mini_llvmonly_resolve_generic_virtual_iface_call) \
MONO_JIT_ICALL (mini_llvmonly_resolve_iface_call_gsharedvt) \
MONO_JIT_ICALL (mini_llvmonly_resolve_vcall_gsharedvt) \
MONO_JIT_ICALL (mini_llvmonly_resolve_vcall_gsharedvt_fast) \
MONO_JIT_ICALL (mini_llvmonly_throw_nullref_exception) \
MONO_JIT_ICALL (mini_llvmonly_throw_aot_failed_exception) \
MONO_JIT_ICALL (mini_llvmonly_pop_lmf) \
MONO_JIT_ICALL (mini_llvmonly_get_interp_entry) \
MONO_JIT_ICALL (mini_llvmonly_interp_entry_gsharedvt) \
MONO_JIT_ICALL (mono_amd64_resume_unwind) \
MONO_JIT_ICALL (mono_amd64_start_gsharedvt_call) \
MONO_JIT_ICALL (mono_amd64_throw_corlib_exception) \
Expand Down
40 changes: 27 additions & 13 deletions src/mono/mono/mini/aot-compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -4291,6 +4291,14 @@ add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth
{
ERROR_DECL (error);

if (method->is_generic && acfg->aot_opts.profile_only) {
// Add the fully shared version to its home image
// This has already been added just need to add it to profile_methods so its not skipped
method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error);
g_hash_table_insert (acfg->profile_methods, method, method);
return;
}

if (mono_method_is_generic_sharable_full (method, TRUE, TRUE, FALSE)) {
MonoMethod *orig = method;

Expand Down Expand Up @@ -6792,6 +6800,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
case MONO_PATCH_INFO_METHOD:
case MONO_PATCH_INFO_METHOD_JUMP:
case MONO_PATCH_INFO_METHOD_FTNDESC:
case MONO_PATCH_INFO_LLVMONLY_INTERP_ENTRY:
case MONO_PATCH_INFO_ICALL_ADDR:
case MONO_PATCH_INFO_ICALL_ADDR_CALL:
case MONO_PATCH_INFO_METHOD_RGCTX:
Expand Down Expand Up @@ -8679,7 +8688,8 @@ can_encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
case MONO_PATCH_INFO_METHOD_FTNDESC:
case MONO_PATCH_INFO_METHODCONST:
case MONO_PATCH_INFO_METHOD_CODE_SLOT:
case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE: {
case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE:
case MONO_PATCH_INFO_LLVMONLY_INTERP_ENTRY: {
MonoMethod *method = patch_info->data.method;

return can_encode_method (acfg, method);
Expand Down Expand Up @@ -13015,20 +13025,24 @@ resolve_profile_data (MonoAotCompile *acfg, ProfileData *data, MonoAssembly* cur
continue;
if (mdata->inst) {
resolve_ginst (mdata->inst);
if (!mdata->inst->inst)
continue;
MonoGenericContext ctx;
if (mdata->inst->inst) {
MonoGenericContext ctx;

memset (&ctx, 0, sizeof (ctx));
ctx.method_inst = mdata->inst->inst;
memset (&ctx, 0, sizeof (ctx));
ctx.method_inst = mdata->inst->inst;

m = mono_class_inflate_generic_method_checked (m, &ctx, error);
if (!m)
continue;
sig = mono_method_signature_checked (m, error);
if (!is_ok (error)) {
mono_error_cleanup (error);
continue;
m = mono_class_inflate_generic_method_checked (m, &ctx, error);
if (!m)
continue;
sig = mono_method_signature_checked (m, error);
if (!is_ok (error)) {
mono_error_cleanup (error);
continue;
}
} else {
/* Use the generic definition */
mdata->method = m;
break;
}
}
char *sig_str = mono_signature_full_name (sig);
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/mini/aot-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -3666,7 +3666,8 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
case MONO_PATCH_INFO_ICALL_ADDR_CALL:
case MONO_PATCH_INFO_METHOD_RGCTX:
case MONO_PATCH_INFO_METHOD_CODE_SLOT:
case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE: {
case MONO_PATCH_INFO_METHOD_PINVOKE_ADDR_CACHE:
case MONO_PATCH_INFO_LLVMONLY_INTERP_ENTRY: {
MethodRef ref;
gboolean res;

Expand Down
53 changes: 20 additions & 33 deletions src/mono/mono/mini/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ mini_emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth
return mini_emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
}

if (!fsig->generic_param_count && !is_iface) {
if (!is_gsharedvt && !fsig->generic_param_count && !is_iface) {
/*
* The simplest case, a normal virtual call.
*/
Expand Down Expand Up @@ -751,22 +751,13 @@ mini_emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth

/* Fastpath */
MONO_START_BB (cfg, non_null_bb);
if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
MonoInst *wrapper_ins = mini_emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT);
int arg_reg = alloc_preg (cfg);
EMIT_NEW_UNALU (cfg, ins, OP_MOVE, arg_reg, slot_reg);
int addr_reg = alloc_preg (cfg);
EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, wrapper_ins->dreg, 0);
return mini_emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
} else {
/* Load the address + arg from the vtable slot */
EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, TARGET_SIZEOF_VOID_P);
return mini_emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
}
/* Load the address + arg from the vtable slot */
EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, slot_reg, 0);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, slot_reg, TARGET_SIZEOF_VOID_P);
return mini_emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
}

if (!fsig->generic_param_count && is_iface && !variant_iface && !special_array_interface) {
if (!is_gsharedvt && !fsig->generic_param_count && is_iface && !variant_iface && !special_array_interface) {
/*
* A simple interface call
*
Expand Down Expand Up @@ -801,18 +792,10 @@ mini_emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth
icall_args [1] = mini_emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD);
ftndesc_ins = mini_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);

if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
MonoInst *wrapper_ins = mini_emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT);
int addr_reg = alloc_preg (cfg);
EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, wrapper_ins->dreg, 0);
return mini_emit_extra_arg_calli (cfg, fsig, sp, ftndesc_ins->dreg, call_target);
} else {
return mini_emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}
return mini_emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}

if (fsig->generic_param_count || variant_iface || special_array_interface) {
if (!is_gsharedvt && (fsig->generic_param_count || variant_iface || special_array_interface)) {
/*
* This is similar to the interface case, the vtable slot points to an imt thunk which is
* dynamically extended as more instantiations are discovered.
Expand Down Expand Up @@ -876,15 +859,19 @@ mini_emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth

/* Common case */
MONO_START_BB (cfg, end_bb);
return mini_emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}

if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
MonoInst *wrapper_ins = mini_emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT);
int addr_reg = alloc_preg (cfg);
EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, wrapper_ins->dreg, 0);
return mini_emit_extra_arg_calli (cfg, fsig, sp, ftndesc_ins->dreg, call_target);
} else {
return mini_emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}
if (is_gsharedvt && !(is_iface || fsig->generic_param_count || variant_iface || special_array_interface)) {
MonoInst *ftndesc_ins;

/* Normal virtual call using a gsharedvt calling conv */
icall_args [0] = sp [0];
EMIT_NEW_ICONST (cfg, icall_args [1], slot);

ftndesc_ins = mono_emit_jit_icall (cfg, mini_llvmonly_resolve_vcall_gsharedvt_fast, icall_args);

return mini_emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
}

/*
Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/mini/decompose.c
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,9 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
first_bb = cfg->cbb;

// This code can't handle the creation of new basic blocks
cfg->disable_inline_rgctx_fetch = TRUE;

for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
MonoInst *ins;
MonoInst *prev = NULL;
Expand Down Expand Up @@ -1592,6 +1595,8 @@ mono_decompose_array_access_opts (MonoCompile *cfg)

if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
}

cfg->disable_inline_rgctx_fetch = FALSE;
}

typedef union {
Expand Down
4 changes: 3 additions & 1 deletion src/mono/mono/mini/ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#ifndef __MONO_EE_H__
#define __MONO_EE_H__

#define MONO_EE_API_VERSION 0x13
#define MONO_EE_API_VERSION 0x14

typedef struct _MonoInterpStackIter MonoInterpStackIter;

Expand Down Expand Up @@ -61,6 +61,8 @@ typedef gpointer MonoInterpFrameHandle;
MONO_EE_CALLBACK (void, mark_stack, (gpointer thread_info, GcScanFunc func, gpointer gc_data, gboolean precise)) \
MONO_EE_CALLBACK (void, jit_info_foreach, (InterpJitInfoFunc func, gpointer user_data)) \
MONO_EE_CALLBACK (gboolean, sufficient_stack, (gsize size)) \
MONO_EE_CALLBACK (void, entry_llvmonly, (gpointer res, gpointer *args, gpointer imethod)) \
MONO_EE_CALLBACK (gpointer, get_interp_method, (MonoMethod *method, MonoError *error)) \

typedef struct _MonoEECallbacks {

Expand Down
13 changes: 13 additions & 0 deletions src/mono/mono/mini/interp-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,19 @@ stub_sufficient_stack (gsize size)
g_assert_not_reached ();
}

static void
stub_entry_llvmonly (gpointer res, gpointer *args, gpointer imethod)
{
g_assert_not_reached ();
}

static gpointer
stub_get_interp_method (MonoMethod *method, MonoError *error)
{
g_assert_not_reached ();
return NULL;
}

#undef MONO_EE_CALLBACK
#define MONO_EE_CALLBACK(ret, name, sig) stub_ ## name,

Expand Down
Loading

0 comments on commit c79e093

Please sign in to comment.