Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
2e896ef
Add trimmable typemap test plumbing and CI lane
simonrozsival Apr 13, 2026
03931ef
Keep CoreCLR test flavor naming in CI
simonrozsival Apr 13, 2026
6eaf945
Address PR review: fix manifest name matching and null guard
simonrozsival Mar 31, 2026
a66216b
[TrimmableTypeMap] Match compat names in manifest rooting
simonrozsival Apr 7, 2026
0b42774
[TrimmableTypeMap] Merge manifest matching tests into theory
simonrozsival Apr 7, 2026
8e2e36f
[TrimmableTypeMap] Fix CoreCLR test plumbing
simonrozsival Apr 11, 2026
d64ddc1
[TrimmableTypeMap] Keep #11091 to explicit skips
simonrozsival Apr 11, 2026
b0901b4
[TrimmableTypeMap] Prune trimmable test exclusions
simonrozsival Apr 12, 2026
ee3ee25
[TrimmableTypeMap] Move disabled tests into categories
simonrozsival Apr 12, 2026
03e71b8
[TrimmableTypeMap] Restore central Java.Interop exclusions
simonrozsival Apr 12, 2026
3743d40
[TrimmableTypeMap] Revert JniTypeUtf8 test exclusion
simonrozsival Apr 12, 2026
551a3ba
[TrimmableTypeMap] Drop redundant CoreCLRIgnore filter
simonrozsival Apr 12, 2026
1cf5c9b
[TrimmableTypeMap] Simplify excluded categories assignment
simonrozsival Apr 12, 2026
c4313e0
[TrimmableTypeMap] Keep exclusions in NUnitInstrumentation
simonrozsival Apr 12, 2026
ecb5083
Add trimmable [Export] callback support
simonrozsival Apr 13, 2026
e574e3b
Refactor [Export] code generation
simonrozsival Apr 13, 2026
3e5622b
Exclude Mono.Android.Export from trimmable packages
simonrozsival Apr 13, 2026
fad9ff6
Refine export method dispatch model
simonrozsival Apr 13, 2026
6e8222f
Scope export method dispatch emission
simonrozsival Apr 13, 2026
0b16c9e
Tighten trimmable export cleanup
simonrozsival Apr 13, 2026
7818344
Propagate deferred registerNatives to base classes and fix test plumbing
simonrozsival Apr 13, 2026
4766917
Remove unrelated changes: revert test plumbing, CI lane, and manifest…
simonrozsival Apr 16, 2026
c5b5ca4
Revert whitespace-only changes and restore EmitRegisterNatives position
simonrozsival Apr 16, 2026
4d1aae9
Fix stack corruption in TryEmitExportParameterArgument
simonrozsival Apr 16, 2026
5b19b4e
Revert MonoAndroidExportTest changes that force trimmable typemap
simonrozsival Apr 17, 2026
76b6bc7
Fix instrumentation targetPackage default
simonrozsival Apr 18, 2026
6684633
Fix missing 'static' keyword in Java codegen for static [Export] methods
simonrozsival Apr 21, 2026
6b9c343
Address review: perf optimization + code organization
simonrozsival Apr 21, 2026
8ef8e74
Fix test: TypeMapAssociationAttribute is no longer generic
simonrozsival Apr 22, 2026
88ccf3a
Revert Java.Interop submodule to match main
simonrozsival Apr 22, 2026
3b191bc
Remove dead ManagedParameterTypeNames/ManagedReturnTypeName propertie…
simonrozsival Apr 22, 2026
68aafbe
Fix test: TypeMapAssociationAttribute is generic (TypeMapAssociationA…
simonrozsival Apr 26, 2026
44f797a
Restore ExcludedTestNames for trimmable typemap tests
simonrozsival Apr 26, 2026
5fb797e
Trimmable typemap: invoke user-visible parameterless ctor in UCO wrap…
simonrozsival Apr 26, 2026
5750370
Fix bad-rebase artifacts: restore CI lane and submodule SHA
simonrozsival Apr 27, 2026
15799c5
Reduce diff churn against base
simonrozsival Apr 27, 2026
2148538
Drop unnecessary Java_mono_android_Runtime_registerNatives JNI export
simonrozsival Apr 27, 2026
71c1dd9
Move EmitRegisterNatives + AddUnmanagedCallersOnlyAttribute back to o…
simonrozsival Apr 27, 2026
a7d125a
Clean up UCO ctor comment: drop test-specific detail, point at the sa…
simonrozsival Apr 27, 2026
f3c57cd
Address review feedback: lazy export emitter, hoist deferred check, d…
simonrozsival Apr 27, 2026
48f4603
Add device tests for parameterized ctor activation contract
simonrozsival Apr 27, 2026
172f6ca
Redesign parameterized ctor activation tests around Throwable args
simonrozsival Apr 27, 2026
d8d356b
[trimmable typemap] Gate user-ctor UCO emission on matching managed .…
simonrozsival Apr 27, 2026
e130dde
[trimmable typemap] Forward JNI args to user-visible parameterized .ctor
simonrozsival Apr 27, 2026
8d27b03
[trimmable typemap] Simplify ManagedParameterTypes plumbing
simonrozsival Apr 27, 2026
9344130
[trimmable typemap] Extract user-visible ctor wrapper emission helper
simonrozsival Apr 27, 2026
7f1b851
Reuse export primitive marshalling for parameterized UCO ctor args
simonrozsival Apr 27, 2026
be70eb9
Add Mono.Android.NET-Tests device coverage for [Export] marshalling
simonrozsival Apr 27, 2026
7ab24b6
Wrap [Export] UCO methods with OnUserUnhandledException routing
simonrozsival Apr 27, 2026
06d89aa
Skip parameterized [Export] ctors with unsupported types
simonrozsival Apr 27, 2026
0314a0f
Update [Export] throws tests for OnUserUnhandledException semantics
simonrozsival Apr 27, 2026
634af35
Marshal enum [Export] params/returns via underlying primitive JNI ABI
simonrozsival Apr 27, 2026
86e94d7
Marshal ICharSequence and non-generic collection [Export] returns via…
simonrozsival Apr 27, 2026
359ce47
Update export-comparison.md to reflect Phase 1 marshalling parity work
simonrozsival Apr 27, 2026
655aac7
Make enum scanner resolution assembly-aware and resilient to FQN coll…
simonrozsival Apr 27, 2026
1c91016
Simplify enum scanner helpers in JavaPeerScanner
simonrozsival Apr 27, 2026
0d2f040
Remove export-comparison.md — analysis doc not intended for merge
simonrozsival Apr 27, 2026
a90771d
Add scanner integration coverage for advanced [Export] shapes
simonrozsival Apr 27, 2026
a35ba66
Scanner integration: cover [ExportField] and [ExportParameter]; fix u…
simonrozsival Apr 27, 2026
2341855
Phase A scanner coverage: dispatch & declaration shapes
simonrozsival Apr 27, 2026
eee851c
Phase B scanner coverage: edge marshalling shapes
simonrozsival Apr 27, 2026
430aa04
Phase C scanner coverage: robustness shapes
simonrozsival Apr 27, 2026
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;

namespace Microsoft.Android.Sdk.TrimmableTypeMap;

/// <summary>
/// Holds pre-resolved metadata references needed by <see cref="ExportMethodDispatchEmitter"/>
/// for generating [Export] method dispatch IL. Created once per emit pass and reused
/// for all export methods.
/// </summary>
sealed class ExportMethodDispatchEmitterContext
{
public static ExportMethodDispatchEmitterContext Create (
PEAssemblyBuilder pe,
TypeReferenceHandle iJavaPeerableRef,
TypeReferenceHandle jniHandleOwnershipRef,
TypeReferenceHandle jniEnvRef,
TypeReferenceHandle systemTypeRef,
MemberReferenceHandle getTypeFromHandleRef,
MemberReferenceHandle ucoAttrCtorRef,
BlobHandle ucoAttrBlobHandle,
TypeReferenceHandle jniTransitionRef,
TypeReferenceHandle jniRuntimeRef,
TypeReferenceHandle exceptionRef,
MemberReferenceHandle beginMarshalMethodRef,
MemberReferenceHandle endMarshalMethodRef,
MemberReferenceHandle onUserUnhandledExceptionRef)
{
var metadata = pe.Metadata;
var iJavaObjectRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("IJavaObject"));
var javaLangObjectRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Java.Lang"), metadata.GetOrAddString ("Object"));
var systemArrayRef = metadata.AddTypeReference (pe.SystemRuntimeRef,
metadata.GetOrAddString ("System"), metadata.GetOrAddString ("Array"));
var systemStreamRef = metadata.AddTypeReference (pe.SystemRuntimeRef,
metadata.GetOrAddString ("System.IO"), metadata.GetOrAddString ("Stream"));
var systemXmlRef = pe.FindOrAddAssemblyRef ("System.Xml.ReaderWriter");
var systemXmlReaderRef = metadata.AddTypeReference (systemXmlRef,
metadata.GetOrAddString ("System.Xml"), metadata.GetOrAddString ("XmlReader"));
var inputStreamInvokerRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("InputStreamInvoker"));
var outputStreamInvokerRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("OutputStreamInvoker"));
var inputStreamAdapterRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("InputStreamAdapter"));
var outputStreamAdapterRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("OutputStreamAdapter"));
var xmlPullParserReaderRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("XmlPullParserReader"));
var xmlResourceParserReaderRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("XmlResourceParserReader"));
var xmlReaderPullParserRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("XmlReaderPullParser"));
var xmlReaderResourceParserRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("XmlReaderResourceParser"));
var charSequenceRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("CharSequence"));
var iCharSequenceRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Java.Lang"), metadata.GetOrAddString ("ICharSequence"));
var javaListRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("JavaList"));
var javaDictionaryRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("JavaDictionary"));
var javaCollectionRef = metadata.AddTypeReference (pe.MonoAndroidRef,
metadata.GetOrAddString ("Android.Runtime"), metadata.GetOrAddString ("JavaCollection"));
var systemCollectionsIListRef = metadata.AddTypeReference (pe.SystemRuntimeRef,
metadata.GetOrAddString ("System.Collections"), metadata.GetOrAddString ("IList"));
var systemCollectionsIDictionaryRef = metadata.AddTypeReference (pe.SystemRuntimeRef,
metadata.GetOrAddString ("System.Collections"), metadata.GetOrAddString ("IDictionary"));
var systemCollectionsICollectionRef = metadata.AddTypeReference (pe.SystemRuntimeRef,
metadata.GetOrAddString ("System.Collections"), metadata.GetOrAddString ("ICollection"));

