diff --git a/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs b/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs
index ccf1ac857a4..7f9585bb197 100644
--- a/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs
+++ b/src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs
@@ -97,8 +97,10 @@ sealed class TypeMapAssemblyEmitter
MemberReferenceHandle _getUninitializedObjectRef;
MemberReferenceHandle _notSupportedExceptionCtorRef;
MemberReferenceHandle _jniObjectReferenceCtorRef;
+ MemberReferenceHandle _setPeerReferenceRef;
MemberReferenceHandle _jniEnvDeleteRefRef;
MemberReferenceHandle _shouldSkipActivationRef;
+ MemberReferenceHandle _markActivationPeerReplaceableRef;
MemberReferenceHandle _waitForBridgeProcessingRef;
MemberReferenceHandle _androidEnvironmentUnhandledExceptionRef;
MemberReferenceHandle _ucoAttrCtorRef;
@@ -308,6 +310,11 @@ void EmitMemberReferences ()
p.AddParameter ().Type ().Type (_jniObjectReferenceTypeRef, true);
}));
+ _setPeerReferenceRef = _pe.AddMemberRef (_iJavaPeerableRef, "SetPeerReference",
+ sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
+ rt => rt.Void (),
+ p => p.AddParameter ().Type ().Type (_jniObjectReferenceRef, true)));
+
// JNIEnv.DeleteRef(IntPtr, JniHandleOwnership) — static, internal
// Used by JI-style activation to clean up the original handle after constructing the peer.
// Matches the legacy TypeManager.CreateProxy behavior.
@@ -325,6 +332,11 @@ void EmitMemberReferences ()
rt => rt.Type ().Boolean (),
p => { p.AddParameter ().Type ().IntPtr (); }));
+ _markActivationPeerReplaceableRef = _pe.AddMemberRef (_javaPeerProxyNonGenericRef, "MarkActivationPeerReplaceable",
+ sig => sig.MethodSignature ().Parameters (1,
+ rt => rt.Void (),
+ p => p.AddParameter ().Type ().IntPtr ()));
+
_waitForBridgeProcessingRef = _pe.AddMemberRef (_androidRuntimeInternalRef, "WaitForBridgeProcessing",
sig => sig.MethodSignature ().Parameters (0, rt => rt.Void (), p => { }));
@@ -868,6 +880,14 @@ MemberReferenceHandle AddActivationCtorRef (EntityHandle declaringTypeRef)
}));
}
+ MemberReferenceHandle AddDefaultCtorRef (EntityHandle declaringTypeRef)
+ {
+ return _pe.AddMemberRef (declaringTypeRef, ".ctor",
+ sig => sig.MethodSignature (isInstanceMethod: true).Parameters (0,
+ rt => rt.Void (),
+ p => { }));
+ }
+
MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco, JavaPeerProxyData proxy)
{
var jniParams = JniSignatureHelper.ParseParameterTypes (uco.JniSignature);
@@ -988,6 +1008,41 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
return noopHandle;
}
+ if (jniParams.Count == 0) {
+ var defaultCtorRef = AddDefaultCtorRef (targetTypeRef);
+ var defaultCtorHandle = _pe.EmitBody (uco.WrapperName,
+ MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
+ encodeSig,
+ (encoder, cfb) => EmitUcoConstructorBodyWithMarshal (encoder, cfb, enc => {
+ enc.OpCode (ILOpCode.Ldtoken);
+ enc.Token (targetTypeRef);
+ enc.Call (_getTypeFromHandleRef);
+ enc.Call (_getUninitializedObjectRef);
+ enc.OpCode (ILOpCode.Castclass);
+ enc.Token (targetTypeRef);
+ enc.StoreLocal (4);
+
+ enc.LoadLocalAddress (3); // jniRef
+ enc.LoadArgument (1); // self
+ enc.LoadConstantI4 (0); // JniObjectReferenceType.Invalid
+ enc.Call (_jniObjectReferenceCtorRef);
+
+ enc.LoadLocal (4);
+ enc.LoadLocal (3);
+ enc.OpCode (ILOpCode.Callvirt);
+ enc.Token (_setPeerReferenceRef);
+
+ enc.LoadLocal (4);
+ enc.Call (defaultCtorRef);
+
+ enc.LoadArgument (1); // self
+ enc.Call (_markActivationPeerReplaceableRef);
+ }),
+ blob => EncodeUcoConstructorLocals_DefaultConstructor (blob, targetTypeRef));
+ AddUnmanagedCallersOnlyAttribute (defaultCtorHandle);
+ return defaultCtorHandle;
+ }
+
MethodDefinitionHandle handle;
if (activationCtor.Style == ActivationCtorStyle.JavaInterop) {
var ctorRef = AddJavaInteropActivationCtorRef (
@@ -1027,6 +1082,8 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
enc.LoadConstantI4 (1); // JniObjectReferenceOptions.Copy
enc.Call (ctorRef);
}
+ enc.LoadArgument (1); // self
+ enc.Call (_markActivationPeerReplaceableRef);
}),
EncodeUcoConstructorLocals_JavaInterop);
} else {
@@ -1059,6 +1116,8 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
enc.LoadConstantI4 (0); // JniHandleOwnership.DoNotTransfer
enc.Call (ctorRef);
}
+ enc.LoadArgument (1); // self
+ enc.Call (_markActivationPeerReplaceableRef);
}),
EncodeUcoConstructorLocals_Standard);
}
@@ -1180,6 +1239,31 @@ void EncodeUcoConstructorLocals_JavaInterop (BlobBuilder blob)
blob.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_jniObjectReferenceRef));
}
+ ///
+ /// LOCAL_SIG for UCO constructors that invoke a no-arg managed constructor.
+ /// Locals: 0=JniTransition, 1=JniRuntime, 2=Exception, 3=JniObjectReference, 4=target type.
+ ///
+ void EncodeUcoConstructorLocals_DefaultConstructor (BlobBuilder blob, EntityHandle targetTypeRef)
+ {
+ blob.WriteByte (0x07); // LOCAL_SIG
+ blob.WriteCompressedInteger (5);
+ // local 0: JniTransition (valuetype)
+ blob.WriteByte (0x11); // ELEMENT_TYPE_VALUETYPE
+ blob.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_jniTransitionRef));
+ // local 1: JniRuntime (class)
+ blob.WriteByte (0x12); // ELEMENT_TYPE_CLASS
+ blob.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_jniRuntimeRef));
+ // local 2: Exception (class)
+ blob.WriteByte (0x12); // ELEMENT_TYPE_CLASS
+ blob.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_exceptionRef));
+ // local 3: JniObjectReference (valuetype)
+ blob.WriteByte (0x11); // ELEMENT_TYPE_VALUETYPE
+ blob.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_jniObjectReferenceRef));
+ // local 4: target type (class)
+ blob.WriteByte (0x12); // ELEMENT_TYPE_CLASS
+ blob.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (targetTypeRef));
+ }
+
void EmitRegisterNatives (JavaPeerProxyData proxy,
Dictionary wrapperHandles)
{
diff --git a/src/Mono.Android/Java.Interop/JavaPeerProxy.cs b/src/Mono.Android/Java.Interop/JavaPeerProxy.cs
index 88f7fa32244..190f1c597f7 100644
--- a/src/Mono.Android/Java.Interop/JavaPeerProxy.cs
+++ b/src/Mono.Android/Java.Interop/JavaPeerProxy.cs
@@ -103,6 +103,17 @@ public static bool ShouldSkipActivation (IntPtr jniSelf)
return (state & JniManagedPeerStates.Activatable) != JniManagedPeerStates.Activatable
&& (state & JniManagedPeerStates.Replaceable) != JniManagedPeerStates.Replaceable;
}
+
+ public static void MarkActivationPeerReplaceable (IntPtr jniSelf)
+ {
+ var reference = new JniObjectReference (jniSelf, JniObjectReferenceType.Invalid);
+ var peer = JniEnvironment.Runtime.ValueManager.PeekPeer (reference);
+ if (peer == null) {
+ return;
+ }
+
+ peer.SetJniManagedPeerState (peer.JniManagedPeerState | JniManagedPeerStates.Replaceable);
+ }
}
///
diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs
index 148c7dc9383..ae49c425e93 100644
--- a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs
+++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs
@@ -302,14 +302,11 @@ public void ActivatedDirectObjectSubclassesShouldBeRegistered ()
}
}
- // TODO: https://github.com/dotnet/android/issues/11170 — throwable subclass not registered under trimmable typemap
[Test]
public void ActivatedDirectThrowableSubclassesShouldBeRegistered ()
{
if (Build.VERSION.SdkInt <= BuildVersionCodes.GingerbreadMr1)
Assert.Ignore ("Skipping test due to Bug #34141");
-
- Console.Error.WriteLine ($"# jonp: BEGIN ActivatedDirectThrowableSubclassesShouldBeRegistered!!!");
using (var ThrowableActivatedFromJava_class = Java.Lang.Class.FromType (typeof (ThrowableActivatedFromJava))) {
var ThrowableActivatedFromJava_init = JNIEnv.GetMethodID (ThrowableActivatedFromJava_class.Handle, "", "()V");
@@ -325,7 +322,6 @@ public void ActivatedDirectThrowableSubclassesShouldBeRegistered ()
Assert.IsTrue (v.Constructed);
v.Dispose ();
}
- Console.Error.WriteLine ($"# jonp: END ActivatedDirectThrowableSubclassesShouldBeRegistered!!!");
}
[Test]
diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs
index b4d921acd17..764fc416379 100644
--- a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs
+++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs
@@ -19,7 +19,6 @@ namespace Java.LangTests
[TestFixture]
public class ObjectTest
{
- // TODO: https://github.com/dotnet/android/issues/11170 — trimmable typemap doesn't resolve most-derived managed type
[Test]
public void GetObject_ReturnsMostDerivedType ()
{
diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs b/tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs
index d3783cdee0b..573940a6250 100644
--- a/tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs
+++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs
@@ -43,12 +43,6 @@ protected NUnitInstrumentation(IntPtr handle, JniHandleOwnership transfer)
// Open generic type handling differs from non-trimmable
"Java.InteropTests.JnienvTest.NewOpenGenericTypeThrows",
- // Throwable subclass registration
- "Java.InteropTests.JnienvTest.ActivatedDirectThrowableSubclassesShouldBeRegistered",
-
- // Instance identity after JNI round-trip
- "Java.LangTests.ObjectTest.JnienvCreateInstance_RegistersMultipleInstances",
-
// Global ref leak when inflating custom views
"Xamarin.Android.RuntimeTests.CustomWidgetTests.InflateCustomView_ShouldNotLeakGlobalRefs",
};