Skip to content

Commit dd04b25

Browse files
Scope export method dispatch emission
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4106f7e commit dd04b25

2 files changed

Lines changed: 142 additions & 152 deletions

File tree

src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/ExportMethodDispatchEmitter.cs

Lines changed: 5 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,12 @@ public ExportMethodDispatchEmitter (PEAssemblyBuilder pe, ExportMethodDispatchEm
1919

2020
public MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco)
2121
{
22+
var exportMethodDispatch = GetRequiredExportMethodDispatch (uco);
2223
var jniParams = JniSignatureHelper.ParseParameterTypes (uco.JniSignature);
2324
var returnKind = JniSignatureHelper.ParseReturnType (uco.JniSignature);
2425
int paramCount = 2 + jniParams.Count;
2526
bool isVoid = returnKind == JniParamKind.Void;
26-
var exportMethodDispatchLocals = uco.UsesExportMethodDispatch
27-
? CreateExportMethodDispatchLocals (GetRequiredExportMethodDispatch (uco), isVoid)
28-
: ExportMethodDispatchLocals.Empty;
27+
var exportMethodDispatchLocals = CreateExportMethodDispatchLocals (exportMethodDispatch, isVoid);
2928

3029
Action<BlobEncoder> encodeSig = sig => sig.MethodSignature ().Parameters (paramCount,
3130
rt => { if (isVoid) rt.Void (); else JniSignatureHelper.EncodeClrType (rt.Type (), returnKind); },
@@ -37,23 +36,13 @@ public MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco)
3736
}
3837
});
3938
var callbackTypeHandle = _pe.ResolveTypeRef (uco.CallbackType);
40-
var callbackRef = uco.UsesExportMethodDispatch
41-
? AddExportMethodDispatchRef (uco, callbackTypeHandle)
42-
: _pe.AddMemberRef (callbackTypeHandle, uco.CallbackMethodName, encodeSig);
39+
var callbackRef = AddExportMethodDispatchRef (uco, callbackTypeHandle);
4340

4441
var handle = _pe.EmitBody (uco.WrapperName,
4542
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
4643
encodeSig,
4744
encoder => {
48-
if (!uco.UsesExportMethodDispatch) {
49-
for (int p = 0; p < paramCount; p++) {
50-
encoder.LoadArgument (p);
51-
}
52-
53-
encoder.Call (callbackRef);
54-
} else {
55-
EmitExportMethodDispatch (encoder, uco, callbackTypeHandle, callbackRef, jniParams, returnKind, exportMethodDispatchLocals);
56-
}
45+
EmitExportMethodDispatch (encoder, uco, callbackTypeHandle, callbackRef, jniParams, returnKind, exportMethodDispatchLocals);
5746
encoder.OpCode (ILOpCode.Ret);
5847
},
5948
exportMethodDispatchLocals.EncodeLocals,
@@ -63,131 +52,6 @@ public MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco)
6352
return handle;
6453
}
6554