return new ExportMethodDispatchEmitterContext {
IJavaObjectRef = iJavaObjectRef,
GetTypeFromHandleRef = getTypeFromHandleRef,
JniEnvGetStringRef = pe.AddMemberRef (jniEnvRef, "GetString",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Type ().String (),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
})),
JniEnvGetArrayRef = pe.AddMemberRef (jniEnvRef, "GetArray",
sig => sig.MethodSignature ().Parameters (3,
rt => rt.Type ().Type (systemArrayRef, false),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
p.AddParameter ().Type ().Type (systemTypeRef, false);
})),
JniEnvCopyArrayRef = pe.AddMemberRef (jniEnvRef, "CopyArray",
sig => sig.MethodSignature ().Parameters (3,
rt => rt.Void (),
p => {
p.AddParameter ().Type ().Type (systemArrayRef, false);
p.AddParameter ().Type ().Type (systemTypeRef, false);
p.AddParameter ().Type ().IntPtr ();
})),
JniEnvNewArrayRef = pe.AddMemberRef (jniEnvRef, "NewArray",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Type ().IntPtr (),
p => {
p.AddParameter ().Type ().Type (systemArrayRef, false);
p.AddParameter ().Type ().Type (systemTypeRef, false);
})),
JniEnvNewStringRef = pe.AddMemberRef (jniEnvRef, "NewString",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().String ())),
JniEnvToLocalJniHandleRef = pe.AddMemberRef (jniEnvRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (iJavaObjectRef, false))),
JavaLangObjectGetObjectRef = pe.AddMemberRef (javaLangObjectRef, "GetObject",
sig => sig.MethodSignature ().Parameters (3,
rt => rt.Type ().Type (iJavaPeerableRef, false),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
p.AddParameter ().Type ().Type (systemTypeRef, false);
})),
InputStreamInvokerFromJniHandleRef = pe.AddMemberRef (inputStreamInvokerRef, "FromJniHandle",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Type ().Type (systemStreamRef, false),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
})),
OutputStreamInvokerFromJniHandleRef = pe.AddMemberRef (outputStreamInvokerRef, "FromJniHandle",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Type ().Type (systemStreamRef, false),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
})),
InputStreamAdapterToLocalJniHandleRef = pe.AddMemberRef (inputStreamAdapterRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemStreamRef, false))),
OutputStreamAdapterToLocalJniHandleRef = pe.AddMemberRef (outputStreamAdapterRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemStreamRef, false))),
XmlPullParserReaderFromJniHandleRef = pe.AddMemberRef (xmlPullParserReaderRef, "FromJniHandle",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Type ().Type (systemXmlReaderRef, false),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
})),
XmlResourceParserReaderFromJniHandleRef = pe.AddMemberRef (xmlResourceParserReaderRef, "FromJniHandle",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Type ().Type (systemXmlReaderRef, false),
p => {
p.AddParameter ().Type ().IntPtr ();
p.AddParameter ().Type ().Type (jniHandleOwnershipRef, true);
})),
XmlReaderPullParserToLocalJniHandleRef = pe.AddMemberRef (xmlReaderPullParserRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemXmlReaderRef, false))),
XmlReaderResourceParserToLocalJniHandleRef = pe.AddMemberRef (xmlReaderResourceParserRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemXmlReaderRef, false))),
CharSequenceToLocalJniHandleRef = pe.AddMemberRef (charSequenceRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (iCharSequenceRef, false))),
JavaListToLocalJniHandleRef = pe.AddMemberRef (javaListRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemCollectionsIListRef, false))),
JavaDictionaryToLocalJniHandleRef = pe.AddMemberRef (javaDictionaryRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemCollectionsIDictionaryRef, false))),
JavaCollectionToLocalJniHandleRef = pe.AddMemberRef (javaCollectionRef, "ToLocalJniHandle",
sig => sig.MethodSignature ().Parameters (1,
rt => rt.Type ().IntPtr (),
p => p.AddParameter ().Type ().Type (systemCollectionsICollectionRef, false))),
UcoAttrCtorRef = ucoAttrCtorRef,
UcoAttrBlobHandle = ucoAttrBlobHandle,
JniTransitionRef = jniTransitionRef,
JniRuntimeRef = jniRuntimeRef,
ExceptionRef = exceptionRef,
BeginMarshalMethodRef = beginMarshalMethodRef,
EndMarshalMethodRef = endMarshalMethodRef,
OnUserUnhandledExceptionRef = onUserUnhandledExceptionRef,
};
}

