Repository navigation
Remove JNINativeWrapper.CreateDelegate() Usage From Marshal Methods #1258
Description
Activity
In order for this approach to be viable, MonoVM needs to implement support for
Debugger.BreakForUserUnhandledException(); see also: dotnet/runtime#108211 (comment)Hopefully we can get that support for .NET 10.
We should also make this "only use blittable types" change as part of this as well: #1027
Question: should there be any "extensibility" in here, to reduce the need to change (implicit) ABI after this? I'm thinking something along the lines of:
partial class JniRuntime { public virtual void OnUnhandledException (ref JniTransition transition, Exception e) { transition.SetPendingException (e); Debugger.BreakForUserUnhandledException (e); } }
catchblocks would then call:catch (Exception __e) { JniEnvironment.Runtime.OnUnhandledException(ref __envp, __e); }
The downside is that
catchblocks become slightly slower (JniEnvironment.Runtimelooks up per-thread TLS data, plusvirtualmethod invocation), but that's in an "exceptional" path, so I'm not sure it'll matter, performance-wise.- addedenhancementProposed change to current functionalityProposed change to current functionalitygeneratorIssues binding a Java library (generator, class-parse, etc.)Issues binding a Java library (generator, class-parse, etc.)
on Sep 30, 2024 The
$(DebuggerSupport)MSBuild property toggles theSystem.Diagnostics.Debugger.IsSupportedtrimmer feature flag.We already set this by default in
Releasemode:One thing we could do, is solve this issue for Release mode by using this trimmer flag, MSBuild property, etc.? We could avoid System.Reflection.Emit for
Releasemode completely?@jonathanpeppers: I don't immediately understand your previous comment.
System.Reflection.Emitis used in two places:- Within
JNINativeWrapper.CreateDelegate() - For
Mono.Android.Export.dll: https://github.com/dotnet/android/blob/70948d5eaa72091389940fdd5a0eb828c85bdd60/src/Mono.Android.Export/CallbackCode.cs#L634-L650
This issue #1258 would remove the call to
JNINativeWrapper.CreateDelegate(), and thus remove the need for System.Reflection.Emit entirely for new bindings in .NET 10.This would not impact
[ExportAttribute]usage /Mono.Android.Export; the only way I know of to attempt to fix that would be viajnimarshalmethod-gen…- Within
- added a commit that references this issue
on Dec 18, 2024 - locked and limited conversation to collaborators
on Jan 4, 2025 - added a commit that references this issue
on Jul 1, 2026
Context: dotnet/runtime#108211
Context: dotnet/android#9306
Context: dotnet/android#9309
Context: https://github.com/xamarin/monodroid/commit/3e9de5a51bd46263b08365ef18bed1ae472122d8
Consider this marshal method and related infrastructure::
Why do we have
JNINativeWrapper.CreateDelegate()? (Closely related: why isn't there atry/catchblock inn_Accept_I()? Though part of that is "we didn't think of it.")The answer is around the "unhandled exception" experience when a debugger is attached: the debugger breaks at the "active"
throwsite. If the type will be caught by acatchblock, then you won't get an "unhandled exception" notification, which made customers sad.Which means that for a good debugger experience, we can't have
catchblocks catching exceptions; if we did, then the exceptions would be handled!Meanwhile, we must catch and marshal exceptions back to Java, otherwise we'll corrupt the JVM during stack unwind!
Where we wound up was a terrible middle:
JNINativeWrapper.CreateDelegate()usedSystem.Reflection.Emitto bridge these two worlds.However, .NET 9 introduces
System.Diagnostics.DebuggerDisableUserUnhandledExceptionsAttribute:Thus, the proposal: update the above marshal method related infrastructure to instead be:
This entirely removes
JNINativeWrapper.CreateDelegate()and in turnSystem.Reflection.Emitfrom the marshal method codepath, which should improve app startup.