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] Fix static virtual calls to generic methods from gshared code #66739

Merged
merged 6 commits into from
Apr 1, 2022
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
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 @@ -3778,7 +3778,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs
del_imethod = mono_interp_get_imethod (mono_marshal_get_native_wrapper (del_imethod->method, FALSE, FALSE), error);
mono_error_assert_ok (error);
del->interp_invoke_impl = del_imethod;
} else if (del_imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL && !del->target && !m_class_is_valuetype (del_imethod->method->klass)) {
} else if ((m_method_is_virtual (del_imethod->method) && !m_method_is_static (del_imethod->method)) && !del->target && !m_class_is_valuetype (del_imethod->method->klass)) {
// 'this' is passed dynamically, we need to recompute the target method
// with each call
del_imethod = get_virtual_method (del_imethod, LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, MonoObject*)->vtable);
Expand Down
29 changes: 19 additions & 10 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -11312,23 +11312,27 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
case MONO_CEE_LDFTN: {
MonoInst *argconst;
MonoMethod *cil_method;
gboolean gshared_static_virtual = FALSE;

cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
CHECK_CFG_ERROR;

if (constrained_class) {
if (m_method_is_static (cmethod) && mini_class_check_context_used (cfg, constrained_class))
// FIXME:
GENERIC_SHARING_FAILURE (CEE_LDFTN);
cmethod = get_constrained_method (cfg, image, n, cmethod, constrained_class, generic_context);
constrained_class = NULL;
CHECK_CFG_ERROR;
if (m_method_is_static (cmethod) && mini_class_check_context_used (cfg, constrained_class)) {
gshared_static_virtual = TRUE;
} else {
cmethod = get_constrained_method (cfg, image, n, cmethod, constrained_class, generic_context);
constrained_class = NULL;
CHECK_CFG_ERROR;
}
} else {
// we can't save token info if we have a constrained_class since
// n no longer represents the token for cmethod
mono_save_token_info (cfg, image, n, cmethod);
}

mono_class_init_internal (cmethod->klass);

mono_save_token_info (cfg, image, n, cmethod);

context_used = mini_method_check_context_used (cfg, cmethod);

cil_method = cmethod;
Expand All @@ -11342,7 +11346,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
/*
* Optimize the common case of ldftn+delegate creation
*/
if ((sp > stack_start) && (next_ip + 4 < end) && ip_in_bb (cfg, cfg->cbb, next_ip) && (next_ip [0] == CEE_NEWOBJ)) {
if (!gshared_static_virtual && (sp > stack_start) && (next_ip + 4 < end) && ip_in_bb (cfg, cfg->cbb, next_ip) && (next_ip [0] == CEE_NEWOBJ)) {
MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (next_ip + 1), NULL, generic_context);
if (ctor_method && (m_class_get_parent (ctor_method->klass) == mono_defaults.multicastdelegate_class)) {
MonoInst *target_ins, *handle_ins;
Expand Down Expand Up @@ -11420,7 +11424,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
}
}

argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
if (gshared_static_virtual) {
argconst = emit_get_rgctx_virt_method (cfg, -1, constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD);
constrained_class = NULL;
} else {
argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
}
ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
*sp++ = ins;

Expand Down
25 changes: 22 additions & 3 deletions src/mono/mono/mini/mini-generic-sharing.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ inflate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoTempl
g_assert (is_ok (error));
return isig;
}
case MONO_RGCTX_INFO_VIRT_METHOD:
case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
Expand Down Expand Up @@ -2250,6 +2251,7 @@ instantiate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoT

return mini_get_interp_callbacks ()->create_method_pointer_llvmonly (m, FALSE, error);
}
case MONO_RGCTX_INFO_VIRT_METHOD:
case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
MonoClass *iface_class = info->method->klass;
Expand All @@ -2270,10 +2272,24 @@ instantiate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoT
g_assert (m_class_get_vtable (info->klass));
method = m_class_get_vtable (info->klass) [ioffset + slot];

method = mono_class_inflate_generic_method_checked (method, context, error);
return_val_if_nok (error, NULL);