public required TypeReferenceHandle IJavaObjectRef { get; init; }
public required MemberReferenceHandle GetTypeFromHandleRef { get; init; }
public required MemberReferenceHandle JniEnvGetStringRef { get; init; }
public required MemberReferenceHandle JniEnvGetArrayRef { get; init; }
public required MemberReferenceHandle JniEnvCopyArrayRef { get; init; }
public required MemberReferenceHandle JniEnvNewArrayRef { get; init; }
public required MemberReferenceHandle JniEnvNewStringRef { get; init; }
public required MemberReferenceHandle JniEnvToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle JavaLangObjectGetObjectRef { get; init; }
public required MemberReferenceHandle InputStreamInvokerFromJniHandleRef { get; init; }
public required MemberReferenceHandle OutputStreamInvokerFromJniHandleRef { get; init; }
public required MemberReferenceHandle InputStreamAdapterToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle OutputStreamAdapterToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle XmlPullParserReaderFromJniHandleRef { get; init; }
public required MemberReferenceHandle XmlResourceParserReaderFromJniHandleRef { get; init; }
public required MemberReferenceHandle XmlReaderPullParserToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle XmlReaderResourceParserToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle CharSequenceToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle JavaListToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle JavaDictionaryToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle JavaCollectionToLocalJniHandleRef { get; init; }
public required MemberReferenceHandle UcoAttrCtorRef { get; init; }

