Skip to content

Commit

Permalink
[Mono.Android] avoid System.Reflection.Emit usage for common calls (#…
Browse files Browse the repository at this point in the history
…6657)

Context: https://github.com/xamarin/xamarin-android/wiki/Blueprint#java-type-registration
Context: b7a368a
Context: #4877
Context: #4927 (comment)

In order for Java code to call C# code,
[`JNIEnv::RegisterNatives()][0] must be invoked, providing an array
of `JNINativeMethod` structures, each of which contains a function
pointer to invoke, kept in `JNINativeMethod::fnPtr`.

Fortunately, delegates marshal as function pointers, and there is a
bunch of `generator`-emitted infrastructure and coordination with
Java Callable Wrappers to eventually obtain a Delegate instance to
provide `JNIEnv::RegisterNatives()`.

There is one deficiency in the `generator`-emitted infrastructure:
it doesn't deal with C# exceptions.  However, exceptions "can't"
cross the JNI boundary (see b7a368a for an example of the breakage
that results when exceptions do cross the boundary!), except when we
*do* want exceptions to cross the JNI boundary ("improved" IDE first
chance exception experience; see #4877).

This "we want to catch exceptions, except when we don't" scenario has
existed since the very beginning.  As "the very beginning" predates
[C# 4 exception filters][1], there wasn't a way for `generator`
output to "selectively `catch` exceptions".

We squared this circle by using `System.Reflection.Emit`:

 1. During Java Callable Wrapper registration, we lookup the
    "marshal method getter" as provided to the `Runtime.register()`
    invocation, e.g.
    `Android.App.Activity.GetOnCreate_Landroid_os_Bundle_Handler()`.

 2. `GetOnCreate_Landroid_os_Bundle_Handler()` is `generator` output,
    and contains a `JNINativeWrapper.CreateDelegate()` invocation:

        cb_onCreate_Landroid_os_Bundle_ = JNINativeWrapper.CreateDelegate ((_JniMarshal_PPL_V) n_OnCreate_Landroid_os_Bundle_);

 3. `JNINativeWrapper.CreateDelegate()` uses `System.Reflection.Emit`
    to create a new delegate instance which *wraps* the marshal
    method `Activity.n_OnCreate_Landroid_os_Bundle()` in a
    `try`/*filtered* `catch` block and marshals the exception to Java;
    `JNINativeWrapper.CreateDelegate()` effectively returns:

        bool _run_catch_if_debugger_not_attached (Exception e)
        {
            if (Debugger.IsAttached || !JNIEnv.PropagateExceptions) {
                JNIEnv.mono_unhandled_exception (e);
                return false;
            }
            return true;
        }

        _JniMarshal_PPL_V result = (jnienv, native__this, native_savedInstanceState) => {
            JNIEnv.WaitForBridgeProcessing ();
            try {
                Activity.n_OnCreate_Landroid_os_Bundle_ (jnienv, native__this, native_savedInstanceState);
            } catch (Exception e) when (_run_catch_if_debugger_not_attached (e)) {
                AndroidEnvironment.UnhandledException (e);
                if (Debugger.IsAttached || !JNIEnv.PropagateExceptions)
                    throw;
            }
        };
        return result;

    Again, this was C# 2.0 at the time, so C# 4 exception filters
    couldn't be used, thus the need for `System.Reflection.Emit`, so
    that [`ILGenerator.BeginExceptionFilterBLock()`][2] could be used
    (the support for which is a Mono extension).

After this point, use of `System.Reflection.Emit` was part of the
implicit ABI between Xamarin.Android and binding assemblies.  While
`generator` *could* be updated to *itself* emit the `try`/`catch`
block with exception filters, that would only work for binding
assemblies released *after* that `generator` fix.
The `System.Reflection.Emit` wrapper *can't* be skipped without
breaking semantic compatibility, *or* without allowing C# exceptions
to always pass through a JNI boundary, which would be Bad™.

The use of `System.Refleciton.Emit` is a Known Problem™, and
something we'd *like* to remove.
(Hence the [`jnimarshalmethod-gen`][3] explorations…)

With that background out of the way…

Let us turn our attention to the `dotnet new maui` template.
The default MAUI template hits `JNINativeWrapper.CreateDelegate()`
58 times during process startup, and we were wondering if we could
selectively improve these particular invocations, without needing to
re-think the entire "marshal method" infrastructure.

*Partially specialize* `JNINativeWrapper.CreateDelegate()` for the
following delegate types:

  * `_JniMarshal_PP_V`
  * `_JniMarshal_PPI_V`
  * `_JniMarshal_PPL_L`
  * `_JniMarshal_PPL_V`
  * `_JniMarshal_PPL_Z`
  * `_JniMarshal_PPII_V`
  * `_JniMarshal_PPLI_V`
  * `_JniMarshal_PPLL_V`
  * `_JniMarshal_PPLL_Z`
  * `_JniMarshal_PPIIL_V`
  * `_JniMarshal_PPILL_V`
  * `_JniMarshal_PPLIL_Z`
  * `_JniMarshal_PPLLL_L`
  * `_JniMarshal_PPLLL_Z`
  * `_JniMarshal_PPIIII_V`
  * `_JniMarshal_PPLLLL_V`
  * `_JniMarshal_PPLIIII_V`
  * `_JniMarshal_PPZIIII_V`
  * `_JniMarshal_PPLIIIIIIII_V`

This is done via use of a T4 template, which generates
`JNINativeWrapper.CreateBuiltInDelegate()`, and
`JNINativeWrapper.CreateDelegate()` is updated to call
`CreateBuiltInDelegate()`:

	partial class JNINativeWrapper {
	    static Delegate? CreateBuiltInDelegate (Delegate dlg, Type delegateType)
	    {
	        switch (delegateType.Name) {
	        case "_JniMarshal_PP_V":    return …
	        case "_JniMarshal_PPI_V":   return …
	        …
	        }
	        return null;
	    }

	    public static Delegate CreateDelegate (Delegate dlg)
	    {
	        …
	        var builtin = CreateBuiltInDelegate (dlg, dlg.GetType ();
	        if (builtin != null)
	            return builtin;
	        …
	    }
	}

This avoids use of `System.Reflection.Emit` for the specified types.

Other changes:

  * Update `TypeManager.GetActivateHandler()` to use
    `_JniMarshal_PPLLLL_V` instead of
    `Action<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr>`, so the
    fast path can be used.

  * Added a log message for `adb shell septprop debug.mono.log assembly`:

        Falling back to System.Reflection.Emit for delegate type '{delegateType}': {dlg.Method}

  * I was also able to remove `mono_unhandled_exception_method` from
    `JNINativeWrapper` as we already has this value in `JNIEnv`.

~~ Results ~~

Testing `dotnet new maui` with version:

	msbuild Xamarin.Android.sln -t:InstallMaui -bl -p:MauiVersion=6.0.200-preview.13.2536

A `Release` build on a Pixel 5 device, total startup time:

| Startup   |  Average (ms) |  Std Err (ms) |  Std Dev (ms) |
| --------- | ------------: | ------------: | ------------: | 
| Before    |        1106.3 |         6.919 |        21.879 |
| After     |        1078.8 |         5.438 |        17.197 |

This might save ~35ms on average?

If I time the message for one call, [such as][4]:

	I monodroid-timing: Runtime.register: registering type `Microsoft.Maui.MauiApplication, Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null`
	I monodroid-timing: Runtime.register: end time; elapsed: 0s:17::794845

The result is:

| One Call  |  Average (ms) |  Std Err (ms) |  Std Dev (ms) |
| --------- | ------------: | ------------: | ------------: | 
| Before    |        23.925 |         0.050 |         0.159 |
| After     |        18.723 |         0.094 |         0.298 |

Saving ~5.8ms for this one call.

`.apk` size difference for `dotnet new android`:

	% apkdiff -f before.apk after.apk
	Size difference in bytes ([*1] apk1 only, [*2] apk2 only):
	+       3,390 assemblies/assemblies.blob
	+          54 assemblies/assemblies.x86_64.blob
	-           4 assemblies/assemblies.arm64_v8a.blob
	-          15 assemblies/assemblies.x86.blob
	-          65 assemblies/assemblies.armeabi_v7a.blob
	Summary:
	+       3,360 Other entries 0.03% (of 10,526,432)
	+           0 Dalvik executables 0.00% (of 7,816,392)
	+           0 Shared libraries 0.00% (of 18,414,404)
	+       4,096 Package size difference 0.02% (of 21,006,128)

We're looking at a ~4KB size increase for this partial specialization.

[0]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#RegisterNatives
[1]: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/exception-handling#catch-blocks
[2]: https://docs.microsoft.com/is-is/dotnet/api/system.reflection.emit.ilgenerator.beginexceptfilterblock?view=net-6.0
[3]: http://github.com/xamarin/Java.Interop/commit/c8f3e51a6cfd78bdce89e2429efae4495481f57b
[4]: https://github.com/dotnet/maui/blob/bfba62ed796d3416c4fcaa7cfbea86dc8d5e04c2/src/Compatibility/ControlGallery/src/Android/MainApplication.cs
  • Loading branch information
jonathanpeppers authored Jan 28, 2022
1 parent ce0d212 commit 32cff43
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 35 deletions.
18 changes: 11 additions & 7 deletions src/Mono.Android/Android.Runtime/JNIEnv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static partial class JNIEnv {
internal static bool PropagateExceptions;

internal static bool IsRunningOnDesktop;
internal static bool LogTypemapMissStackTrace;
internal static bool LogAssemblyCategory;

static AndroidRuntime? androidRuntime;
static BoundExceptionType BoundExceptionType;
Expand All @@ -67,7 +67,7 @@ public static partial class JNIEnv {
internal static AndroidValueManager? AndroidValueManager;

[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
extern static void monodroid_log (LogLevel level, LogCategories category, string message);
internal extern static void monodroid_log (LogLevel level, LogCategories category, string message);

[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
internal extern static IntPtr monodroid_timing_start (string? message);
Expand Down Expand Up @@ -149,7 +149,7 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
partial_timing_sequence = monodroid_timing_start (null);
}

LogTypemapMissStackTrace = (args->logCategories & (uint)LogCategories.Assembly) != 0;
LogAssemblyCategory = (args->logCategories & (uint)LogCategories.Assembly) != 0;

gref_gc_threshold = args->grefGcThreshold;

Expand Down Expand Up @@ -246,6 +246,7 @@ static void ManualJavaObjectDispose (Java.Lang.Object obj)
#else // NETCOREAPP
internal static Action<Exception> mono_unhandled_exception = null!;
#endif // NETCOREAPP
internal static MethodInfo? mono_unhandled_exception_method = null;

#if !NETCOREAPP
static Action<AppDomain, UnhandledExceptionEventArgs> AppDomain_DoUnhandledException = null!;
Expand All @@ -254,10 +255,13 @@ static void ManualJavaObjectDispose (Java.Lang.Object obj)
static void Initialize ()
{
if (mono_unhandled_exception == null) {
var mono_UnhandledException = typeof (System.Diagnostics.Debugger)
mono_unhandled_exception_method = typeof (System.Diagnostics.Debugger)
.GetMethod ("Mono_UnhandledException", BindingFlags.NonPublic | BindingFlags.Static);
if (mono_UnhandledException != null)
mono_unhandled_exception = (Action<Exception>) Delegate.CreateDelegate (typeof(Action<Exception>), mono_UnhandledException);
if (mono_unhandled_exception_method != null)
mono_unhandled_exception = (Action<Exception>) Delegate.CreateDelegate (typeof(Action<Exception>), mono_unhandled_exception_method);
}
if (mono_unhandled_exception_method == null && mono_unhandled_exception != null) {
mono_unhandled_exception_method = mono_unhandled_exception.Method;
}

#if !NETCOREAPP
Expand Down Expand Up @@ -737,7 +741,7 @@ internal static void LogTypemapTrace (StackTrace st)
}

if (ret == IntPtr.Zero) {
if (LogTypemapMissStackTrace) {
if (LogAssemblyCategory) {
monodroid_log (LogLevel.Warn, LogCategories.Default, $"typemap: failed to map managed type to Java type: {type.AssemblyQualifiedName} (Module ID: {type.Module.ModuleVersionId}; Type token: {type.MetadataToken})");
LogTypemapTrace (new StackTrace (true));
}
Expand Down
26 changes: 13 additions & 13 deletions src/Mono.Android/Android.Runtime/JNINativeWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,16 @@
using System.Threading;

namespace Android.Runtime {
public static class JNINativeWrapper {
public static partial class JNINativeWrapper {

static MethodInfo? mono_unhandled_exception_method;
static MethodInfo? exception_handler_method;
static MethodInfo? wait_for_bridge_processing_method;

static void get_runtime_types ()
{
if (exception_handler_method != null)
return;
#if MONOANDROID1_0
mono_unhandled_exception_method = typeof (System.Diagnostics.Debugger).GetMethod (
"Mono_UnhandledException", BindingFlags.NonPublic | BindingFlags.Static);
if (mono_unhandled_exception_method == null)
AndroidEnvironment.FailFast ("Cannot find System.Diagnostics.Debugger.Mono_UnhandledException");
#endif
#if NETCOREAPP
mono_unhandled_exception_method = JNIEnv.mono_unhandled_exception.Method;
#endif // NETCOREAPP

exception_handler_method = typeof (AndroidEnvironment).GetMethod (
"UnhandledException", BindingFlags.NonPublic | BindingFlags.Static);
if (exception_handler_method == null)
Expand All @@ -45,6 +36,15 @@ public static Delegate CreateDelegate (Delegate dlg)

get_runtime_types ();

var delegateType = dlg.GetType ();
var result = CreateBuiltInDelegate (dlg, delegateType);
if (result != null)
return result;

if (JNIEnv.LogAssemblyCategory) {
JNIEnv.monodroid_log (LogLevel.Debug, LogCategories.Assembly, $"Falling back to System.Reflection.Emit for delegate type '{delegateType}': {dlg.Method}");
}

var ret_type = dlg.Method.ReturnType;
var parameters = dlg.Method.GetParameters ();
var param_types = new Type [parameters.Length];
Expand Down Expand Up @@ -73,10 +73,10 @@ public static Delegate CreateDelegate (Delegate dlg)
ig.Emit (OpCodes.Leave, label);

bool filter = Debugger.IsAttached || !JNIEnv.PropagateExceptions;
if (filter && mono_unhandled_exception_method != null) {
if (filter && JNIEnv.mono_unhandled_exception_method != null) {
ig.BeginExceptFilterBlock ();

ig.Emit (OpCodes.Call, mono_unhandled_exception_method);
ig.Emit (OpCodes.Call, JNIEnv.mono_unhandled_exception_method);
ig.Emit (OpCodes.Ldc_I4_1);
ig.BeginCatchBlock (null!);
} else {
Expand Down
272 changes: 272 additions & 0 deletions src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
using System;
using System.Diagnostics;

namespace Android.Runtime
{
public static partial class JNINativeWrapper
{
static bool _unhandled_exception (Exception e)
{
if (Debugger.IsAttached || !JNIEnv.PropagateExceptions) {
JNIEnv.mono_unhandled_exception (e);
return false;
}
return true;
}

private static Delegate CreateBuiltInDelegate (Delegate dlg, Type delegateType)
{
switch (delegateType.Name) {
case nameof (_JniMarshal_PP_V): {
_JniMarshal_PP_V callback = (_JniMarshal_PP_V) Delegate.CreateDelegate (typeof (_JniMarshal_PP_V), dlg.Target, dlg.Method);
_JniMarshal_PP_V result = (jnienv, klazz) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPI_V): {
_JniMarshal_PPI_V callback = (_JniMarshal_PPI_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPI_V), dlg.Target, dlg.Method);
_JniMarshal_PPI_V result = (jnienv, klazz, p0) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPL_L): {
_JniMarshal_PPL_L callback = (_JniMarshal_PPL_L) Delegate.CreateDelegate (typeof (_JniMarshal_PPL_L), dlg.Target, dlg.Method);
_JniMarshal_PPL_L result = (jnienv, klazz, p0) => {
JNIEnv.WaitForBridgeProcessing ();
try {
return callback (jnienv, klazz, p0);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
return default;
}
};
return result;
}
case nameof (_JniMarshal_PPL_V): {
_JniMarshal_PPL_V callback = (_JniMarshal_PPL_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPL_V), dlg.Target, dlg.Method);
_JniMarshal_PPL_V result = (jnienv, klazz, p0) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPL_Z): {
_JniMarshal_PPL_Z callback = (_JniMarshal_PPL_Z) Delegate.CreateDelegate (typeof (_JniMarshal_PPL_Z), dlg.Target, dlg.Method);
_JniMarshal_PPL_Z result = (jnienv, klazz, p0) => {
JNIEnv.WaitForBridgeProcessing ();
try {
return callback (jnienv, klazz, p0);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
return default;
}
};
return result;
}
case nameof (_JniMarshal_PPII_V): {
_JniMarshal_PPII_V callback = (_JniMarshal_PPII_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPII_V), dlg.Target, dlg.Method);
_JniMarshal_PPII_V result = (jnienv, klazz, p0, p1) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLI_V): {
_JniMarshal_PPLI_V callback = (_JniMarshal_PPLI_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPLI_V), dlg.Target, dlg.Method);
_JniMarshal_PPLI_V result = (jnienv, klazz, p0, p1) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLL_V): {
_JniMarshal_PPLL_V callback = (_JniMarshal_PPLL_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPLL_V), dlg.Target, dlg.Method);
_JniMarshal_PPLL_V result = (jnienv, klazz, p0, p1) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLL_Z): {
_JniMarshal_PPLL_Z callback = (_JniMarshal_PPLL_Z) Delegate.CreateDelegate (typeof (_JniMarshal_PPLL_Z), dlg.Target, dlg.Method);
_JniMarshal_PPLL_Z result = (jnienv, klazz, p0, p1) => {
JNIEnv.WaitForBridgeProcessing ();
try {
return callback (jnienv, klazz, p0, p1);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
return default;
}
};
return result;
}
case nameof (_JniMarshal_PPIIL_V): {
_JniMarshal_PPIIL_V callback = (_JniMarshal_PPIIL_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPIIL_V), dlg.Target, dlg.Method);
_JniMarshal_PPIIL_V result = (jnienv, klazz, p0, p1, p2) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPILL_V): {
_JniMarshal_PPILL_V callback = (_JniMarshal_PPILL_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPILL_V), dlg.Target, dlg.Method);
_JniMarshal_PPILL_V result = (jnienv, klazz, p0, p1, p2) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLIL_Z): {
_JniMarshal_PPLIL_Z callback = (_JniMarshal_PPLIL_Z) Delegate.CreateDelegate (typeof (_JniMarshal_PPLIL_Z), dlg.Target, dlg.Method);
_JniMarshal_PPLIL_Z result = (jnienv, klazz, p0, p1, p2) => {
JNIEnv.WaitForBridgeProcessing ();
try {
return callback (jnienv, klazz, p0, p1, p2);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
return default;
}
};
return result;
}
case nameof (_JniMarshal_PPLLL_L): {
_JniMarshal_PPLLL_L callback = (_JniMarshal_PPLLL_L) Delegate.CreateDelegate (typeof (_JniMarshal_PPLLL_L), dlg.Target, dlg.Method);
_JniMarshal_PPLLL_L result = (jnienv, klazz, p0, p1, p2) => {
JNIEnv.WaitForBridgeProcessing ();
try {
return callback (jnienv, klazz, p0, p1, p2);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
return default;
}
};
return result;
}
case nameof (_JniMarshal_PPLLL_Z): {
_JniMarshal_PPLLL_Z callback = (_JniMarshal_PPLLL_Z) Delegate.CreateDelegate (typeof (_JniMarshal_PPLLL_Z), dlg.Target, dlg.Method);
_JniMarshal_PPLLL_Z result = (jnienv, klazz, p0, p1, p2) => {
JNIEnv.WaitForBridgeProcessing ();
try {
return callback (jnienv, klazz, p0, p1, p2);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
return default;
}
};
return result;
}
case nameof (_JniMarshal_PPIIII_V): {
_JniMarshal_PPIIII_V callback = (_JniMarshal_PPIIII_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPIIII_V), dlg.Target, dlg.Method);
_JniMarshal_PPIIII_V result = (jnienv, klazz, p0, p1, p2, p3) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2, p3);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLLLL_V): {
_JniMarshal_PPLLLL_V callback = (_JniMarshal_PPLLLL_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPLLLL_V), dlg.Target, dlg.Method);
_JniMarshal_PPLLLL_V result = (jnienv, klazz, p0, p1, p2, p3) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2, p3);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLIIII_V): {
_JniMarshal_PPLIIII_V callback = (_JniMarshal_PPLIIII_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPLIIII_V), dlg.Target, dlg.Method);
_JniMarshal_PPLIIII_V result = (jnienv, klazz, p0, p1, p2, p3, p4) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2, p3, p4);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPZIIII_V): {
_JniMarshal_PPZIIII_V callback = (_JniMarshal_PPZIIII_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPZIIII_V), dlg.Target, dlg.Method);
_JniMarshal_PPZIIII_V result = (jnienv, klazz, p0, p1, p2, p3, p4) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2, p3, p4);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
case nameof (_JniMarshal_PPLIIIIIIII_V): {
_JniMarshal_PPLIIIIIIII_V callback = (_JniMarshal_PPLIIIIIIII_V) Delegate.CreateDelegate (typeof (_JniMarshal_PPLIIIIIIII_V), dlg.Target, dlg.Method);
_JniMarshal_PPLIIIIIIII_V result = (jnienv, klazz, p0, p1, p2, p3, p4, p5, p6, p7, p8) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz, p0, p1, p2, p3, p4, p5, p6, p7, p8);
} catch (Exception e) when (_unhandled_exception (e)) {
AndroidEnvironment.UnhandledException (e);
}
};
return result;
}
default:
return null;
}
}
}
}
Loading

0 comments on commit 32cff43

Please sign in to comment.