Skip to content

Conversation

@jonpryor
Copy link
Contributor

Context: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#improved-method-group-conversion-to-delegate Context: #1034 Context: dotnet/roslyn#62832

C#11 introduced a "slight semantic" change with "Improved method group conversion to delegate":

The C# 11 compiler caches the delegate object created from a method
group conversion and reuses that single delegate object.

The result of optimization is that for current generator-emitted code such as:

static Delegate GetFooHandler ()
{
  if (cb_foo == null)
    cb_foo = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_Foo);
  return cb_foo;
}

The (_JniMarshal_PP_V) n_Foo expression is a "method group conversion", and under C#11 the generated IL is larger, as the delegate instance is cached in case it is needed again.

However in our case we know the delegate instance won't be needed again, not in this scope, so all this "optimization" does for us is increase the size of our binding assemblies when built under C#11.

Review src/Java.Interop for use of new JniNativeMethodRegistration and replace "cast-style" method group conversions (D) M to "new-style" delegate conversions new D(M). This explicitly "opts-out" of the C#11 optimization.

Context: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#improved-method-group-conversion-to-delegate
Context: dotnet#1034
Context: dotnet/roslyn#62832

C#11 introduced a "slight semantic" change with "Improved method
group conversion to delegate":

> The C# 11 compiler caches the delegate object created from a method
> group conversion and reuses that single delegate object.

The result of optimization is that for current `generator`-emitted
code such as:

	static Delegate GetFooHandler ()
	{
	  if (cb_foo == null)
	    cb_foo = JNINativeWrapper.CreateDelegate ((_JniMarshal_PP_V) n_Foo);
	  return cb_foo;
	}

The `(_JniMarshal_PP_V) n_Foo` expression is a "method group
conversion", and under C#11 the generated IL is *larger*, as the
delegate instance is *cached* in case it is needed again.

However in *our* case we *know* the delegate instance won't be needed
again, not in this scope, so all this "optimization" does *for us* is
increase the size of our binding assemblies when built under  C#11.

Review `src/Java.Interop` for use of `new JniNativeMethodRegistration`
and replace "cast-style" method group conversions `(D) M` to
"new-style" delegate conversions `new D(M)`.  This explicitly
"opts-out" of the C#11 optimization.
@jonpryor jonpryor merged commit f498fcf into dotnet:main Oct 11, 2022
jonpryor pushed a commit to dotnet/android that referenced this pull request Nov 1, 2022
Fixes: dotnet/java-interop#1034
Fixes: dotnet/java-interop#1051

Context: 938b2cb

Changes: dotnet/java-interop@e1ee4b1...5318261

  * dotnet/java-interop@53182615: [build] Update Microsoft.* NuGet package versions (dotnet/java-interop#1055)
  * dotnet/java-interop@8e18c909: [generator] Avoid C#11 delegate cache overhead. (dotnet/java-interop#1053)
  * dotnet/java-interop@2d8b6d24: [generator] More AttributeTargets on SupportedOSPlatformAttribute (dotnet/java-interop#1054)
  * dotnet/java-interop@7dfbab67: [generator] Add [SupportedOSPlatform] to bound constant fields (dotnet/java-interop#1038)
  * dotnet/java-interop@1720628a: [generator] Mark generated .cs files as generated (dotnet/java-interop#1052)
  * dotnet/java-interop@f498fcf5: [Java.Interop] Avoid some method group conversions (dotnet/java-interop#1050)
  * dotnet/java-interop@16e1ecd4: [build] Use $(VSINSTALLDIR), not $(VSINSTALLROOT) (dotnet/java-interop#1048)
  * dotnet/java-interop@8e4c7d20: [Hello-Core] Add "low level" sample. (dotnet/java-interop#1047)

Additionally, remove `$(LangVersion)`=10 from `Mono.Android.csproj`,
which was a hack to work around a size regression due to delegate
caching in C# 11; see also 938b2cb, dotnet/java-interop@8e18c909.

Co-authored-by: Jonathan Pobst <[email protected]>
@github-actions github-actions bot locked and limited conversation to collaborators Apr 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants