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

Enable marshal methods support by default #7351

Merged
merged 141 commits into from Oct 10, 2022

Conversation

grendello
Copy link
Member

@grendello grendello commented Sep 7, 2022

Context: 5271f3e
Context: e1af958
Context: 186a9fc
Context: 903ba37
Context: a760281

Note: marshal methods are supported only in the .NET version of
Xamarin.Android, "classic" code does not support them.

This is the last commit in a long series (see the context links above)
which implements support for so called Marshal Methods - a mechanism
to register API callbacks with the Android Java runtime/VM that allow
us to implement Java method overrides in managed code. Java VM uses the
Java Native Interface (JNI) library and API to facilitate this for
native code developers (managed code is considered "native" in this
context) by allowing them to implement portions of Java classes in
language of their choice, so long as the language can call JNI
functions that "register" the the native implementations of Java class
member methods. Alternatively, the native implementations can be
placed in a shared library as a public symbol with name that follows
JNI requirements, so that the Java runtime can find the native
implementation of a method found in a certain Java class belonging to
a certain Java package.

Up until this commit, Mono/Xamarin/.NET Android has been using the
"dynamic" registration method, which incurred a non-trivial amount of
overhead, especially when starting the application on device and made
both registration and execution of managed code unnecessarily slower.

With this commit we add a way to use the other, "static", mechanism
which works by generating native functions, correctly named for JNI to
be able to find them, at the application build time. This approach
allows us to completely remove runtime registration overhead at
application startup, since it's replaced by native symbol lookup
performed by Java whenever a native class method is called. Such
lookup is usually very fast, since the native loader in the Android
system keeps symbol tables in memory once the shared library is
loaded. Marshal methods support is enabled by default for Release
builds and always disabled for Debug buillds. In order to
disable it for Release builds, one needs to set the
$(AndroidEnableMarshalMethods) MSBuild property to False.

Instead of using the older native assembly generator (which only
supported generating native data sections), marshal methods use the
LLVM IR language, subsequently compiled into native machine code by
the LLVM IR compiler (llc). This ascertains that the generated
native code as well as object files and shared libraries adhere to all
the requirements of the target platform ABI and enables certain
optimizations.

During application build we scan for all the managed types that mirror
their Java counterparts and implement abstract or override virtual
methods. Based on this selection we generate Java code that includes
declarations of native Java methods as described above, for whose we
generate the marshal methods chunks that are subsequently invoked at
the application runtime. While scanning, a marshal method classifier
is used to analyze whether the candidate method conforms to a set of
requirements that allow us to register the given native method using
the "static" approach. If yes, such method is removed from the set of
dynamically registered methods and, ideally, at the end of build we
have no methods that require the dynamic approach. However, if we
do encounter such methods, they are registered using the "old"
dynamic mechanism without conflicts between it and the generated
marshal methods code.

Managed methods selected for "static" registration need to be slightly
transformed in order to make them directly invokable from native code
as well as wrapped in such way that allows us to capture and handle
any unhandled exceptions, should they be thrown during the method
execution. This is done by a marshal methods assembly rewriter, which
makes the following changes:

  • Adds the [UnmanagedCallersOnly] attribute to each selected
    method.
  • Generates a wrapper which captures any exception and passes it to
    a special unhandled exception handler, whose task is to properly
    propagate the exceptions so that they don't break neither Java nor
    Managed call stacks.
  • If the selected method uses non-blittable types in its return
    value or parameters (currently we identify only bool), the above
    exception wrapper includes code that casts the non-blittable types
    to/from the blittable types without losing any information.

Marshal methods make application startup around 3.2% faster (the bigger the app the
more performance gains), with a bit room for future improvements (by eliminating
wrapper methods and other optimizations):

.NET Podcasts app test results:

