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][llvmonly] Optimize virtual calls/rgctx fetches in gsharedvt methods. #60491

Merged
merged 2 commits into from
Oct 19, 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
3 changes: 3 additions & 0 deletions src/mono/mono/mini/aot-compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -6925,6 +6925,9 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
case MONO_PATCH_INFO_FIELD:
encode_field_info (acfg, (MonoClassField *)template_->data, p, &p);
break;
case MONO_PATCH_INFO_METHOD:
encode_method_ref (acfg, (MonoMethod*)template_->data, p, &p);
break;
default:
g_assert_not_reached ();
break;
Expand Down
6 changes: 6 additions & 0 deletions src/mono/mono/mini/aot-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -3906,6 +3906,12 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
if (!template_->data)
goto cleanup;
break;
case MONO_PATCH_INFO_METHOD:
template_->data = decode_resolve_method_ref (aot_module, p, &p, error);
mono_error_cleanup (error); /* FIXME don't swallow the error */
if (!template_->data)
goto cleanup;
break;
default:
g_assert_not_reached ();
break;
Expand Down
43 changes: 33 additions & 10 deletions src/mono/mono/mini/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ mini_emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth
helper_sig_llvmonly_imt_trampoline = tmp;
}

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

/* Fastpath */
MONO_START_BB (cfg, non_null_bb);
/* 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 (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);
}
}

if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt && !special_array_interface) {
if (!fsig->generic_param_count && is_iface && !variant_iface && !special_array_interface) {
/*
* A simple interface call
*
Expand Down Expand Up @@ -780,10 +788,17 @@ mini_emit_llvmonly_virtual_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMeth
cmethod, MONO_RGCTX_INFO_METHOD);
ftndesc_ins = mini_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);

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 ((fsig->generic_param_count || variant_iface || special_array_interface) && !is_gsharedvt) {
if (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 @@ -847,7 +862,15 @@ 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);
}
}

/*
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/llvmonly-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,7 @@ gpointer
mini_llvmonly_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
{
ERROR_DECL (error);

gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, error);
if (!is_ok (error)) {
MonoException *ex = mono_error_convert_to_exception (error);
Expand Down
44 changes: 34 additions & 10 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,9 @@ mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean i
return res;
}

static MonoInst*
emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type);

static MonoInst*
emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
{
Expand All @@ -2584,8 +2587,8 @@ emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEnt
EMIT_NEW_AOTCONST (cfg, slot_ins, MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);

// Can't add basic blocks during decompose/interp entry mode etc.
// FIXME: Add a fastpath for in_mrgctx
if (cfg->after_method_to_ir || cfg->gsharedvt || cfg->interp_entry_only || entry->in_mrgctx) {
// Can't add basic blocks to the gsharedvt init block either
if (cfg->after_method_to_ir || entry->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO || cfg->interp_entry_only) {
MonoInst *args [2] = { rgctx, slot_ins };
if (entry->in_mrgctx)
call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
Expand All @@ -2610,13 +2613,19 @@ emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEnt
NEW_BBLOCK (cfg, end_bb);
NEW_BBLOCK (cfg, slowpath_bb);

rgctx_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
// FIXME: Avoid this check by allocating the table when the vtable is created etc.
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
if (entry->in_mrgctx) {
rgctx_reg = rgctx->dreg;
} else {
rgctx_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
// FIXME: Avoid this check by allocating the table when the vtable is created etc.
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
}

int table_size = mono_class_rgctx_get_array_size (0, FALSE);
int table_size = mono_class_rgctx_get_array_size (0, entry->in_mrgctx);
if (entry->in_mrgctx)
table_size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (TARGET_SIZEOF_VOID_P);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, slot_ins->dreg, table_size - 1);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBGE, slowpath_bb);

Expand All @@ -2627,7 +2636,7 @@ emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEnt
EMIT_NEW_UNALU (cfg, ins, OP_MOVE, addr_reg, rgctx_reg);
EMIT_NEW_BIALU (cfg, ins, OP_PADD, addr_reg, addr_reg, shifted_slot_reg);
int val_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, addr_reg, TARGET_SIZEOF_VOID_P);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, addr_reg, TARGET_SIZEOF_VOID_P + (entry->in_mrgctx ? MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT : 0));

MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, slowpath_bb);
Expand All @@ -2641,7 +2650,10 @@ emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEnt
slowpath_bb->out_of_line = TRUE;

MonoInst *args[2] = { rgctx, slot_ins };
call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
if (entry->in_mrgctx)
call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
else
call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, call->dreg);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);

Expand Down Expand Up @@ -2694,6 +2706,10 @@ mini_emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
}
}

// Its cheaper to load these from the gsharedvt info struct
if (cfg->llvm_only && cfg->gsharedvt)
return mini_emit_get_gsharedvt_info_klass (cfg, klass, rgctx_type);

MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used_is_mrgctx (cfg, context_used), MONO_PATCH_INFO_CLASS, klass, rgctx_type);

return emit_rgctx_fetch (cfg, context_used, entry);
Expand Down Expand Up @@ -2789,6 +2805,10 @@ emit_get_rgctx_method (MonoCompile *cfg, int context_used,
g_assert_not_reached ();
}
} else {
// Its cheaper to load these from the gsharedvt info struct
if (cfg->llvm_only && cfg->gsharedvt)
return emit_get_gsharedvt_info (cfg, cmethod, rgctx_type);

MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used_is_mrgctx (cfg, context_used), MONO_PATCH_INFO_METHODCONST, cmethod, rgctx_type);

return emit_rgctx_fetch (cfg, context_used, entry);
Expand All @@ -2799,6 +2819,10 @@ static MonoInst*
emit_get_rgctx_field (MonoCompile *cfg, int context_used,
MonoClassField *field, MonoRgctxInfoType rgctx_type)
{
// Its cheaper to load these from the gsharedvt info struct
if (cfg->llvm_only && cfg->gsharedvt)
return emit_get_gsharedvt_info (cfg, field, rgctx_type);

MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->method, context_used_is_mrgctx (cfg, context_used), MONO_PATCH_INFO_FIELD, field, rgctx_type);

return emit_rgctx_fetch (cfg, context_used, entry);
Expand Down
22 changes: 22 additions & 0 deletions src/mono/mono/mini/mini-generic-sharing.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ inflate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoTempl
case MONO_RGCTX_INFO_METHOD_FTNDESC:
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT:
case MONO_RGCTX_INFO_METHOD_RGCTX:
case MONO_RGCTX_INFO_METHOD_CONTEXT:
case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
Expand Down Expand Up @@ -2231,6 +2232,17 @@ instantiate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoT
return mini_llvmonly_create_ftndesc (m, addr, arg);
}
}
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT: {
MonoMethod *m = (MonoMethod*)data;
gpointer addr;

/* A gsharedvt out wrapper for the signature of M */
g_assert (mono_llvm_only);
addr = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature_internal (m), NULL, -1, FALSE);

