-
Notifications
You must be signed in to change notification settings - Fork 545
[XABT] Move marshal method generation to a "linker step". #10027
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
base: main
Are you sure you want to change the base?
Conversation
5a287b2
to
d8bcd19
Compare
There seems to be an issue with this as we move from an "all at once" model to an incremental "per-assembly" model. Previously we would scan all assemblies with the marshal method classifier to determine which methods needed to be changed. Then we would perform the needed modifications on all the assemblies. In the new process, we would like to be able to convert single assemblies independently. For example, in an incremental build where only a user's custom binding project changed, we do not want to rerun the marshal method generation process on every assembly in the project. However, this leads to a problem, as scanning an assembly requires being able to find the relevant "connector" method which may be in a dependent assembly. If this dependent assembly has already gone through the marshal method process then the connector method has already been removed then the marshal method process fails to convert the new method. A concrete example:
// Xamarin.AndroidX.Core - 1.12.0.2
[Register("androidx/core/app/ComponentActivity", DoNotGenerateAcw = true)]
public class AndroidX.Core.App.ComponentActivity.ComponentActivity : Activity, KeyEventDispatcher.IComponent, IJavaObject, IDisposable, IJavaPeerable, ILifecycleOwner
{
public unsafe virtual Lifecycle Lifecycle
{
[Register("getLifecycle", "()Landroidx/lifecycle/Lifecycle;", "GetGetLifecycleHandler")]
get {
JniObjectReference val = _members.get_InstanceMethods().InvokeVirtualObjectMethod("getLifecycle.()Landroidx/lifecycle/Lifecycle;", (IJavaPeerable)(object)this, (JniArgumentValue*)null);
return Object.GetObject<Lifecycle>(((JniObjectReference)(ref val)).get_Handle(), (JniHandleOwnership)1);
}
}
private static IntPtr n_GetLifecycle(IntPtr jnienv, IntPtr native__this)
{
return JNIEnv.ToLocalJniHandle((IJavaObject)(object)Object.GetObject<ComponentActivity>(jnienv, native__this, (JniHandleOwnership)0).Lifecycle);
}
private static Delegate GetGetLifecycleHandler()
{
if ((object)cb_getLifecycle == null) {
cb_getLifecycle = JNINativeWrapper.CreateDelegate((Delegate)new _JniMarshal_PP_L(n_GetLifecycle));
}
return cb_getLifecycle;
}
}
// Xamarin.AndroidX.Lifecycle.Common - 2.6.2.2
[Register("androidx/lifecycle/LifecycleOwner", "", "AndroidX.Lifecycle.ILifecycleOwnerInvoker")]
public interface AndroidX.Lifecycle.ILifecycleOwner : IJavaObject, IDisposable, IJavaPeerable
{
Lifecycle Lifecycle
{
[Register("getLifecycle", "()Landroidx/lifecycle/Lifecycle;", "GetGetLifecycleHandler:AndroidX.Lifecycle.ILifecycleOwnerInvoker, Xamarin.AndroidX.Lifecycle.Common")]
get;
}
}
[Register("androidx/lifecycle/LifecycleOwner", DoNotGenerateAcw = true)]
internal class AndroidX.Lifecycle.ILifecycleOwnerInvoker : Object, ILifecycleOwner, IJavaObject, IDisposable, IJavaPeerable
{
public Lifecycle Lifecycle
{
get
{
if (id_getLifecycle == IntPtr.Zero)
{
id_getLifecycle = JNIEnv.GetMethodID(class_ref, "getLifecycle", "()Landroidx/lifecycle/Lifecycle;");
}
return Object.GetObject<Lifecycle>(JNIEnv.CallObjectMethod(((Object)this).get_Handle(), id_getLifecycle), (JniHandleOwnership)1);
}
}
private static IntPtr n_GetLifecycle(IntPtr jnienv, IntPtr native__this)
{
return JNIEnv.ToLocalJniHandle((IJavaObject)(object)Object.GetObject<ILifecycleOwner>(jnienv, native__this, (JniHandleOwnership)0).Lifecycle);
}
private static Delegate GetGetLifecycleHandler()
{
if ((object)cb_getLifecycle == null)
{
cb_getLifecycle = JNINativeWrapper.CreateDelegate((Delegate)new _JniMarshal_PP_L(n_GetLifecycle));
}
return cb_getLifecycle;
}
} Now imagine that the marshal method rewriter runs on the It removes // Xamarin.AndroidX.Lifecycle.Common - 2.6.2.2
[Register("androidx/lifecycle/LifecycleOwner", DoNotGenerateAcw = true)]
internal class AndroidX.Lifecycle.ILifecycleOwnerInvoker : Object, ILifecycleOwner, IJavaObject, IDisposable, IJavaPeerable
{
[UnmanagedCallersOnly]
private static IntPtr n_GetLifecycle_mm_wrapper(IntPtr jnienv, IntPtr native__this)
{
AndroidRuntimeInternal.WaitForBridgeProcessing();
try
{
return n_GetLifecycle(jnienv, native__this);
}
catch (System.Exception e)
{
Android.Runtime.AndroidEnvironmentInternal.UnhandledException(e);
return (IntPtr)0;
}
}
} Then we run the marshal method rewriter on
|
d8bcd19
to
d26e3a2
Compare
An easier example would be "app assembly" and We will need to retain the |
0b322b3
to
33cc446
Compare
fe7e281
to
0fd7718
Compare
0fd7718
to
b37490c
Compare
This commit moves the process of rewriting marshal methods found in Java binding libraries to a new
RewriteMarshalMethodsStep
"linker step".The marshal method generation step involves scanning through all assemblies that may contain Java bindings with Cecil, making changes, and writing the assemblies back out to disk. By combining this with our "linker steps" pipeline, we only need to open, modify, and write the assemblies to disk once instead of twice.
This involves:
AssemblyModifierPipeline
asRewriteMarshalMethodsStep
. This step must go before the typemapFindTypeMapObjectsStep
because it changes the assembly MVID and type token values.Release
typemap object scanning to theAssemblyModifierPipeline
because it has the updated MVID/token values.GenerateJavaStubs
now needs to add marshal methods data toNativeCodeGenState
because theRewriteMarshalMethods
task is no longer run. This is for tasks later in the pipeline that need this data, likeGenerateNativeMarshalMethodSources
.