diff --git a/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs b/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs
index 70521a1473f..149d13cfa0b 100644
--- a/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs
+++ b/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs
@@ -27,7 +27,7 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
/// // Creates the managed peer when Java calls into .NET
/// public override IJavaPeerable CreateInstance(IntPtr handle, JniHandleOwnership ownership)
/// => new Activity(handle, ownership); // leaf ctor
-/// // or: (Activity)RuntimeHelpers.GetUninitializedObject(typeof(Activity));
+/// // or: (Activity)CreateActivatedPeer(typeof(Activity), handle);
/// // obj.BaseCtor(handle, ownership); // inherited ctor
/// // or: new IOnClickListenerInvoker(handle, ownership); // interface invoker
/// // or: null; // no activation
@@ -43,7 +43,7 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
/// [UnmanagedCallersOnly]
/// public static void nctor_0_uco(IntPtr jnienv, IntPtr self)
/// => new Activity(self, JniHandleOwnership.DoNotTransfer);
-/// // or: var obj = (Activity)RuntimeHelpers.GetUninitializedObject(typeof(Activity));
+/// // or: var obj = (Activity)CreateActivatedPeer(typeof(Activity), self);
/// // obj.BaseCtor(self, JniHandleOwnership.DoNotTransfer);
///
/// // Registers JNI native methods (ACWs only):
@@ -68,6 +68,7 @@ sealed class TypeMapAssemblyEmitter
AssemblyReferenceHandle _javaInteropRef;
+ TypeReferenceHandle _javaPeerProxyBaseRef;
TypeReferenceHandle _javaPeerProxyRef;
TypeReferenceHandle _iJavaPeerableRef;
TypeReferenceHandle _jniHandleOwnershipRef;
@@ -79,10 +80,9 @@ sealed class TypeMapAssemblyEmitter
TypeReferenceHandle _runtimeTypeHandleRef;
TypeReferenceHandle _jniTypeRef;
TypeReferenceHandle _notSupportedExceptionRef;
- TypeReferenceHandle _runtimeHelpersRef;
MemberReferenceHandle _getTypeFromHandleRef;
- MemberReferenceHandle _getUninitializedObjectRef;
+ MemberReferenceHandle _createActivatedPeerRef;
MemberReferenceHandle _notSupportedExceptionCtorRef;
MemberReferenceHandle _jniObjectReferenceCtorRef;
MemberReferenceHandle _jniEnvDeleteRefRef;
@@ -163,6 +163,8 @@ void EmitCore (TypeMapAssemblyData model)
void EmitTypeReferences ()
{
var metadata = _pe.Metadata;
+ _javaPeerProxyBaseRef = metadata.AddTypeReference (_pe.MonoAndroidRef,
+ metadata.GetOrAddString ("Java.Interop"), metadata.GetOrAddString ("JavaPeerProxy"));
_javaPeerProxyRef = metadata.AddTypeReference (_pe.MonoAndroidRef,
metadata.GetOrAddString ("Java.Interop"), metadata.GetOrAddString ("JavaPeerProxy`1"));
_iJavaPeerableRef = metadata.AddTypeReference (_javaInteropRef,
@@ -185,8 +187,6 @@ void EmitTypeReferences ()
metadata.GetOrAddString ("Java.Interop"), metadata.GetOrAddString ("JniType"));
_notSupportedExceptionRef = metadata.AddTypeReference (_pe.SystemRuntimeRef,
metadata.GetOrAddString ("System"), metadata.GetOrAddString ("NotSupportedException"));
- _runtimeHelpersRef = metadata.AddTypeReference (_pe.SystemRuntimeRef,
- metadata.GetOrAddString ("System.Runtime.CompilerServices"), metadata.GetOrAddString ("RuntimeHelpers"));
_jniNativeMethodRef = metadata.AddTypeReference (_javaInteropRef,
metadata.GetOrAddString ("Java.Interop"), metadata.GetOrAddString ("JniNativeMethod"));
@@ -208,10 +208,13 @@ void EmitMemberReferences ()
rt => rt.Type ().Type (_systemTypeRef, false),
p => p.AddParameter ().Type ().Type (_runtimeTypeHandleRef, true)));
- _getUninitializedObjectRef = _pe.AddMemberRef (_runtimeHelpersRef, "GetUninitializedObject",
- sig => sig.MethodSignature ().Parameters (1,
- rt => rt.Type ().Object (),
- p => p.AddParameter ().Type ().Type (_systemTypeRef, false)));
+ _createActivatedPeerRef = _pe.AddMemberRef (_javaPeerProxyBaseRef, "CreateActivatedPeer",
+ sig => sig.MethodSignature ().Parameters (2,
+ rt => rt.Type ().Type (_iJavaPeerableRef, false),
+ p => {
+ p.AddParameter ().Type ().Type (_systemTypeRef, false);
+ p.AddParameter ().Type ().IntPtr ();
+ }));
_notSupportedExceptionCtorRef = _pe.AddMemberRef (_notSupportedExceptionRef, ".ctor",
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
@@ -493,7 +496,8 @@ void EmitCreateInstanceInheritedCtor (EntityHandle targetTypeRef, ActivationCtor
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (targetTypeRef);
encoder.Call (_getTypeFromHandleRef);
- encoder.Call (_getUninitializedObjectRef);
+ encoder.OpCode (ILOpCode.Ldarg_1);
+ encoder.Call (_createActivatedPeerRef);
encoder.OpCode (ILOpCode.Castclass);
encoder.Token (targetTypeRef);
@@ -543,7 +547,7 @@ void EmitCreateInstanceViaJavaInteropNewobj (EntityHandle typeRef)
///
/// Emits CreateInstance for JavaInterop-style activation (inherited ctor):
- /// var obj = (TargetType)RuntimeHelpers.GetUninitializedObject(typeof(TargetType));
+ /// var obj = (TargetType)CreateActivatedPeer(typeof(TargetType), handle);
/// var jniRef = new JniObjectReference(handle);
/// obj.BaseCtor(ref jniRef, JniObjectReferenceOptions.Copy);
/// JNIEnv.DeleteRef(handle, ownership);
@@ -555,11 +559,12 @@ void EmitCreateInstanceInheritedJavaInteropCtor (EntityHandle targetTypeRef, Act
EmitCreateInstanceBodyWithLocals (
EncodeJniObjectReferenceLocal,
encoder => {
- // var obj = (TargetType)RuntimeHelpers.GetUninitializedObject(typeof(TargetType));
+ // var obj = (TargetType)CreateActivatedPeer(typeof(TargetType), handle);
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (targetTypeRef);
encoder.Call (_getTypeFromHandleRef);
- encoder.Call (_getUninitializedObjectRef);
+ encoder.OpCode (ILOpCode.Ldarg_1); // handle
+ encoder.Call (_createActivatedPeerRef);
encoder.OpCode (ILOpCode.Castclass);
encoder.Token (targetTypeRef);
@@ -743,7 +748,8 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (targetTypeRef);
encoder.Call (_getTypeFromHandleRef);
- encoder.Call (_getUninitializedObjectRef);
+ encoder.LoadArgument (1); // self
+ encoder.Call (_createActivatedPeerRef);
encoder.OpCode (ILOpCode.Castclass);
encoder.Token (targetTypeRef);
}
@@ -792,7 +798,8 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (targetTypeRef);
encoder.Call (_getTypeFromHandleRef);
- encoder.Call (_getUninitializedObjectRef);
+ encoder.LoadArgument (1); // self
+ encoder.Call (_createActivatedPeerRef);
encoder.OpCode (ILOpCode.Castclass);
encoder.Token (targetTypeRef);
diff --git a/src/Mono.Android/Java.Interop/JavaPeerProxy.cs b/src/Mono.Android/Java.Interop/JavaPeerProxy.cs
index c4309d78f85..a2dc89ec4ef 100644
--- a/src/Mono.Android/Java.Interop/JavaPeerProxy.cs
+++ b/src/Mono.Android/Java.Interop/JavaPeerProxy.cs
@@ -18,10 +18,12 @@ namespace Java.Interop
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
public abstract class JavaPeerProxy : Attribute
{
+ const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
+
protected JavaPeerProxy (
string jniName,
Type targetType,
- [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
+ [DynamicallyAccessedMembers (Constructors)]
Type? invokerType)
{
JniName = jniName ?? throw new ArgumentNullException (nameof (jniName));
@@ -52,7 +54,7 @@ protected JavaPeerProxy (
/// Gets the invoker type for interfaces and abstract classes.
/// Returns null for concrete types that can be directly instantiated.
///
- [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
+ [DynamicallyAccessedMembers (Constructors)]
public Type? InvokerType { get; }
///
@@ -61,6 +63,22 @@ protected JavaPeerProxy (
///
/// A factory for creating containers of the target type, or null if not supported.
public virtual JavaPeerContainerFactory? GetContainerFactory () => null;
+ ///
+ /// Creates the managed peer for inherited Java activation paths and binds it
+ /// to the provided JNI handle before the activation constructor runs.
+ ///
+ protected static IJavaPeerable CreateActivatedPeer (
+ [DynamicallyAccessedMembers (Constructors)] Type type,
+ IntPtr handle)
+ {
+ var peer = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (type);
+
+ peer.SetJniManagedPeerState (peer.JniManagedPeerState | JniManagedPeerStates.Replaceable | JniManagedPeerStates.Activatable);
+
+ var reference = new JniObjectReference (handle);
+ JniEnvironment.Runtime.ValueManager.ConstructPeer (peer, ref reference, JniObjectReferenceOptions.Copy);
+ return peer;
+ }
}
///
diff --git a/tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs b/tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs
index a99d95bfca0..0d59f3c642c 100644
--- a/tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs
+++ b/tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs
@@ -176,7 +176,7 @@ public void Generate_EmptyPeerList_ProducesValidAssembly ()
}
[Fact]
- public void Generate_SimpleActivity_UsesGetUninitializedObject ()
+ public void Generate_SimpleActivity_UsesSharedActivationHelper ()
{
var peers = ScanFixtures ();
var simpleActivity = peers.First (p => p.JavaName == "my/app/SimpleActivity");
@@ -186,12 +186,11 @@ public void Generate_SimpleActivity_UsesGetUninitializedObject ()
using var stream = GenerateAssembly (new [] { simpleActivity }, "InheritedCtorTest");
using var pe = new PEReader (stream);
var reader = pe.GetMetadataReader ();
- var typeNames = GetTypeRefNames (reader);
- Assert.Contains ("RuntimeHelpers", typeNames);
var memberNames = GetMemberRefNames (reader);
Assert.DoesNotContain ("CreateManagedPeer", memberNames);
- Assert.Contains ("GetUninitializedObject", memberNames);
+ Assert.Contains ("CreateActivatedPeer", memberNames);
+ Assert.DoesNotContain ("GetUninitializedObject", memberNames);
}
[Fact]
@@ -230,7 +229,8 @@ public void Generate_InheritedCtor_UcoUsesGuardAndInlinedActivation ()
var memberNames = GetMemberRefNames (reader);
Assert.Contains ("get_WithinNewObjectScope", memberNames);
- Assert.Contains ("GetUninitializedObject", memberNames);
+ Assert.Contains ("CreateActivatedPeer", memberNames);
+ Assert.DoesNotContain ("GetUninitializedObject", memberNames);
Assert.DoesNotContain ("ActivateInstance", memberNames);
Assert.DoesNotContain ("ActivatePeerFromJavaConstructor", memberNames);
}