public required BlobHandle UcoAttrBlobHandle { get; init; }

// Marshal-method wrapper plumbing — mirrors the UCO ctor wrapper used by
// TypeMapAssemblyEmitter so that managed exceptions thrown from [Export] method
// bodies surface as Java exceptions instead of crashing the runtime.
public required TypeReferenceHandle JniTransitionRef { get; init; }
public required TypeReferenceHandle JniRuntimeRef { get; init; }
public required TypeReferenceHandle ExceptionRef { get; init; }
public required MemberReferenceHandle BeginMarshalMethodRef { get; init; }
public required MemberReferenceHandle EndMarshalMethodRef { get; init; }
public required MemberReferenceHandle OnUserUnhandledExceptionRef { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,14 @@ static void WriteMethods (JavaPeerInfo type, TextWriter writer)
""");
} else {
string access = method.IsExport && method.JavaAccess != null ? method.JavaAccess : "public";
string staticKeyword = method.IsStatic ? "static " : "";
writer.Write ($$"""

{{access}} {{javaReturnType}} {{method.JniName}} ({{parameters}}){{throwsClause}}
{{access}} {{staticKeyword}}{{javaReturnType}} {{method.JniName}} ({{parameters}}){{throwsClause}}
{
{{registerNativesLine}} {{returnPrefix}}{{method.NativeCallbackName}} ({{args}});
}
{{access}} native {{javaReturnType}} {{method.NativeCallbackName}} ({{parameters}});
{{access}} {{staticKeyword}}native {{javaReturnType}} {{method.NativeCallbackName}} ({{parameters}});

""");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ sealed class JavaPeerProxyData
/// </summary>
public bool IsGenericDefinition { get; init; }

/// <summary>
/// True when the Java stub must not call RegisterNatives from a static initializer because
/// the type can be instantiated before the runtime is fully ready (for example Application
/// or Instrumentation subclasses).
/// </summary>
public bool CannotRegisterInStaticConstructor { get; init; }

/// <summary>
/// Whether this proxy needs ACW support (RegisterNatives + UCO wrappers + IAndroidCallableWrapper).
/// </summary>
Expand All @@ -149,7 +156,7 @@ sealed class JavaPeerProxyData
/// <summary>
/// A cross-assembly type reference (assembly name + full managed type name).
/// </summary>
sealed record TypeRefData
public sealed record TypeRefData
{
/// <summary>
/// Full managed type name, e.g., "Android.App.Activity" or "MyApp.Outer+Inner".
Expand All @@ -160,11 +167,19 @@ sealed record TypeRefData
/// Assembly containing the type, e.g., "Mono.Android".
/// </summary>
public required string AssemblyName { get; init; }

/// <summary>
/// True if this type — or, for array types, the element type — is an enum.
/// Used by the IL emitter to encode the type as <c>ELEMENT_TYPE_VALUETYPE</c>
/// rather than <c>ELEMENT_TYPE_CLASS</c> in member references and signatures.
/// </summary>
public bool IsEnum { get; init; }
}

/// <summary>
/// An [UnmanagedCallersOnly] static wrapper for a marshal method.
/// Body: load all args → call n_* callback → ret.
/// Body: either forward to an existing n_* callback or dispatch directly to the
/// managed export target when the trimmable path can avoid dynamic callback generation.
/// </summary>
sealed record UcoMethodData
{
Expand All @@ -174,7 +189,7 @@ sealed record UcoMethodData
public required string WrapperName { get; init; }

/// <summary>
/// Name of the n_* callback to call, e.g., "n_OnCreate".
/// Java/JNI-visible native method name, e.g., "n_OnCreate".
/// </summary>
public required string CallbackMethodName { get; init; }

Expand All @@ -187,6 +202,53 @@ sealed record UcoMethodData
/// JNI method signature, e.g., "(Landroid/os/Bundle;)V". Used to determine CLR parameter types.
/// </summary>
public required string JniSignature { get; init; }

/// <summary>
/// Optional [Export]-only metadata for wrappers that dispatch directly to the
/// managed export target instead of forwarding to a generated n_* callback.
/// </summary>
public ExportMethodDispatchData? ExportMethodDispatch { get; init; }

/// <summary>
/// True when this wrapper performs the static [Export] direct-dispatch path.
/// </summary>
public bool UsesExportMethodDispatch => ExportMethodDispatch != null;
}

sealed record ExportMethodDispatchData
{
/// <summary>
/// Managed method name on the callback type that should be invoked for [Export].
/// </summary>
public required string ManagedMethodName { get; init; }

/// <summary>
/// Managed parameter types for the target method, including the defining assembly.
/// </summary>
public IReadOnlyList<TypeRefData> ParameterTypes { get; init; } = [];

/// <summary>
/// Per-parameter [ExportParameter] kinds for legacy callback marshalling.
/// </summary>
public IReadOnlyList<ExportParameterKindInfo> ParameterKinds { get; init; } = [];

/// <summary>
/// Managed return type for the target method, including the defining assembly.
/// </summary>
public TypeRefData ReturnType { get; init; } = new () {
ManagedTypeName = "System.Void",
AssemblyName = "System.Runtime",
};

/// <summary>
/// [ExportParameter] kind applied to the return value, if any.
/// </summary>
public ExportParameterKindInfo ReturnKind { get; init; }

/// <summary>
/// Whether the managed target method is static.
/// </summary>
public bool IsStatic { get; init; }
}

/// <summary>
Expand All @@ -211,6 +273,24 @@ sealed record UcoConstructorData
/// JNI constructor signature, e.g., "(Landroid/content/Context;)V". Used for RegisterNatives registration.
/// </summary>
public required string JniSignature { get; init; }

/// <summary>
/// <see langword="true"/> when the UCO codegen can statically prove the managed
/// type defines a matching user-visible ctor with this signature. When
/// <see langword="false"/>, the codegen must use the legacy activation-ctor
/// `(IntPtr, JniHandleOwnership)` path instead of emitting a member ref to
/// a (potentially non-existent) user ctor.
/// </summary>
public required bool HasMatchingManagedCtor { get; init; }

/// <summary>
/// Managed parameter types of the matching user-visible ctor, in declaration
/// order. Empty for `()V`. Non-empty when <see cref="HasMatchingManagedCtor"/>
/// is <see langword="true"/> and the ctor takes parameters; the emitter uses
/// this to build the member ref signature and to marshal each JNI argument
/// to the corresponding managed type before calling the user ctor.
/// </summary>
public IReadOnlyList<TypeRefData> ManagedParameterTypes { get; init; } = [];
}

/// <summary>
Expand Down
Loading