if (mono_llvm_only) {
if (info->method->is_inflated) {
MonoGenericContext *method_ctx = mono_method_get_context (info->method);
if (method_ctx->method_inst != NULL) {
MonoGenericContext tmp_context;
tmp_context.class_inst = NULL;
tmp_context.method_inst = method_ctx->method_inst;

// The resolved virtual method can be generic, in which case we need to inflate
// it with the type parameters that we are calling with.
method = mono_class_inflate_generic_method_checked (method, &tmp_context, error);
return_val_if_nok (error, NULL);
}
}

if (oti->info_type == MONO_RGCTX_INFO_VIRT_METHOD) {
return method;
} else if (mono_llvm_only) {
gpointer arg = NULL;
addr = mini_llvmonly_load_method (method, FALSE, FALSE, &arg, error);

Expand Down Expand Up @@ -2668,6 +2684,7 @@ mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
case MONO_RGCTX_INFO_BZERO: return "BZERO";
case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX: return "NULLABLE_CLASS_BOX";
case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: return "NULLABLE_CLASS_UNBOX";
case MONO_RGCTX_INFO_VIRT_METHOD: return "VIRT_METHOD";
case MONO_RGCTX_INFO_VIRT_METHOD_CODE: return "VIRT_METHOD_CODE";
case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: return "VIRT_METHOD_BOX_TYPE";
case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO: return "DELEGATE_TRAMP_INFO";
Expand Down Expand Up @@ -2773,6 +2790,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
case MONO_RGCTX_INFO_SIG_GSHAREDVT_IN_TRAMPOLINE_CALLI:
case MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI:
return data1 == data2;
case MONO_RGCTX_INFO_VIRT_METHOD:
case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: {
MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1;
Expand Down Expand Up @@ -2835,6 +2853,7 @@ mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
return MONO_PATCH_INFO_METHOD;
case MONO_RGCTX_INFO_DELEGATE_TRAMP_INFO:
return MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
case MONO_RGCTX_INFO_VIRT_METHOD:
case MONO_RGCTX_INFO_VIRT_METHOD_CODE:
case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE:
return MONO_PATCH_INFO_VIRT_METHOD;
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 @@ -1076,7 +1076,9 @@ typedef enum {
/* The InterpMethod for a method */
MONO_RGCTX_INFO_INTERP_METHOD = 35,
/* The llvmonly interp entry for a method */
MONO_RGCTX_INFO_LLVMONLY_INTERP_ENTRY = 36
MONO_RGCTX_INFO_LLVMONLY_INTERP_ENTRY = 36,
/* Same as VIRT_METHOD_CODE, but resolve MonoMethod* instead of code */
MONO_RGCTX_INFO_VIRT_METHOD = 37
} MonoRgctxInfoType;

/* How an rgctx is passed to a method */
Expand Down
6 changes: 3 additions & 3 deletions src/tests/issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1495,9 +1495,6 @@
<ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/CompatibleWithTest/**">
<Issue>Doesn't pass after LLVM AOT compilation.</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/StaticVirtualMethods/GenericContext/**">
<Issue>Static virtual methods are not yet implemented in the Mono runtime.</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/StaticVirtualMethods/InterfaceVariance/**">
<Issue>Static virtual methods are not yet implemented in the Mono runtime.</Issue>
</ExcludeList>
Expand Down Expand Up @@ -3752,6 +3749,9 @@
<ExcludeList Include = "$(XunitTestBinBase)/tracing/eventpipe/reverseouter/**">
<Issue>Cannot run multiple apps on Android for subprocesses</Issue>
</ExcludeList>
<ExcludeList Include = "$(XunitTestBinBase)/Loader/classloader/StaticVirtualMethods/GenericContext/**">
<Issue>https://github.com/dotnet/runtime/issues/67359</Issue>
</ExcludeList>
</ItemGroup>

<ItemGroup Condition=" $(TargetOS) == 'Android' And '$(TargetArchitecture)' == 'arm64' " >
Expand Down