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] Extend mono_gsharedvt_constrained_call for static calls and handle nullable value types #94787

Merged

Conversation

kotlarmilos
Copy link
Member

Description

This PR extends mono_gsharedvt_constrained_call to handle static MONO_GSHAREDVT_CONSTRAINT_CALL_TYPE_REF calls. If the cmethod is a static method, this_arg should be NULL. Also, it skips dereferencing sharedvt ref arguments if they are nullable value types.

Fixes #94467

…haredvt ref arguments if it is a nullable vtype.
@ghost
Copy link

ghost commented Nov 15, 2023

Tagging subscribers to 'os-ios': @steveisok, @akoeplinger, @kotlarmilos
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

This PR extends mono_gsharedvt_constrained_call to handle static MONO_GSHAREDVT_CONSTRAINT_CALL_TYPE_REF calls. If the cmethod is a static method, this_arg should be NULL. Also, it skips dereferencing sharedvt ref arguments if they are nullable value types.

Fixes #94467

Author: kotlarmilos
Assignees: kotlarmilos
Labels:

area-Codegen-AOT-mono, os-ios

Milestone: 9.0.0

@@ -1482,7 +1483,9 @@ mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *kl
g_assert (fsig->param_count < 16);
memcpy (new_args, args, fsig->param_count * sizeof (gpointer));
for (int i = 0; i < fsig->param_count; ++i) {
if (deref_args [i])
// If the argument is a ref or nullable non-vtype, deref it
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vargaz Please confirm this is correct.

Copy link
Member

@BrzVlad BrzVlad Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this information already known at the callsite in handle_constrained_gsharedvt_call and can be passed through deref_args? Also isn't deref_args supposed to be set only for valuetype args, why the check below?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a testcase which fails for this case ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case we want handle here is handler.Test<bool?>(true);.

Isn't this information already known at the callsite in handle_constrained_gsharedvt_call and can be passed through deref_args?

Yes, this information already known at the callsite:

if (mini_is_gsharedvt_type (fsig->params [i])) {
	MonoInst *is_deref;
	int deref_arg_reg;
	ins = mini_emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type_internal (fsig->params [i]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
	deref_arg_reg = alloc_preg (cfg);
	/* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
	EMIT_NEW_BIALU_IMM (cfg, is_deref, OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
	MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, is_gsharedvt_ins->dreg, i, is_deref->dreg);
}

Also isn't deref_args supposed to be set only for valuetype args, why the check below?

It appears that an argument is being dereferenced if the BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE. However, if the argument is a nullable value type, deref_args [i] is set because mono_class_is_nullable is checked first:

if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (impl_class)))
	return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_REF);
else if (mono_class_is_nullable (impl_class))
	return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
else
	return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);

Then, during runtime, a nullable value type is dereferenced, leading to a runtime crash. Perhaps this check (if not nullable vtype) can be moved to the handle_constrained_gsharedvt_call, which might result in larger codegen.

Is there a testcase which fails for this case ?

The fullAOT tests are not currently running on the CI. Once the job is enabled, we will check if this case is already covered. If it is not covered, we will add a runtime test. You can currently verify this by using the following sample: #94467 (comment).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would suggest this fix instead:

diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c
index 21f3252c814..442cb9a65aa 100644
--- a/src/mono/mono/mini/jit-icalls.c
+++ b/src/mono/mono/mini/jit-icalls.c
@@ -1482,7 +1482,7 @@ mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *kl
 		g_assert (fsig->param_count < 16);
 		memcpy (new_args, args, fsig->param_count * sizeof (gpointer));
 		for (int i = 0; i < fsig->param_count; ++i) {
-			if (deref_args [i])
+			if (deref_args [i] != MONO_GSHAREDVT_BOX_TYPE_VTYPE && deref_args [i] != MONO_GSHAREDVT_BOX_TYPE_NULLABLE)
 				new_args [i] = *(gpointer*)new_args [i];
 		}
 		args = new_args;
diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c
index 99a11126b62..1f359e31cc6 100644
--- a/src/mono/mono/mini/method-to-ir.c
+++ b/src/mono/mono/mini/method-to-ir.c
@@ -3896,13 +3896,8 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
 			int addr_reg;
 
 			if (mini_is_gsharedvt_type (fsig->params [i])) {
-				MonoInst *is_deref;
-				int deref_arg_reg;
 				ins = mini_emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type_internal (fsig->params [i]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
-				deref_arg_reg = alloc_preg (cfg);
-				/* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
-				EMIT_NEW_BIALU_IMM (cfg, is_deref, OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
-				MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, is_gsharedvt_ins->dreg, i, is_deref->dreg);
+				MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, is_gsharedvt_ins->dreg, i, ins->dreg);
 			} else if (has_gsharedvt) {
 				MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, is_gsharedvt_ins->dreg, i, 0);
 			}

@kotlarmilos
Copy link
Member Author

/azp run runtime-extra-platforms

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kotlarmilos
Copy link
Member Author

/azp run runtime-extra-platforms

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kotlarmilos
Copy link
Member Author

/backport to release/8.0-staging

Copy link
Contributor

github-actions bot commented Dec 8, 2023

Started backporting to release/8.0-staging: https://github.com/dotnet/runtime/actions/runs/7140806171

@vargaz
Copy link
Contributor

vargaz commented Dec 8, 2023

Would be nice to have some CI tests before a backport.

@kotlarmilos
Copy link
Member Author

Agreed. Postponing this backport until we enable fullAOT CI tests: #92057.

@kotlarmilos kotlarmilos added the blocked Issue/PR is blocked on something - see comments label Dec 8, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Jan 8, 2024
@kotlarmilos
Copy link
Member Author

/backport to release/8.0-staging

@github-actions github-actions bot unlocked this conversation Apr 24, 2024
Copy link
Contributor

Started backporting to release/8.0-staging: https://github.com/dotnet/runtime/actions/runs/8815796126

Copy link
Contributor

@kotlarmilos backporting to release/8.0-staging failed, the patch most likely resulted in conflicts:

$ git am --3way --ignore-whitespace --keep-non-patch changes.patch

Applying: [mono] Don't use this_arg in static constrained calls. Don't deref gsharedvt ref arguments if it is a nullable vtype.
Using index info to reconstruct a base tree...
M	src/mono/mono/mini/jit-icalls.c
Falling back to patching base and 3-way merge...
Auto-merging src/mono/mono/mini/jit-icalls.c
CONFLICT (content): Merge conflict in src/mono/mono/mini/jit-icalls.c
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0001 [mono] Don't use this_arg in static constrained calls. Don't deref gsharedvt ref arguments if it is a nullable vtype.
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

Copy link
Contributor

@kotlarmilos an error occurred while backporting to release/8.0-staging, please check the run log for details!

Error: git am failed, most likely due to a merge conflict.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Codegen-AOT-mono blocked Issue/PR is blocked on something - see comments os-ios Apple iOS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[net8.0-ios] App crashes on ios device when calling static abstract generic interface method in a sealed class
3 participants