66-
public MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco)
67-
{
68-
var userTypeRef = _pe.ResolveTypeRef (uco.TargetType);
69-
70-
// UCO constructor wrappers must match the JNI native method signature exactly.
71-
var jniParams = JniSignatureHelper.ParseParameterTypes (uco.JniSignature);
72-
int paramCount = 2 + jniParams.Count;
73-
74-
var handle = _pe.EmitBody (uco.WrapperName,
75-
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
76-
sig => sig.MethodSignature ().Parameters (paramCount,
77-
rt => rt.Void (),
78-
p => {
79-
p.AddParameter ().Type ().IntPtr ();
80-
p.AddParameter ().Type ().IntPtr ();
81-
for (int j = 0; j < jniParams.Count; j++) {
82-
JniSignatureHelper.EncodeClrType (p.AddParameter ().Type (), jniParams [j]);
83-
}
84-
}),
85-
encoder => {
86-
encoder.LoadArgument (1);
87-
encoder.OpCode (ILOpCode.Ldtoken);
88-
encoder.Token (userTypeRef);
89-
encoder.Call (_context.GetTypeFromHandleRef);
90-
encoder.Call (_context.ActivateInstanceRef);
91-
encoder.OpCode (ILOpCode.Ret);
92-
});
93-
94-
AddUnmanagedCallersOnlyAttribute (handle);
95-
return handle;
96-
}
97-
98-
public void EmitRegisterNatives (List<NativeRegistrationData> registrations, Dictionary<string, MethodDefinitionHandle> wrapperHandles)
99-
{
100-
var validRegs = new List<(NativeRegistrationData Reg, MethodDefinitionHandle Wrapper)> (registrations.Count);
101-
foreach (var reg in registrations) {
102-
if (wrapperHandles.TryGetValue (reg.WrapperMethodName, out var wrapperHandle)) {
103-
validRegs.Add ((reg, wrapperHandle));
104-
}
105-
}
106-
107-
if (validRegs.Count == 0) {
108-
_pe.EmitBody ("RegisterNatives",
109-
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig |
110-
MethodAttributes.NewSlot | MethodAttributes.Final,
111-
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
112-
rt => rt.Void (),
113-
p => p.AddParameter ().Type ().Type (_context.JniTypeRef, false)),
114-
encoder => encoder.OpCode (ILOpCode.Ret));
115-
return;
116-
}
117-
118-
var nameFields = new FieldDefinitionHandle [validRegs.Count];
119-
var sigFields = new FieldDefinitionHandle [validRegs.Count];
120-
for (int i = 0; i < validRegs.Count; i++) {
121-
nameFields [i] = _pe.GetOrAddUtf8Field (validRegs [i].Reg.JniMethodName);
122-
sigFields [i] = _pe.GetOrAddUtf8Field (validRegs [i].Reg.JniSignature);
123-
}
124-
125-
int methodCount = validRegs.Count;
126-
127-
_pe.EmitBody ("RegisterNatives",
128-
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig |
129-
MethodAttributes.NewSlot | MethodAttributes.Final,
130-
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
131-
rt => rt.Void (),
132-
p => p.AddParameter ().Type ().Type (_context.JniTypeRef, false)),
133-
encoder => {
134-
encoder.LoadConstantI4 (methodCount);
135-
encoder.OpCode (ILOpCode.Sizeof);
136-
encoder.Token (_context.JniNativeMethodRef);
137-
encoder.OpCode (ILOpCode.Mul);
138-
encoder.OpCode (ILOpCode.Localloc);
139-
encoder.StoreLocal (0);
140-
141-
for (int i = 0; i < methodCount; i++) {
142-
encoder.LoadLocal (0);
143-
if (i > 0) {
144-
encoder.LoadConstantI4 (i);
145-
encoder.OpCode (ILOpCode.Sizeof);
146-
encoder.Token (_context.JniNativeMethodRef);
147-
encoder.OpCode (ILOpCode.Mul);
148-
encoder.OpCode (ILOpCode.Add);
149-
}
150-
151-
encoder.OpCode (ILOpCode.Ldsflda);
152-
encoder.Token (nameFields [i]);
153-
154-
encoder.OpCode (ILOpCode.Ldsflda);
155-
encoder.Token (sigFields [i]);
156-
157-
encoder.OpCode (ILOpCode.Ldftn);
158-
encoder.Token (validRegs [i].Wrapper);
159-
160-
encoder.OpCode (ILOpCode.Newobj);
161-
encoder.Token (_context.JniNativeMethodCtorRef);
162-
encoder.OpCode (ILOpCode.Stobj);
163-
encoder.Token (_context.JniNativeMethodRef);
164-
}
165-
166-
encoder.LoadArgument (1);
167-
encoder.OpCode (ILOpCode.Callvirt);
168-
encoder.Token (_context.JniTypePeerReferenceRef);
169-
encoder.StoreLocal (1);
170-
171-
encoder.LoadLocalAddress (2);
172-
encoder.LoadLocal (0);
173-
encoder.LoadConstantI4 (methodCount);
174-
encoder.Call (_context.ReadOnlySpanOfJniNativeMethodCtorRef);
175-
176-
encoder.LoadLocal (1);
177-
encoder.LoadLocal (2);
178-
encoder.Call (_context.JniEnvTypesRegisterNativesRef);
179-
encoder.OpCode (ILOpCode.Ret);
180-
},
181-
encodeLocals: localSig => {
182-
localSig.WriteByte (0x07);
183-
localSig.WriteCompressedInteger (3);
184-
localSig.WriteByte (0x18);
185-
localSig.WriteByte (0x11);
186-
localSig.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_context.JniObjectReferenceRef));
187-
EncodeGenericValueTypeInst (localSig, _context.ReadOnlySpanOpenRef, _context.JniNativeMethodRef);
188-
});
189-
}
190-
19155
sealed class ExportMethodDispatchLocals
19256
{
19357
public static readonly ExportMethodDispatchLocals Empty = new (new Dictionary<int, int> (), -1, null);
@@ -208,7 +72,7 @@ public ExportMethodDispatchLocals (Dictionary<int, int> arrayParameterLocals, in
20872

20973
static ExportMethodDispatchData GetRequiredExportMethodDispatch (UcoMethodData uco)
21074
{
211-
return uco.ExportMethodDispatch ?? throw new InvalidOperationException ($"UCO method '{uco.WrapperName}' is missing ExportMethodDispatch metadata.");
75+
return uco.ExportMethodDispatch ?? throw new InvalidOperationException ($"ExportMethodDispatchEmitter only supports UCO methods with ExportMethodDispatch metadata.");
21276
}
21377

21478
ExportMethodDispatchLocals CreateExportMethodDispatchLocals (ExportMethodDispatchData exportMethodDispatch, bool isVoid)
@@ -592,15 +456,6 @@ void AddUnmanagedCallersOnlyAttribute (MethodDefinitionHandle handle)
592456
_pe.Metadata.AddCustomAttribute (handle, _context.UcoAttrCtorRef, _context.UcoAttrBlobHandle);
593457
}
594458

595-
static void EncodeGenericValueTypeInst (BlobBuilder builder, EntityHandle openType, EntityHandle valueTypeArg)
596-
{
597-
builder.WriteByte (0x15);
598-
builder.WriteByte (0x11);
599-
builder.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (openType));
600-
builder.WriteCompressedInteger (1);
601-
builder.WriteByte (0x11);
602-
builder.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (valueTypeArg));
603-
}
604459
}
605460

