Skip to content

Commit 70a4f93

Browse files
authored
[NativeAOT] Integrate TryCreatePeer (#9746)
Context: dbb0b92 Context: dotnet/java-interop@dd3c1d0 Commit dbb0b92 had to copy significant parts of `JniRuntime.JniValueManager.CreatePeer()` in order to get the desired semantics. dotnet/java-interop@dd3c1d05 added a `TryCreatePeer()` virtual method in an effort to reduce the amount of copied code required. Update `NativeAotValueManager` to override the new method, allowing us to remove most of the `CreatePeer()` code added in dbb0b92. Additionally, override `GetInvokerTypeCore()` within `NativeAotTypeManager` so that .NET for Android -style `Invoker` types can be appropriately resolved.
1 parent b09d51a commit 70a4f93

File tree

2 files changed

+42
-143
lines changed

2 files changed

+42
-143
lines changed

samples/NativeAOT/NativeAotTypeManager.cs

+40
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace NativeAOT;
77

88
partial class NativeAotTypeManager : JniRuntime.JniTypeManager {
99

10+
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
1011
internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods;
1112
internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
1213

@@ -28,6 +29,45 @@ public NativeAotTypeManager ()
2829
AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: NativeAotTypeManager()");
2930
}
3031

32+
protected override Type? GetInvokerTypeCore (Type type)
33+
{
34+
const string suffix = "Invoker";
35+
36+
// https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186
37+
const string assemblyGetTypeMessage = "'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
38+
const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
39+
40+
[UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = assemblyGetTypeMessage)]
41+
[UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = assemblyGetTypeMessage)]
42+
[return: DynamicallyAccessedMembers (Constructors)]
43+
static Type? AssemblyGetType (Assembly assembly, string typeName) =>
44+
assembly.GetType (typeName);
45+
46+
[UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)]
47+
[return: DynamicallyAccessedMembers (Constructors)]
48+
static Type MakeGenericType (
49+
[DynamicallyAccessedMembers (Constructors)]
50+
Type type,
51+
Type [] arguments) =>
52+
// FIXME: https://github.com/dotnet/java-interop/issues/1192
53+
#pragma warning disable IL3050
54+
type.MakeGenericType (arguments);
55+
#pragma warning restore IL3050
56+
57+
Type[] arguments = type.GetGenericArguments ();
58+
if (arguments.Length == 0)
59+
return AssemblyGetType (type.Assembly, type + suffix) ?? base.GetInvokerTypeCore (type);
60+
Type definition = type.GetGenericTypeDefinition ();
61+
int bt = definition.FullName!.IndexOf ("`", StringComparison.Ordinal);
62+
if (bt == -1)
63+
throw new NotSupportedException ("Generic type doesn't follow generic type naming convention! " + type.FullName);
64+
Type? suffixDefinition = AssemblyGetType (definition.Assembly,
65+
definition.FullName.Substring (0, bt) + suffix + definition.FullName.Substring (bt));
66+
if (suffixDefinition == null)
67+
return base.GetInvokerTypeCore (type);
68+
return MakeGenericType (suffixDefinition, arguments);
69+
}
70+
3171
public override void RegisterNativeMembers (
3272
JniType nativeClass,
3373
[DynamicallyAccessedMembers (MethodsAndPrivateNested)]

samples/NativeAOT/NativeAotValueManager.cs

+2-143
Original file line numberDiff line numberDiff line change
@@ -253,142 +253,11 @@ public override List<JniSurfacedPeerInfo> GetSurfacedPeers ()
253253
}
254254
}
255255

