Skip to content
Open
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
d9dfce0
Add trimmable [Export] callback support
simonrozsival Apr 13, 2026
22d6b11
Refactor [Export] code generation
simonrozsival Apr 13, 2026
6b69c63
Exclude Mono.Android.Export from trimmable packages
simonrozsival Apr 13, 2026
9e92791
Refine export method dispatch model
simonrozsival Apr 13, 2026
2c8dae7
Scope export method dispatch emission
simonrozsival Apr 13, 2026
ce1aa36
Tighten trimmable export cleanup
simonrozsival Apr 13, 2026
f6232bb
Propagate deferred registerNatives to base classes and fix test plumbing
simonrozsival Apr 13, 2026
67ecfbd
Remove unrelated changes: revert test plumbing, CI lane, and manifest…
simonrozsival Apr 16, 2026
a0e5e30
Revert whitespace-only changes and restore EmitRegisterNatives position
simonrozsival Apr 16, 2026
f2aa14e
Fix stack corruption in TryEmitExportParameterArgument
simonrozsival Apr 16, 2026
c6fe56d
Revert MonoAndroidExportTest changes that force trimmable typemap
simonrozsival Apr 17, 2026
d0acd52
Fix instrumentation targetPackage default
simonrozsival Apr 18, 2026
88ca58f
Fix missing 'static' keyword in Java codegen for static [Export] methods
simonrozsival Apr 21, 2026
430d5e3
Address review: perf optimization + code organization
simonrozsival Apr 21, 2026
c4aac55
Fix test: TypeMapAssociationAttribute is no longer generic
simonrozsival Apr 22, 2026
d8dc37f
Remove dead ManagedParameterTypeNames/ManagedReturnTypeName propertie…
simonrozsival Apr 22, 2026
80b2986
Fix test: TypeMapAssociationAttribute is generic (TypeMapAssociationA…
simonrozsival Apr 26, 2026
e6b38e1
Restore ExcludedTestNames for trimmable typemap tests
simonrozsival Apr 26, 2026
ffb5093
Trimmable typemap: invoke user-visible parameterless ctor in UCO wrap…
simonrozsival Apr 26, 2026
308a961
Fix bad-rebase artifacts: restore CI lane and submodule SHA
simonrozsival Apr 27, 2026
85e0b65
Reduce diff churn against base
simonrozsival Apr 27, 2026
f136461
Drop unnecessary Java_mono_android_Runtime_registerNatives JNI export
simonrozsival Apr 27, 2026
d49ba61
Move EmitRegisterNatives + AddUnmanagedCallersOnlyAttribute back to o…
simonrozsival Apr 27, 2026
586eeda
Clean up UCO ctor comment: drop test-specific detail, point at the sa…
simonrozsival Apr 27, 2026
e5c7810
Address review feedback: lazy export emitter, hoist deferred check, d…
simonrozsival Apr 27, 2026
deb6874
Add device tests for parameterized ctor activation contract
simonrozsival Apr 27, 2026
4aaf705
Redesign parameterized ctor activation tests around Throwable args
simonrozsival Apr 27, 2026
c1cc2b6
[trimmable typemap] Gate user-ctor UCO emission on matching managed .…
simonrozsival Apr 27, 2026
5d623bf
[trimmable typemap] Forward JNI args to user-visible parameterized .ctor
simonrozsival Apr 27, 2026
f438f1f
[trimmable typemap] Simplify ManagedParameterTypes plumbing
simonrozsival Apr 27, 2026
1f6ffbf
[trimmable typemap] Extract user-visible ctor wrapper emission helper
simonrozsival Apr 27, 2026
07b14f9
Reuse export primitive marshalling for parameterized UCO ctor args
simonrozsival Apr 27, 2026
71317c0
Add Mono.Android.NET-Tests device coverage for [Export] marshalling
simonrozsival Apr 27, 2026
bca9cd1
Wrap [Export] UCO methods with OnUserUnhandledException routing
simonrozsival Apr 27, 2026
27dfe39
Skip parameterized [Export] ctors with unsupported types
simonrozsival Apr 27, 2026
c6c8ea6
Update [Export] throws tests for OnUserUnhandledException semantics
simonrozsival Apr 27, 2026
8835615
Marshal enum [Export] params/returns via underlying primitive JNI ABI
simonrozsival Apr 27, 2026
82dc863
Marshal ICharSequence and non-generic collection [Export] returns via…
simonrozsival Apr 27, 2026
e5767fa
Update export-comparison.md to reflect Phase 1 marshalling parity work
simonrozsival Apr 27, 2026
e06d2d2
Make enum scanner resolution assembly-aware and resilient to FQN coll…
simonrozsival Apr 27, 2026
372c1ac
Simplify enum scanner helpers in JavaPeerScanner
simonrozsival Apr 27, 2026
9292fc6
Remove export-comparison.md — analysis doc not intended for merge
simonrozsival Apr 27, 2026
ef712f0
Add scanner integration coverage for advanced [Export] shapes
simonrozsival Apr 27, 2026
f1272b9
Scanner integration: cover [ExportField] and [ExportParameter]; fix u…
simonrozsival Apr 27, 2026
f577304
Phase A scanner coverage: dispatch & declaration shapes
simonrozsival Apr 27, 2026
fb8ed6c
Phase B scanner coverage: edge marshalling shapes
simonrozsival Apr 27, 2026
e2a45df
Phase C scanner coverage: robustness shapes
simonrozsival Apr 27, 2026
16382c2
Fix trimmable export rebase fallout
simonrozsival May 5, 2026
a730499
Merge branch 'main' into dev/simonrozsival/trimmable-typemap-export-a…
Copilot May 6, 2026
2d76be1
Merge remote-tracking branch 'origin/main' into dev/simonrozsival/tri…
simonrozsival May 7, 2026
424eb11
Merge main into dev/simonrozsival/trimmable-typemap-export-attribute …
simonrozsival May 9, 2026
fbef8ee
Merge main into dev/simonrozsival/trimmable-typemap-export-attribute …
simonrozsival May 9, 2026
3507f3e
Surface diagnostic for silent user-ctor fallback in trimmable typemap
simonrozsival May 11, 2026
11c95d2
Add scanner regression tests for HasMatchingManagedCtor + CtorFallbac…
simonrozsival May 11, 2026
7f1c2ae
Phase D integration: [Export] on a [Register]'d interface implementor
simonrozsival May 11, 2026
fcbf35f
Build-task coverage: trimmable [Export]/[ExportField] artifacts + tri…
simonrozsival May 11, 2026
399ed83
Device tests for nested + re-entrant exception routing through [Export]
simonrozsival May 11, 2026
a6017e4
fixup! Build-task coverage: match generated JCW Java by content not f…
simonrozsival May 11, 2026
fee4ce4
Release notes: document trimmable [Export]/[ExportField] support + Mo…
simonrozsival May 11, 2026
0cfb95b
Merge branch 'dev/simonrozsival/trimmable-typemap-export-attribute' o…
simonrozsival May 12, 2026
bc07d98
Merge origin/main into trimmable typemap export
simonrozsival May 12, 2026
37e10d4
Simplify tracked IL emission
simonrozsival May 12, 2026
cbcb4b5
Reject generic export signatures
simonrozsival May 12, 2026
b0f8cb2
Fix CI: JcwJavaSourceGenerator [ExportField] method generation and mi…
simonrozsival May 12, 2026
d93063f
Fix trim warning test: exclude IL2026 about ExportAttribute's Require…
simonrozsival May 13, 2026
b1b94b6
Exclude Export tests from non-trimmable device test configs
simonrozsival May 13, 2026
243f5fa
Revert "Exclude Export tests from non-trimmable device test configs"
simonrozsival May 13, 2026
da27f9d
Fix device test crash: preserve GetObject from trimming for Mono.Andr…
simonrozsival May 13, 2026
815956b
Address review feedback: remove null-forgiving operator, fix formatti…
simonrozsival May 13, 2026
c6751b8
Merge origin/main into trimmable typemap export
simonrozsival May 13, 2026
0c3997d
Remove trimmable typemap release note
simonrozsival May 13, 2026
490d3d3
Clarify trimmable typemap UCO pseudo-code
simonrozsival May 13, 2026
dc1dcd3
Merge remote-tracking branch 'origin/main' into dev/simonrozsival/tri…
simonrozsival May 13, 2026
1b46e24
Address trimmable typemap review feedback
simonrozsival May 13, 2026
8d90b39
Fix inherited activation CreateInstance regression
simonrozsival May 14, 2026
27b9ce2
Keep CRC64 normalization conflict resolution surgical
simonrozsival May 14, 2026
3a72501
Minimize trimmable typemap emitter changes
simonrozsival May 14, 2026
c31afdc
Remove constructor fallback diagnostics
simonrozsival May 14, 2026
ee61095
Simplify constructor argument marshalling
simonrozsival May 14, 2026
b239ba3
Clean up trimmable export PR diff
simonrozsival May 14, 2026
d42e1eb
Reduce trimmable test assembly roots
simonrozsival May 14, 2026
00bb8a2
Reduce runtime test project churn
simonrozsival May 14, 2026
4e69074
Address trimmable export review feedback
simonrozsival May 14, 2026
5d1a968
Reduce trimmable scanner churn
simonrozsival May 14, 2026
f14ac09
Remove manifest rewrite churn
simonrozsival May 14, 2026
f42f09b
Remove unused TrimmableIgnore category
simonrozsival May 14, 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 @@ -249,7 +249,7 @@ static void WriteMethods (JavaPeerInfo type, TextWriter writer)
throwsClause = $"\n\t\tthrows {string.Join (", ", method.ThrownNames)}";
}

if (method.Connector != null) {
if (method.Connector != null && !method.IsExport) {
writer.Write ($$"""

@Override
Expand All @@ -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 @@ -142,6 +142,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 @@ -166,7 +173,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 @@ -177,11 +184,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 @@ -191,7 +206,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 @@ -205,6 +220,52 @@ sealed record UcoMethodData
/// </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 @@ -231,14 +292,22 @@ sealed record UcoConstructorData
public required string JniSignature { get; init; }

/// <summary>
/// Managed constructor parameter type names, in declaration order.
/// <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 IReadOnlyList<string> ManagedParameterTypes { get; init; } = [];
public required bool HasMatchingManagedCtor { get; init; }

/// <summary>
/// True when this Java constructor has a matching managed constructor on the target type.
/// 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 bool HasManagedConstructor { get; init; }
public IReadOnlyList<TypeRefData> ManagedParameterTypes { get; init; } = [];
}

/// <summary>
Expand Down
Loading