Before After Δ Notes
868.500 840.400 -3.24% ✓ preload disabled; 32-bit build; no compression
863.700 837.600 -3.02% ✓ preload disabled; 64-bit build; no compression
872.500 850.100 -2.57% ✓ preload enabled; 64-bit build
877.000 854.800 -2.53% ✓ preload disabled; 64-bit build
859.300 839.800 -2.27% ✓ preload enabled; 64-bit build; no compression
871.700 853.100 -2.13% ✓ preload enabled; 32-bit build
860.600 842.300 -2.13% ✓ preload enabled; 32-bit build; no compression
869.500 852.500 -1.96% ✓ preload disabled; 32-bit build

Maui Hello World app test results:

Before After Δ Notes
374.800 365.500 -2.48% ✓ preload disabled; 64-bit build
374.100 365.600 -2.27% ✓ preload disabled; 32-bit build
369.100 364.400 -1.27% ✓ preload enabled; 32-bit build
364.300 360.600 -1.02% ✓ preload enabled; 32-bit build; no compression
368.900 365.400 -0.95% ✓ preload enabled; 64-bit build
362.500 359.400 -0.86% ✓ preload disabled; 32-bit build; no compression
361.100 361.600 +0.14% ✗ preload enabled; 64-bit build; no compression
359.200 368.000 +2.39% ✗ preload disabled; 64-bit build; no compression

The point of this commit is only to generate code and make sure it's
valid as far as compiling and linking are concerned. The code has not
been tested at run time as not all the infrastructure on the
Xamarin.Android side is implemented yet. This is on purpose, to keep PRs
smaller.

The majority of this PR introduces various classes, enums and structures
related to code generation. Support for various LLVM IR instructions is
limited only to those we actually use and only to elements of those
constructions that we use. As such, it's not a general purpose code
generator which allows us to make some assumptions and take some
shortcuts (without compromising correctness and validity of the
generated code)

Portions of the PR (the native type handling system) are to be treated
as proof-of-concept as they are not as optimized (design wise) as they
should be. The reason for this limitation is that it requires modifying
the previous LLVM IR data generation code and it would contribute to
this PR's already substantial size. The next PR in the series will take
care of that rewrite as well as it will focus on implementing the
runtime side of marshal methods, making it possible to actually run
applications which use marshal methods.

What this PR implements is the following:

  * LLVM IR
    * function and instruction attributes
    * function parameter (declaration/definition) and argument (runtime)
      handling
    * function variable (including parameters) handling, including
      unnamed local variables
    * support for native function signatures and pointers to functions
    * The ret, store, load, icmp, br, call and phi instructions
  * Marshal method generator
    * managed to JNI signature and symbol name translations