256-
public override IJavaPeerable? CreatePeer (
257-
ref JniObjectReference reference,
258-
JniObjectReferenceOptions transfer,
259-
[DynamicallyAccessedMembers (Constructors)]
260-
Type? targetType)
261-
{
262-
if (!reference.IsValid) {
263-
return null;
264-
}
265-
266-
targetType = targetType ?? typeof (global::Java.Interop.JavaObject);
267-
targetType = GetPeerType (targetType);
268-
269-
if (!typeof (IJavaPeerable).IsAssignableFrom (targetType))
270-
throw new ArgumentException ($"targetType `{targetType.AssemblyQualifiedName}` must implement IJavaPeerable!", nameof (targetType));
271-
272-
var targetSig = Runtime.TypeManager.GetTypeSignature (targetType);
273-
if (!targetSig.IsValid || targetSig.SimpleReference == null) {
274-
throw new ArgumentException ($"Could not determine Java type corresponding to `{targetType.AssemblyQualifiedName}`.", nameof (targetType));
275-
}
276-
277-
var refClass = JniEnvironment.Types.GetObjectClass (reference);
278-
JniObjectReference targetClass;
279-
try {
280-
targetClass = JniEnvironment.Types.FindClass (targetSig.SimpleReference);
281-
} catch (Exception e) {
282-
JniObjectReference.Dispose (ref refClass);
283-
throw new ArgumentException ($"Could not find Java class `{targetSig.SimpleReference}`.",
284-
nameof (targetType),
285-
e);
286-
}
287-
288-
if (!JniEnvironment.Types.IsAssignableFrom (refClass, targetClass)) {
289-
JniObjectReference.Dispose (ref refClass);
290-
JniObjectReference.Dispose (ref targetClass);
291-
return null;
292-
}
293-
294-
JniObjectReference.Dispose (ref targetClass);
295-
296-
var proxy = CreatePeerProxy (ref refClass, targetType, ref reference, transfer);
297-
298-
if (proxy == null) {
299-
throw new NotSupportedException (string.Format ("Could not find an appropriate constructable wrapper type for Java type '{0}', targetType='{1}'.",
300-
JniEnvironment.Types.GetJniTypeNameFromInstance (reference), targetType));
301-
}
302-
303-
proxy.SetJniManagedPeerState (proxy.JniManagedPeerState | JniManagedPeerStates.Replaceable);
304-
return proxy;
305-
}
306-
307-
[return: DynamicallyAccessedMembers (Constructors)]
308-
static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type)
309-
{
310-
if (type == typeof (object))
311-
return typeof (global::Java.Interop.JavaObject);
312-
if (type == typeof (IJavaPeerable))
313-
return typeof (global::Java.Interop.JavaObject);
314-
if (type == typeof (Exception))
315-
return typeof (global::Java.Interop.JavaException);
316-
return type;
317-
}
318-
319-
IJavaPeerable? CreatePeerProxy (
320-
ref JniObjectReference klass,
321-
[DynamicallyAccessedMembers (Constructors)]
322-
Type fallbackType,
323-
ref JniObjectReference reference,
324-
JniObjectReferenceOptions options)
325-
{
326-
var jniTypeName = JniEnvironment.Types.GetJniTypeNameFromClass (klass);
327-
328-
Type? type = null;
329-
while (jniTypeName != null) {
330-
JniTypeSignature sig;
331-
if (!JniTypeSignature.TryParse (jniTypeName, out sig))
332-
return null;
333-
334-
type = Runtime.TypeManager.GetType (sig);
335-
336-
if (type != null) {
337-
var peer = TryCreatePeerProxy (type, ref reference, options);
338-
if (peer != null) {
339-
return peer;
340-
}
341-
}
342-
343-
var super = JniEnvironment.Types.GetSuperclass (klass);
344-
jniTypeName = super.IsValid
345-
? JniEnvironment.Types.GetJniTypeNameFromClass (super)
346-
: null;
347-
348-
JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);
349-
klass = super;
350-
}
351-
JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose);
352-
353-
return TryCreatePeerProxy (fallbackType, ref reference, options);
354-
}
355-
356-
[return: DynamicallyAccessedMembers (Constructors)]
357-
static Type? GetInvokerType (Type type)
358-
{
359-
// https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186
360-
const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
361-
362-
[UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)]
363-
[return: DynamicallyAccessedMembers (Constructors)]
364-
static Type MakeGenericType (
365-
[DynamicallyAccessedMembers (Constructors)]
366-
Type type,
367-
Type [] arguments) =>
368-
// FIXME: https://github.com/dotnet/java-interop/issues/1192
369-
#pragma warning disable IL3050
370-
type.MakeGenericType (arguments);
371-
#pragma warning restore IL3050
372-
373-
var signature = type.GetCustomAttribute<JniTypeSignatureAttribute> ();
374-
if (signature == null || signature.InvokerType == null) {
375-
return null;
376-
}
377-
378-
Type[] arguments = type.GetGenericArguments ();
379-
if (arguments.Length == 0)
380-
return signature.InvokerType;
381-
382-
return MakeGenericType (signature.InvokerType, arguments);
383-
}
384-
385256
const BindingFlags ActivationConstructorBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
386257

387-
388258
static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) };
389-
static readonly Type[] JIConstructorSignature = new Type [] { typeof (JniObjectReference).MakeByRefType (), typeof (JniObjectReferenceOptions) };
390259

391-
protected virtual IJavaPeerable? TryCreatePeerProxy (Type type, ref JniObjectReference reference, JniObjectReferenceOptions options)
260+
protected override IJavaPeerable? TryCreatePeer (ref JniObjectReference reference, JniObjectReferenceOptions options, Type type)
392261
{
393262
var c = type.GetConstructor (ActivationConstructorBindingFlags, null, XAConstructorSignature, null);
394263
if (c != null) {
@@ -400,16 +269,6 @@ static Type MakeGenericType (
400269
JniObjectReference.Dispose (ref reference, options);
401270
return p;
402271
}
403-
c = type.GetConstructor (ActivationConstructorBindingFlags, null, JIConstructorSignature, null);
404-
if (c != null) {
405-
var args = new object[] {
406-
reference,
407-
options,
408-
};
409-
var p = (IJavaPeerable) c.Invoke (args);
410-
reference = (JniObjectReference) args [0];
411-
return p;
412-
}
413-
return null;
272+
return base.TryCreatePeer (ref reference, options, type);
414273
}
415274
}

0 commit comments

Comments
 (0)