606461
sealed class ExportMethodDispatchEmitterContext

src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,9 @@ void EmitProxyType (JavaPeerProxyData proxy, Dictionary<string, MethodDefinition
606606

607607
// UCO wrappers
608608
foreach (var uco in proxy.UcoMethods) {
609-
var handle = exportMethodDispatchEmitter.EmitUcoMethod (uco);
609+
var handle = uco.UsesExportMethodDispatch
610+
? exportMethodDispatchEmitter.EmitUcoMethod (uco)
611+
: EmitUcoMethod (uco);
610612
wrapperHandles [uco.WrapperName] = handle;
611613
}
612614

@@ -617,7 +619,7 @@ void EmitProxyType (JavaPeerProxyData proxy, Dictionary<string, MethodDefinition
617619

618620
// RegisterNatives
619621
if (proxy.IsAcw) {
620-
exportMethodDispatchEmitter.EmitRegisterNatives (proxy.NativeRegistrations, wrapperHandles);
622+
EmitRegisterNatives (proxy.NativeRegistrations, wrapperHandles);
621623
}
622624
}
623625

@@ -867,6 +869,139 @@ MemberReferenceHandle AddActivationCtorRef (EntityHandle declaringTypeRef)
867869
}));
868870
}
869871

872+
MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco)
873+
{
874+
var jniParams = JniSignatureHelper.ParseParameterTypes (uco.JniSignature);
875+
var returnKind = JniSignatureHelper.ParseReturnType (uco.JniSignature);
876+
int paramCount = 2 + jniParams.Count;
877+
bool isVoid = returnKind == JniParamKind.Void;
878+
879+
Action<BlobEncoder> encodeSig = sig => sig.MethodSignature ().Parameters (paramCount,
880+
rt => { if (isVoid) rt.Void (); else JniSignatureHelper.EncodeClrType (rt.Type (), returnKind); },
881+
p => {
882+
p.AddParameter ().Type ().IntPtr ();
883+
p.AddParameter ().Type ().IntPtr ();
884+
for (int j = 0; j < jniParams.Count; j++) {
885+
JniSignatureHelper.EncodeClrType (p.AddParameter ().Type (), jniParams [j]);
886+
}
887+
});
888+
var callbackTypeHandle = _pe.ResolveTypeRef (uco.CallbackType);
889+
var callbackRef = _pe.AddMemberRef (callbackTypeHandle, uco.CallbackMethodName, encodeSig);
890+
891+
var handle = _pe.EmitBody (uco.WrapperName,
892+
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
893+
encodeSig,
894+
encoder => {
895+
for (int p = 0; p < paramCount; p++) {
896+
encoder.LoadArgument (p);
897+
}
898+
899+
encoder.Call (callbackRef);
900+
encoder.OpCode (ILOpCode.Ret);
901+
});
902+
903+
AddUnmanagedCallersOnlyAttribute (handle);
904+
return handle;
905+
}
906+
907+
void EmitRegisterNatives (List<NativeRegistrationData> registrations, Dictionary<string, MethodDefinitionHandle> wrapperHandles)
908+
{
909+
var validRegs = new List<(NativeRegistrationData Reg, MethodDefinitionHandle Wrapper)> (registrations.Count);
910+
foreach (var reg in registrations) {
911+
if (wrapperHandles.TryGetValue (reg.WrapperMethodName, out var wrapperHandle)) {
912+
validRegs.Add ((reg, wrapperHandle));
913+
}
914+
}
915+
916+
if (validRegs.Count == 0) {
917+
_pe.EmitBody ("RegisterNatives",
918+
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig |
919+
MethodAttributes.NewSlot | MethodAttributes.Final,
920+
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
921+
rt => rt.Void (),
922+
p => p.AddParameter ().Type ().Type (_jniTypeRef, false)),
923+
encoder => encoder.OpCode (ILOpCode.Ret));
924+
return;
925+
}
926+
927+
var nameFields = new FieldDefinitionHandle [validRegs.Count];
928+
var sigFields = new FieldDefinitionHandle [validRegs.Count];
929+
for (int i = 0; i < validRegs.Count; i++) {
930+
nameFields [i] = _pe.GetOrAddUtf8Field (validRegs [i].Reg.JniMethodName);
931+
sigFields [i] = _pe.GetOrAddUtf8Field (validRegs [i].Reg.JniSignature);
932+
}
933+
934+
int methodCount = validRegs.Count;
935+
936+
_pe.EmitBody ("RegisterNatives",
937+
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig |
938+
MethodAttributes.NewSlot | MethodAttributes.Final,
939+
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (1,
940+
rt => rt.Void (),
941+
p => p.AddParameter ().Type ().Type (_jniTypeRef, false)),
942+
encoder => {
943+
encoder.LoadConstantI4 (methodCount);
944+
encoder.OpCode (ILOpCode.Sizeof);
945+
encoder.Token (_jniNativeMethodRef);
946+
encoder.OpCode (ILOpCode.Mul);
947+
encoder.OpCode (ILOpCode.Localloc);
948+
encoder.StoreLocal (0);
949+
950+
for (int i = 0; i < methodCount; i++) {
951+
encoder.LoadLocal (0);
952+
if (i > 0) {
953+
encoder.LoadConstantI4 (i);
954+
encoder.OpCode (ILOpCode.Sizeof);
955+
encoder.Token (_jniNativeMethodRef);
956+
encoder.OpCode (ILOpCode.Mul);
957+
encoder.OpCode (ILOpCode.Add);
958+
}
959+
960+
encoder.OpCode (ILOpCode.Ldsflda);
961+
encoder.Token (nameFields [i]);
962+
963+
encoder.OpCode (ILOpCode.Ldsflda);
964+
encoder.Token (sigFields [i]);
965+
966+
encoder.OpCode (ILOpCode.Ldftn);
967+
encoder.Token (validRegs [i].Wrapper);
968+
969+
encoder.OpCode (ILOpCode.Newobj);
970+
encoder.Token (_jniNativeMethodCtorRef);
971+
encoder.OpCode (ILOpCode.Stobj);
972+
encoder.Token (_jniNativeMethodRef);
973+
}
974+
975+
encoder.LoadArgument (1);
976+
encoder.OpCode (ILOpCode.Callvirt);
977+
encoder.Token (_jniTypePeerReferenceRef);
978+
encoder.StoreLocal (1);
979+
980+
encoder.LoadLocalAddress (2);
981+
encoder.LoadLocal (0);
982+
encoder.LoadConstantI4 (methodCount);
983+
encoder.Call (_readOnlySpanOfJniNativeMethodCtorRef);
984+
985+
encoder.LoadLocal (1);
986+
encoder.LoadLocal (2);
987+
encoder.Call (_jniEnvTypesRegisterNativesRef);
988+
encoder.OpCode (ILOpCode.Ret);
989+
},
990+
encodeLocals: localSig => {
991+
localSig.WriteByte (0x07);
992+
localSig.WriteCompressedInteger (3);
993+
localSig.WriteByte (0x18);
994+
localSig.WriteByte (0x11);
995+
localSig.WriteCompressedInteger (CodedIndex.TypeDefOrRefOrSpec (_jniObjectReferenceRef));
996+
EncodeGenericValueTypeInst (localSig, _readOnlySpanOpenRef, _jniNativeMethodRef);
997+
});
998+
}
999+
1000+
void AddUnmanagedCallersOnlyAttribute (MethodDefinitionHandle handle)
1001+
{
1002+
_pe.Metadata.AddCustomAttribute (handle, _ucoAttrCtorRef, _ucoAttrBlobHandle);
1003+
}
1004+
8701005
MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxyData proxy)
8711006
{
8721007
var targetTypeRef = _pe.ResolveTypeRef (uco.TargetType);

0 commit comments

Comments
 (0)