Implement missing runtime support so that applications are able to
actually run.  Also fix issues with marshal method overloads as well as
add code to handle the case where two unrelated methods (from different
types) end up using the same JNI symbol name:

  * `Java_crc64e1fb321c08285b90_CellAdapter_n_1onActionItemClicked
    * `System.Boolean Android.Views.ActionMode/ICallback::OnActionItemClicked(Android.Views.ActionMode,Android.Views.IMenuItem)`
    * `System.Boolean AndroidX.AppCompat.View.ActionMode/ICallback::OnActionItemClicked(AndroidX.AppCompat.View.ActionMode,Android.Views.IMenuItem)`
* main:
  LEGO: Merge pull request 7221
  LEGO: Merge pull request 7219
  [Xamarin.Android.Build.Tasks] use `ToJniName(type, cache)` (xamarin#7211)
  [docs] Synchronize with MicrosoftDocs/xamarin-docs (xamarin#7208)
  [Mono.Android] Remove System.Linq usage (xamarin#7210)
  Bump to Android NDK r25 (xamarin#6764)
  Bump to mono/opentk@daa9b2d5 (xamarin#7192)
  [Mono.Android] Optional NTLMv2 support in AndroidMessageHandler (xamarin#6999)
  Bump to dotnet/installer@53587f9 7.0.100-rc.1.22374.1 (xamarin#7198)
* mm-codegen:
  LEGO: Merge pull request 7221
  LEGO: Merge pull request 7219
  [Xamarin.Android.Build.Tasks] use `ToJniName(type, cache)` (xamarin#7211)
  [docs] Synchronize with MicrosoftDocs/xamarin-docs (xamarin#7208)
  [Mono.Android] Remove System.Linq usage (xamarin#7210)
  Bump to Android NDK r25 (xamarin#6764)
  Bump to mono/opentk@daa9b2d5 (xamarin#7192)
  [Mono.Android] Optional NTLMv2 support in AndroidMessageHandler (xamarin#6999)
  Bump to dotnet/installer@53587f9 7.0.100-rc.1.22374.1 (xamarin#7198)
* main:
  Bump to xamarin/java.interop@a5756ca8. (xamarin#7226)
  Bump `$(AndroidNet6Version)` to 32.0.447 (xamarin#7224)
* mm-codegen:
  Bump to xamarin/java.interop@a5756ca8. (xamarin#7226)
  Bump `$(AndroidNet6Version)` to 32.0.447 (xamarin#7224)
Also, deal with duplicate native symbol names
* main:
  [Mono.Android] fix crash on startup with EnableLLVM (xamarin#7188)
  [ci] Add Android Designer test template (xamarin#7227)
* mm-codegen:
  [Mono.Android] fix crash on startup with EnableLLVM (xamarin#7188)
  [ci] Add Android Designer test template (xamarin#7227)
* main:
  [Localization] Import translated resx files (xamarin#7190)
* mm-codegen:
  [Localization] Import translated resx files (xamarin#7190)
Hit a snag with one of the callbacks using non-blittable
arguments (`bool` in this case), but it seems to be the last (famous
last words) obstacle preventing the app from starting.

A handful of hacks are needed ATM, too.
* main:
  [build] update to latest JDKs (xamarin#7236)
* mm-codegen:
  [build] update to latest JDKs (xamarin#7236)
Unfortunately, 133 out of 182 methods are still registered dynamically,
the reason being that they either return `bool` or take it as one of
their parameters. `bool` isn't a blittable type and thus such methods
cannot be used with `[UnregisteredCallersOnly]`. To move farther, we
need to modify the generator to stop generating native callbacks (just
them) with `bool`.
* main:
  [ci] Upload test assemblies after signing (xamarin#7241)
* mm-codegen:
  [ci] Upload test assemblies after signing (xamarin#7241)
The app still crashes for some reason (appears something is not
decorated with the `[UnmanagedCallersOnly]` attribute) but the IL code
generation is complete and the app doesn't report any native/runtime
linking errors.

TBC next week
* main:
  Bump to xamarin/monodroid@210073e1 (xamarin#7272)
  [OneLoc] Localize Microsoft.Android.Templates (xamarin#7248)
  [README] Add links to XA 13.0 release installers (xamarin#7251)
  Bump to dotnet/installer@716bd17 7.0.100-rc.1.22409.23 (xamarin#7247)
  Bump manifest-merger from 30.2.1 to 30.2.2 (xamarin#7238)
@grendello grendello added the do-not-merge PR should not be merged. label Sep 29, 2022
* main:
  Localized file check-in by OneLocBuild Task: Build definition ID 11410: Build ID 6759133 (xamarin#7423)
  LEGO: Merge pull request 7422
  Bump to 32.0.476 .NET 6 Android packages (xamarin#7415)
@grendello grendello removed the do-not-merge PR should not be merged. label Sep 29, 2022
@grendello grendello mentioned this pull request Sep 29, 2022
@@ -33,6 +33,7 @@ by projects that use the Microsoft.Android framework in .NET 6+.
<ItemGroup>
<_AndroidRefPackAssemblies Include="$(JavaInteropSourceDirectory)\bin\$(Configuration)-net7.0\ref\Java.Interop.dll" />
<_AndroidRefPackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)ref\Mono.Android.dll" />
<_AndroidRefPackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)ref\Mono.Android.Runtime.dll" />
Copy link
Member

Choose a reason for hiding this comment

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

I fear that I'm gonna be "bikeshedding" half the naming here -- and I am! -- but…

Mono.Android.Runtime is not "future-facing". We may stick with Mono.Android.dll "forever", but there are equal odds that we may do a Microsoft.Android.dll name in the future (.NET 10?).

As such, we should choose names which are unlikely to need changing. Possible suggestions:

  • Microsoft.Android.Startup.dll
  • Microsoft.Android.Internals.dll
  • Microsoft.Android.Interop.dll

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd rather keep it Mono.Android.Runtime for now, since it pairs nicely with Mono.Android (and that was the reason I chose this name)

@@ -0,0 +1,18 @@
using System;

namespace Android.Runtime
Copy link
Member

Choose a reason for hiding this comment

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

…and more name bikeshedding: I think it was a historical mistake to use Android.Runtime; we're lucky that Google never introduced an android.runtime package.

I think Microsoft.Android.Internals would be a good namespace, or just Microsoft.Android, as all the types here are internal.

Copy link
Member Author

Choose a reason for hiding this comment

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

Likewise, I'd rather keep the Android.Runtime namespace, because this assembly includes sources from Mono.Android that are in this namespace. If we want to rename it, we should rename it all at once one day.

<method name="PropagateUncaughtException" />
</type>
<type fullname="Android.Runtime.JNIEnvInit">
Copy link
Member

Choose a reason for hiding this comment

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

I forget; does JNIEnvInit need to remain in Mono.Android.dll? Or can it be moved to the assembly containing AndroidRuntimeInternal?

Copy link
Member Author

Choose a reason for hiding this comment

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

It remains there for classic Xamarin, it is moved to the new assembly for .NET

internal static void UnhandledException (Exception e)
{
if (UnhandledExceptionHandler == null) {
return;
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this should abort; if we hit here, either we're very early in startup -- which means aborts would be bad ;-) -- or something is Very Wrong™.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wouldn't abort explicitly here. Hitting it during startup is very unlikely, and if it's not properly initialized, the app will crash anyway, implicitly aborting.


namespace Android.Runtime
{
static internal class JNIEnvInit
Copy link
Member

Choose a reason for hiding this comment

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

Can this be moved to the other new assembly? (I think I asked this before, but forgot the answer.)

Copy link
Member Author

Choose a reason for hiding this comment

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

It is included in the new assembly for .NET, for classic it remains in Mono.Android, thus the source is here and the new assembly includes it with a relative path.

try {
callback (jnienv, klazz);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);

Copy link
Member

Choose a reason for hiding this comment

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

How did you update this file? Manually? Or via Visual Studio (for Mac?) and re-evaluating JNINativeWrapper.g..tt ?

My suspicion -- based on these whitespace changes -- is that you updated manually.

Copy link
Member Author

Choose a reason for hiding this comment

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

I did update it manually.

@jonpryor
Copy link
Member

Also need an "epic" commit message tying all the pieces together and explaining what it does and how it works; see also:

The commit message should "revisit: e1af958, explain that the TODO item "Update generator so that two sets of marshal methods are emitted" is not required and is tracked as xamarin/java.interop#1027, and any other relevant "administrivia".

@grendello grendello changed the title Marshal methods cleanup and enabling Enable marshal methods support by default Oct 3, 2022
@grendello grendello added the do-not-merge PR should not be merged. label Oct 5, 2022
* main:
  [Mono.Android] Improve generated API docs diff (xamarin#7427)
  Localized file check-in by OneLocBuild Task: Build definition ID 11410: Build ID 6765281 (xamarin#7430)
  LEGO: Merge pull request 7429
  Bump to xamarin/java.interop@a0728ed5 (xamarin#7420)
It was a remnant from the attempt to move the `JNIEnvInit` class to
a separate assembly.
@grendello grendello removed the do-not-merge PR should not be merged. label Oct 5, 2022
@jonpryor
Copy link
Member

jonpryor commented Oct 10, 2022

Context: 5271f3e109a2242caa3bd7801dfad9c1683488d7
Context: e1af9587bb98d4c249bbc392ceccc2b53ffff155
Context: 186a9fcfac14ba15af1d8ad091dfa6612232fdcb
Context: 903ba37ce70d2840983774e1d6fb55f8002561e2
Context: a760281bb1c86baeedc54e3bb5333063bfcd48aa
Context: https://github.com/xamarin/xamarin-android/wiki/Blueprint#java-type-registration

Complete the LLVM Marshal Methods effort sketched out in e1af9587.

LLVM Marshal Methods are only supported in .NET Android, *not*
Xamarin.Android.

A *Marshal Method* is a JNI Callable C function (pointer) which has
[parameter types and return types which comply with the JNI ABI][0].
[`generator`][1] emits marshal methods as part of the binding, which
are turned into Delegate instances at runtime as part of
[Java Type Registration][2].

*LLVM Marshal Methods* turn this runtime operation -- looking up
`generator`-emitted marshal methods and registering those methods
with Java -- into a *build-time* operation, using LLVM-IR to generate
[JNI Native Method Names][3] which will then be contained within
`libxamarin-app.so`.  LLVM Marshal Methods will also *remove* the
previous Reflection-based infrastructure from relevant types.

LLVM Marshal Methods are *enabled by default* for ***Release***
configuration builds in .NET 8, and disabled by default for Debug
builds. The new `$(AndroidEnableMarshalMethods)` MSBuild property
explicitly controls whether or not LLVM Marshal Methods are used.

LLVM Marshal Methods are *not* available in Classic Xamarin.Android.


~~ Build Phase: Scanning for Compatible Types ~~

During the application build, all `Java.Lang.Object` and
`Java.Lang.Throwable` subclasses are scanned as part of
[Java Callable Wrapper generation][4], looking for "un-bound"
(user-written) types which override `abstract` or `virtual`
methods, or implement interface members.  This is done to emit
Java Callable Wrappers, Java code which "mirrors" the C# code with
an appropriate base class, interface implementation list, and
Java `native` method declarations for "virtual" member overrides.

This scanning process is updated for LLVM Marshal Methods to classify
each type to see if it requires the legacy Delegate-based
registration mechanism, as constructs such as
`[Java.Interop.ExportAttribute]` cannot (yet) be used with
LLVM Marshal Methods.


~~ Build Phase: Java Callable Wrapper Generation ~~

For example, given the C# type:

    // C#
    public partial class MainActivity : Activity {
        protected override void OnCreate (Bundle? state) => …
    }

Then the resulting Java Callable Wrapper *without* LLVM Marshal
Methods enabled will be:

    // Java + No LLVM Marshal Methods
    public /* partial */ class MainActivity extends Activity {
        static {
            String __md_methods =
                "n_onCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler\n";
            mono.android.Runtime.register ("Example.MainActivity, ExampleAssembly", MainActivity.class, __md_methods);
        }
        public void onCreate (android.os.Bundle p0) {n_onCreate(p0);}
        private native void n_onCreate (android.os.Bundle p0);
    }

When LLVM Marshal Methods are enabled, the Java Callable Wrapper
has no static constructor, nor any call to `Runtime.register()`.


~~ Build Phase: Marshal Method Wrapper ~~

Consider the binding infrastructure code that `generator` emits for
`Android.App.Activity.OnCreate()`:

	namespace Android.App {
	    public partial class Activity {
	        static Delegate? cb_onCreate_Landroid_os_Bundle_;
	#pragma warning disable 0169
	        static Delegate GetOnCreate_Landroid_os_Bundle_Handler ()
	        {
	            if (cb_onCreate_Landroid_os_Bundle_ == null)
	                cb_onCreate_Landroid_os_Bundle_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_OnCreate_Landroid_os_Bundle_);
	            return cb_onCreate_Landroid_os_Bundle_;
	        }

	        static void n_OnCreate_Landroid_os_Bundle_ (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)
	        {
	            var __this = global::Java.Lang.Object.GetObject<Android.App.Activity> (jnienv, native__this, JniHandleOwnership.DoNotTransfer)!;
	            var savedInstanceState = global::Java.Lang.Object.GetObject<Android.OS.Bundle> (native_savedInstanceState, JniHandleOwnership.DoNotTransfer);
	            __this.OnCreate (savedInstanceState);
	        }
	#pragma warning restore 0169

	        [Register ("onCreate", "(Landroid/os/Bundle;)V", "GetOnCreate_Landroid_os_Bundle_Handler")]
	        protected virtual unsafe void OnCreate (Android.OS.Bundle? savedInstanceState)
	        {
	            const string __id = "onCreate.(Landroid/os/Bundle;)V";
	            try {
	                JniArgumentValue* __args = stackalloc JniArgumentValue [1];
	                __args [0] = new JniArgumentValue ((savedInstanceState == null) ? IntPtr.Zero : ((global::Java.Lang.Object) savedInstanceState).Handle);
	                _members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args);
	            } finally {
	                global::System.GC.KeepAlive (savedInstanceState);
	            }
	        }
	    }
	}

When LLVM Marshal Methods are enabled, the following IL
transformations are performed:

  * The `static Delegate? cb_…` field is removed.
  * The `static Delegate Get…Handler()` method is removed.
  * A new `static … n_…_mm_wrapper()` method is added.

The `n_…_mm_wrapper()` method is responsible for exception marshaling
and for `bool` marshaling.  The `n_…_mm_wrapper()` method has the
[`UnmanagedCallersOnlyAttribute`][5], and works by calling the
existing `n_…()` method:

	namespace Android.App {
	    public partial class Activity {

	        // Added
	        [UnmanagedCallersOnly]
	        static void n_OnCreate_Landroid_os_Bundle__mm_wrapper (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)
	        {
	            try {
	                n_OnCreate_Landroid_os_Bundle_ (jnienv, native__this, native_savedInstanceState);
	            }
	            catch (Exception __e) {
	                Android.Runtime.AndroidEnvironmentInternal.UnhandledException (__e);
	            }
	        }
	    }
	}


~~ Build Phase: LLVM-IR Marshal Method Generation ~~

For each Java `native` method declaration contained in Java Callable
Wrappers which support LLVM Marshal Methods, LLVM-IR is used to
generate the JNI Native Method with the `Java_…` symbol name:

	using android_app_activity_on_create_bundle_fn = void (*) (JNIEnv *env, jclass klass, jobject savedInstanceState);
	static android_app_activity_on_create_bundle_fn android_app_activity_on_create_bundle = nullptr;

	extern "C" JNIEXPORT void
	JNICALL Java_helloandroid_MainActivity_n_1onCreate__Landroid_os_Bundle_2 (JNIEnv *env, jclass klass, jobject savedInstanceState) noexcept
	{
	  if (android_app_activity_on_create_bundle == nullptr) {
	    get_function_pointer (
	        16,                                                               // mono image index; computed at build time
	        0,                                                                // class index; computed at build time
	        0x0600055B,                                                       // method token; computed at build time
	        reinterpret_cast<void*&>(android_app_activity_on_create_bundle)   // target pointer
	    );
	  }

	  android_app_activity_on_create_bundle (env, klass, savedInstanceState);
	}


~~ Other Changes ~~

The new `Android.Runtime.JNIEnvInit` type was split out of the
`Android.Runtime.JNIEnv` type to further reduce startup overhead, as
there are fewer fields to initialize.

The `Mono.Android.Runtime.dll` assembly is added because the
Marshal Method Wrapper needs to be able to invoke what *was*
`AndroidEnvironment.UnhandledException()`, *while also* updating
`Mono.Android.dll`!  `Mono.Android.Runtime.dll` allows the marshal
method wrappers to reliably use
`Android.Runtime.AndroidEnvironmentInternal.UnhandledException()`,
which will *never* be changed by the marshal method wrapper
infrastructure.


~~ Results ~~

Marshal methods make application startup around 3.2% faster (the
bigger the app the  more performance gains), with a bit room for
future improvements (by eliminating wrapper methods and other
optimizations):

[.NET Podcasts][6] app test results:

| Before  | After   | Δ        | Notes                                          |
| ------- | ------- | -------- | ---------------------------------------------- |
| 868.500 | 840.400 | -3.24% ✓ | preload disabled; 32-bit build; no compression |
| 863.700 | 837.600 | -3.02% ✓ | preload disabled; 64-bit build; no compression |
| 872.500 | 850.100 | -2.57% ✓ | preload enabled; 64-bit build                  |
| 877.000 | 854.800 | -2.53% ✓ | preload disabled; 64-bit build                 |
| 859.300 | 839.800 | -2.27% ✓ | preload enabled; 64-bit build; no compression  |
| 871.700 | 853.100 | -2.13% ✓ | preload enabled; 32-bit build                  |
| 860.600 | 842.300 | -2.13% ✓ | preload enabled; 32-bit build; no compression  |
| 869.500 | 852.500 | -1.96% ✓ | preload disabled; 32-bit build                 |

Maui Hello World app test results:

| Before  | After   | Δ        | Notes                                          |
| ------- | ------- | -------- | ---------------------------------------------- |
| 374.800 | 365.500 | -2.48% ✓ | preload disabled; 64-bit build                 |
| 374.100 | 365.600 | -2.27% ✓ | preload disabled; 32-bit build                 |
| 369.100 | 364.400 | -1.27% ✓ | preload enabled; 32-bit build                  |
| 364.300 | 360.600 | -1.02% ✓ | preload enabled; 32-bit build; no compression  |
| 368.900 | 365.400 | -0.95% ✓ | preload enabled; 64-bit build                  |
| 362.500 | 359.400 | -0.86% ✓ | preload disabled; 32-bit build; no compression |
| 361.100 | 361.600 | +0.14% ✗ | preload enabled; 64-bit build; no compression  |
| 359.200 | 368.000 | +2.39% ✗ | preload disabled; 64-bit build; no compression |


[0]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#native_method_arguments
[1]: https://github.com/xamarin/xamarin-android/wiki/Blueprint#generator
[2]: https://github.com/xamarin/xamarin-android/wiki/Blueprint#java-type-registration
[3]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names
[4]: https://github.com/xamarin/xamarin-android/wiki/Blueprint#java-callable-wrapper-generator
[5]: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute?view=net-7.0
[6]: https://github.com/microsoft/dotnet-podcasts/tree/net7.0

@jonpryor jonpryor merged commit 8bc7a3e into xamarin:main Oct 10, 2022
grendello added a commit to grendello/xamarin-android that referenced this pull request Oct 10, 2022
* main:
  Enable marshal methods support by default (xamarin#7351)
  Bump to xamarin/java.interop@e1ee4b1c, xamarin/android-api-docs@bc5443dc (xamarin#7358)
  [xaprepare] Support Gentoo Linux for OS detection (xamarin#7442)
  [Xamarin.Android.Build.Tasks] Avoid XA5207 for design-time builds (xamarin#7434)
  [Mono.Android] Improve generated API docs diff (xamarin#7427)
  Localized file check-in by OneLocBuild Task: Build definition ID 11410: Build ID 6765281 (xamarin#7430)
  LEGO: Merge pull request 7429
  Bump to xamarin/java.interop@a0728ed5 (xamarin#7420)
grendello added a commit to grendello/xamarin-android that referenced this pull request Oct 10, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Jan 24, 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.

None yet

4 participants