Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,12 @@ void EmitTypeReferences ()
void EmitMemberReferences ()
{
_baseCtorRef = _pe.AddMemberRef (_javaPeerProxyRef, ".ctor",
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (0, rt => rt.Void (), p => { }));
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (2,
rt => rt.Void (),
p => {
p.AddParameter ().Type ().Type (_systemTypeRef, false);
p.AddParameter ().Type ().Type (_systemTypeRef, false);
}));

_getTypeFromHandleRef = _pe.AddMemberRef (_systemTypeRef, "GetTypeFromHandle",
sig => sig.MethodSignature ().Parameters (1,
Expand Down Expand Up @@ -360,29 +365,31 @@ void EmitProxyType (JavaPeerProxyData proxy, Dictionary<string, MethodDefinition
metadata.AddInterfaceImplementation (typeDefHandle, _iAndroidCallableWrapperRef);
}

// .ctor
// .ctor — pass TargetType and InvokerType to base ctor
_pe.EmitBody (".ctor",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (0, rt => rt.Void (), p => { }),
encoder => {
encoder.OpCode (ILOpCode.Ldarg_0);
// arg 1: typeof(TargetType)
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (_pe.ResolveTypeRef (proxy.TargetType));
encoder.Call (_getTypeFromHandleRef);
// arg 2: typeof(InvokerType) or null
if (proxy.InvokerType != null) {
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (_pe.ResolveTypeRef (proxy.InvokerType));
encoder.Call (_getTypeFromHandleRef);
} else {
encoder.OpCode (ILOpCode.Ldnull);
}
encoder.Call (_baseCtorRef);
encoder.OpCode (ILOpCode.Ret);
});

// CreateInstance
EmitCreateInstance (proxy);

// get_TargetType
EmitTypeGetter ("get_TargetType", proxy.TargetType,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig);

// get_InvokerType
if (proxy.InvokerType != null) {
EmitTypeGetter ("get_InvokerType", proxy.InvokerType,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
}

// UCO wrappers
foreach (var uco in proxy.UcoMethods) {
var handle = EmitUcoMethod (uco);
Expand Down Expand Up @@ -646,22 +653,6 @@ MemberReferenceHandle AddActivationCtorRef (EntityHandle declaringTypeRef)
}));
}

void EmitTypeGetter (string methodName, TypeRefData typeRef, MethodAttributes attrs)
{
var handle = _pe.ResolveTypeRef (typeRef);

_pe.EmitBody (methodName, attrs,
sig => sig.MethodSignature (isInstanceMethod: true).Parameters (0,
rt => rt.Type ().Type (_systemTypeRef, false),
p => { }),
encoder => {
encoder.OpCode (ILOpCode.Ldtoken);
encoder.Token (handle);
encoder.Call (_getTypeFromHandleRef);
encoder.OpCode (ILOpCode.Ret);
});
}

MethodDefinitionHandle EmitUcoMethod (UcoMethodData uco)
{
var jniParams = JniSignatureHelper.ParseParameterTypes (uco.JniSignature);
Expand Down
26 changes: 19 additions & 7 deletions src/Mono.Android/Java.Interop/JavaPeerProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,42 @@ namespace Java.Interop
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
public abstract class JavaPeerProxy : Attribute
{
/// <summary>
/// Initializes a new proxy with the specified target and invoker types.
/// </summary>
/// <param name="targetType">The managed peer type this proxy represents.</param>
/// <param name="invokerType">The invoker type for interfaces/abstract classes, or <c>null</c> for concrete types.</param>
protected JavaPeerProxy (
Type targetType,
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? invokerType)
{
TargetType = targetType;
InvokerType = invokerType;
}

/// <summary>
/// Creates an instance of the target type using the JNI handle and ownership semantics.
/// This replaces the reflection-based constructor invocation used in the legacy path.
/// </summary>
/// <param name="handle">The JNI object reference handle.</param>
/// <param name="transfer">How to handle JNI reference ownership.</param>
/// <returns>A new instance of the target type wrapping the JNI handle, or null if activation is not supported.</returns>
public abstract IJavaPeerable? CreateInstance (IntPtr handle, JniHandleOwnership transfer);

/// <summary>
/// Gets the target .NET type that this proxy represents.
/// </summary>
public abstract Type TargetType { get; }
public Type TargetType { get; }

/// <summary>
/// Gets the invoker type for interfaces and abstract classes.
/// Returns null for concrete types that can be directly instantiated.
/// </summary>
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public virtual Type? InvokerType => null;
public Type? InvokerType { get; }

/// <summary>
/// Gets a factory for creating containers (arrays, collections) of the target type.
/// Enables AOT-safe creation of generic collections without <c>MakeGenericType()</c>.
/// </summary>
/// <returns>A factory for creating containers of the target type, or null if not supported.</returns>
public virtual JavaPeerContainerFactory? GetContainerFactory () => null;
}

Expand All @@ -59,7 +69,9 @@ public abstract class JavaPeerProxy<
T
> : JavaPeerProxy where T : class, IJavaPeerable
{
public override Type TargetType => typeof (T);
protected JavaPeerProxy (
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type? invokerType) : base (typeof (T), invokerType) { }

public override JavaPeerContainerFactory GetContainerFactory ()
=> JavaPeerContainerFactory<T>.Instance;
Expand Down