/* Returns an ftndesc */
return mini_llvmonly_create_ftndesc (m, addr, NULL);
}
case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
MonoClass *iface_class = info->method->klass;
Expand Down Expand Up @@ -2614,6 +2626,7 @@ mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO: return "GSHAREDVT_INFO";
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER: return "GSHAREDVT_OUT_WRAPPER";
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT: return "GSHAREDVT_OUT_WRAPPER_VIRT";
case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
Expand Down Expand Up @@ -2726,6 +2739,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
case MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO:
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT:
case MONO_RGCTX_INFO_CLASS_FIELD:
case MONO_RGCTX_INFO_FIELD_OFFSET:
case MONO_RGCTX_INFO_METHOD_RGCTX:
Expand Down Expand Up @@ -2784,9 +2798,17 @@ mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX:
case MONO_RGCTX_INFO_LOCAL_OFFSET:
return MONO_PATCH_INFO_CLASS;
case MONO_RGCTX_INFO_CLASS_FIELD:
case MONO_RGCTX_INFO_FIELD_OFFSET:
return MONO_PATCH_INFO_FIELD;
case MONO_RGCTX_INFO_METHOD:
case MONO_RGCTX_INFO_METHOD_RGCTX:
case MONO_RGCTX_INFO_METHOD_FTNDESC:
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER:
case MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT:
return MONO_PATCH_INFO_METHOD;
default:
printf ("%d\n", info_type);
g_assert_not_reached ();
return (MonoJumpInfoType)-1;
}
Expand Down
4 changes: 3 additions & 1 deletion src/mono/mono/mini/mini.h
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,9 @@ typedef enum {
/* Same as MONO_PATCH_INFO_METHOD_FTNDESC */
MONO_RGCTX_INFO_METHOD_FTNDESC = 33,
/* mono_type_size () for a class */
MONO_RGCTX_INFO_CLASS_SIZEOF = 34
MONO_RGCTX_INFO_CLASS_SIZEOF = 34,
/* A gsharedvt_out wrapper for a method */
MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER_VIRT = 35
} MonoRgctxInfoType;

/* How an rgctx is passed to a method */
Expand Down