@@ -43,7 +43,9 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
4343///
4444/// [UnmanagedCallersOnly]
4545/// public static void nctor_0_uco(IntPtr jnienv, IntPtr self)
46- /// => TrimmableNativeRegistration.ActivateInstance(self, typeof(Activity));
46+ /// => new Activity(self, JniHandleOwnership.DoNotTransfer);
47+ /// // or: var obj = (Activity)RuntimeHelpers.GetUninitializedObject(typeof(Activity));
48+ /// // obj.BaseCtor(self, JniHandleOwnership.DoNotTransfer);
4749///
4850/// // Registers JNI native methods (ACWs only):
4951/// public void RegisterNatives(JniType jniType)
@@ -87,7 +89,6 @@ sealed class TypeMapAssemblyEmitter
8789 MemberReferenceHandle _jniObjectReferenceCtorRef ;
8890 MemberReferenceHandle _jniEnvDeleteRefRef ;
8991 MemberReferenceHandle _withinNewObjectScopeRef ;
90- MemberReferenceHandle _activateInstanceRef ;
9192 MemberReferenceHandle _ucoAttrCtorRef ;
9293 BlobHandle _ucoAttrBlobHandle ;
9394 MemberReferenceHandle _typeMapAttrCtorRef2Arg ;
@@ -244,17 +245,6 @@ void EmitMemberReferences ()
244245 rt => rt . Type ( ) . Boolean ( ) ,
245246 p => { } ) ) ;
246247
247- // TrimmableTypeMap.ActivateInstance(IntPtr, Type)
248- var trimmableTypeMapRef = _pe . Metadata . AddTypeReference ( _pe . MonoAndroidRef ,
249- _pe . Metadata . GetOrAddString ( "Microsoft.Android.Runtime" ) , _pe . Metadata . GetOrAddString ( "TrimmableTypeMap" ) ) ;
250- _activateInstanceRef = _pe . AddMemberRef ( trimmableTypeMapRef , "ActivateInstance" ,
251- sig => sig . MethodSignature ( ) . Parameters ( 2 ,
252- rt => rt . Void ( ) ,
253- p => {
254- p . AddParameter ( ) . Type ( ) . IntPtr ( ) ;
255- p . AddParameter ( ) . Type ( ) . Type ( _systemTypeRef , false ) ;
256- } ) ) ;
257-
258248 // JniNativeMethod..ctor(byte*, byte*, IntPtr)
259249 _jniNativeMethodCtorRef = _pe . AddMemberRef ( _jniNativeMethodRef , ".ctor" ,
260250 sig => sig . MethodSignature ( isInstanceMethod : true ) . Parameters ( 3 ,
@@ -354,6 +344,16 @@ void EmitTypeMapAssociationAttributeCtorRef ()
354344
355345 void EmitProxyType ( JavaPeerProxyData proxy , Dictionary < string , MethodDefinitionHandle > wrapperHandles )
356346 {
347+ if ( proxy . IsAcw ) {
348+ // RegisterNatives uses RVA-backed UTF-8 fields under <PrivateImplementationDetails>.
349+ // Materialize those helper types before adding the proxy TypeDef, otherwise the
350+ // later RegisterNatives method can be attached to the helper type instead.
351+ foreach ( var reg in proxy . NativeRegistrations ) {
352+ _pe . GetOrAddUtf8Field ( reg . JniMethodName ) ;
353+ _pe . GetOrAddUtf8Field ( reg . JniSignature ) ;
354+ }
355+ }
356+
357357 var metadata = _pe . Metadata ;
358358 var typeDefHandle = metadata . AddTypeDefinition (
359359 TypeAttributes . Public | TypeAttributes . Sealed | TypeAttributes . Class ,
@@ -368,14 +368,15 @@ void EmitProxyType (JavaPeerProxyData proxy, Dictionary<string, MethodDefinition
368368 }
369369
370370 // .ctor
371- _pe . EmitBody ( ".ctor" ,
371+ var ctorHandle = _pe . EmitBody ( ".ctor" ,
372372 MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . SpecialName | MethodAttributes . RTSpecialName ,
373373 sig => sig . MethodSignature ( isInstanceMethod : true ) . Parameters ( 0 , rt => rt . Void ( ) , p => { } ) ,
374374 encoder => {
375375 encoder . OpCode ( ILOpCode . Ldarg_0 ) ;
376376 encoder . Call ( _baseCtorRef ) ;
377377 encoder . OpCode ( ILOpCode . Ret ) ;
378378 } ) ;
379+ metadata . AddCustomAttribute ( typeDefHandle , ctorHandle , _ucoAttrBlobHandle ) ;
379380
380381 // CreateInstance
381382 EmitCreateInstance ( proxy ) ;
@@ -704,10 +705,14 @@ MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco)
704705
705706 MethodDefinitionHandle EmitUcoConstructor ( UcoConstructorData uco , JavaPeerProxyData proxy )
706707 {
707- var userTypeRef = _pe . ResolveTypeRef ( uco . TargetType ) ;
708+ var targetTypeRef = _pe . ResolveTypeRef ( uco . TargetType ) ;
708709 var activationCtor = proxy . ActivationCtor ?? throw new InvalidOperationException (
709710 $ "UCO constructor wrapper requires an activation ctor for '{ uco . TargetType . ManagedTypeName } '") ;
710711
712+ // UCO constructor wrappers must match the JNI native method signature exactly.
713+ // Only jnienv (arg 0) and self (arg 1) are used — the constructor parameters
714+ // are not forwarded because we create the managed peer using the
715+ // activation ctor (IntPtr, JniHandleOwnership), not the user-visible constructor.
711716 var jniParams = JniSignatureHelper . ParseParameterTypes ( uco . JniSignature ) ;
712717 int paramCount = 2 + jniParams . Count ;
713718
@@ -733,79 +738,88 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
733738 }
734739
735740 MethodDefinitionHandle handle ;
741+ if ( activationCtor . Style == ActivationCtorStyle . JavaInterop ) {
742+ var ctorRef = AddJavaInteropActivationCtorRef (
743+ activationCtor . IsOnLeafType ? targetTypeRef : _pe . ResolveTypeRef ( activationCtor . DeclaringType ) ) ;
736744
737- // For non-leaf activation, keep the WithinNewObjectScope guard but route back
738- // through the generated proxy activation path instead of a runtime reflection helper.
739- if ( ! activationCtor . IsOnLeafType ) {
740745 handle = _pe . EmitBody ( uco . WrapperName ,
741746 MethodAttributes . Public | MethodAttributes . Static | MethodAttributes . HideBySig ,
742747 encodeSig ,
743748 encoder => {
749+ // Skip activation if the object is being created from managed code
750+ // (e.g., JNIEnv.StartCreateInstance / JNIEnv.NewObject).
744751 var skipLabel = encoder . DefineLabel ( ) ;
745752 encoder . Call ( _withinNewObjectScopeRef ) ;
746753 encoder . Branch ( ILOpCode . Brtrue , skipLabel ) ;
747754
748- encoder . LoadArgument ( 1 ) ; // jniSelf
749- encoder . OpCode ( ILOpCode . Ldtoken ) ;
750- encoder . Token ( userTypeRef ) ;
751- encoder . Call ( _getTypeFromHandleRef ) ;
752- encoder . Call ( _activateInstanceRef ) ;
753-
754- encoder . MarkLabel ( skipLabel ) ;
755- encoder . OpCode ( ILOpCode . Ret ) ;
756- } ,
757- encodeLocals : null ,
758- useBranches : true ) ;
759- } else if ( activationCtor . Style == ActivationCtorStyle . JavaInterop ) {
760- var ctorRef = AddJavaInteropActivationCtorRef ( userTypeRef ) ;
761-
762- handle = _pe . EmitBody ( uco . WrapperName ,
763- MethodAttributes . Public | MethodAttributes . Static | MethodAttributes . HideBySig ,
764- encodeSig ,
765- encoder => {
766- var skipLabel = encoder . DefineLabel ( ) ;
767- encoder . Call ( _withinNewObjectScopeRef ) ;
768- encoder . Branch ( ILOpCode . Brtrue , skipLabel ) ;
755+ if ( ! activationCtor . IsOnLeafType ) {
756+ encoder . OpCode ( ILOpCode . Ldtoken ) ;
757+ encoder . Token ( targetTypeRef ) ;
758+ encoder . Call ( _getTypeFromHandleRef ) ;
759+ encoder . Call ( _getUninitializedObjectRef ) ;
760+ encoder . OpCode ( ILOpCode . Castclass ) ;
761+ encoder . Token ( targetTypeRef ) ;
762+ }
769763
770764 encoder . LoadLocalAddress ( 0 ) ;
771765 encoder . LoadArgument ( 1 ) ; // self
772766 encoder . Call ( _jniObjectReferenceCtorRef ) ;
773767
774- encoder . LoadLocalAddress ( 0 ) ;
775- encoder . LoadConstantI4 ( 1 ) ; // JniObjectReferenceOptions.Copy
776- encoder . OpCode ( ILOpCode . Newobj ) ;
777- encoder . Token ( ctorRef ) ;
778- encoder . OpCode ( ILOpCode . Pop ) ;
768+ if ( activationCtor . IsOnLeafType ) {
769+ encoder . LoadLocalAddress ( 0 ) ;
770+ encoder . LoadConstantI4 ( 1 ) ; // JniObjectReferenceOptions.Copy
771+ encoder . OpCode ( ILOpCode . Newobj ) ;
772+ encoder . Token ( ctorRef ) ;
773+ encoder . OpCode ( ILOpCode . Pop ) ;
774+ } else {
775+ encoder . LoadLocalAddress ( 0 ) ;
776+ encoder . LoadConstantI4 ( 1 ) ; // JniObjectReferenceOptions.Copy
777+ encoder . Call ( ctorRef ) ;
778+ }
779779
780780 encoder . MarkLabel ( skipLabel ) ;
781781 encoder . OpCode ( ILOpCode . Ret ) ;
782782 } ,
783783 EncodeJniObjectReferenceLocal ,
784784 useBranches : true ) ;
785785 } else {
786- var ctorRef = AddActivationCtorRef ( userTypeRef ) ;
786+ var ctorRef = AddActivationCtorRef (
787+ activationCtor . IsOnLeafType ? targetTypeRef : _pe . ResolveTypeRef ( activationCtor . DeclaringType ) ) ;
787788
788789 handle = _pe . EmitBody ( uco . WrapperName ,
789790 MethodAttributes . Public | MethodAttributes . Static | MethodAttributes . HideBySig ,
790791 encodeSig ,
791792 encoder => {
793+ // Skip activation if the object is being created from managed code
792794 var skipLabel = encoder . DefineLabel ( ) ;
793795 encoder . Call ( _withinNewObjectScopeRef ) ;
794796 encoder . Branch ( ILOpCode . Brtrue , skipLabel ) ;
795797
796- encoder . LoadArgument ( 1 ) ; // self
797- encoder . LoadConstantI4 ( 0 ) ; // JniHandleOwnership.DoNotTransfer
798- encoder . OpCode ( ILOpCode . Newobj ) ;
799- encoder . Token ( ctorRef ) ;
800- encoder . OpCode ( ILOpCode . Pop ) ;
798+ if ( activationCtor . IsOnLeafType ) {
799+ encoder . LoadArgument ( 1 ) ; // self
800+ encoder . LoadConstantI4 ( 0 ) ; // JniHandleOwnership.DoNotTransfer
801+ encoder . OpCode ( ILOpCode . Newobj ) ;
802+ encoder . Token ( ctorRef ) ;
803+ encoder . OpCode ( ILOpCode . Pop ) ;
804+ } else {
805+ encoder . OpCode ( ILOpCode . Ldtoken ) ;
806+ encoder . Token ( targetTypeRef ) ;
807+ encoder . Call ( _getTypeFromHandleRef ) ;
808+ encoder . Call ( _getUninitializedObjectRef ) ;
809+ encoder . OpCode ( ILOpCode . Castclass ) ;
810+ encoder . Token ( targetTypeRef ) ;
811+
812+ encoder . LoadArgument ( 1 ) ; // self
813+ encoder . LoadConstantI4 ( 0 ) ; // JniHandleOwnership.DoNotTransfer
814+ encoder . Call ( ctorRef ) ;
815+ }
801816
802817 encoder . MarkLabel ( skipLabel ) ;
803818 encoder . OpCode ( ILOpCode . Ret ) ;
804819 } ,
805820 encodeLocals : null ,
806821 useBranches : true ) ;
807822 }
808-
809823 AddUnmanagedCallersOnlyAttribute ( handle ) ;
810824 return handle ;
811825 }
0 commit comments