From a4797cf6862fd4d21a436d49426960dc5f610406 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 1 Jul 2026 23:55:44 +0200 Subject: [PATCH] [dotnet-linker] Set AssociatedSourceType on UnmanagedCallersOnly trampolines Set the AssociatedSourceType property on UnmanagedCallersOnly attributes generated by the managed registrar step. This tells the trimmer/NativeAOT that the trampoline entry point is only needed if the associated type (the NSObject subclass declaring the exported method) is kept in the app. This reduces app size in NativeAOT scenarios by avoiding unnecessary native exports for trimmed types. Fixes https://github.com/dotnet/macios/issues/25631 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- tools/dotnet-linker/Steps/ManagedRegistrarStep.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs index 9f737f9cc4b..195ac106827 100644 --- a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs +++ b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs @@ -390,7 +390,7 @@ void CreateUnmanagedCallersMethod (MethodDefinition method, AssemblyTrampolineIn } var callback = callbackType.AddMethod (name, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, placeholderType); - callback.CustomAttributes.Add (CreateUnmanagedCallersAttribute (name)); + callback.CustomAttributes.Add (CreateUnmanagedCallersAttribute (name, method.DeclaringType)); infos.Add (new TrampolineInfo (callback, method, name)); // If the target method is marked, then we must mark the trampoline as well. @@ -1242,10 +1242,12 @@ StaticRegistrar StaticRegistrar { get { return DerivedLinkContext.StaticRegistrar; } } - CustomAttribute CreateUnmanagedCallersAttribute (string entryPoint) + CustomAttribute CreateUnmanagedCallersAttribute (string entryPoint, TypeReference? associatedSourceType = null) { var unmanagedCallersAttribute = new CustomAttribute (abr.UnmanagedCallersOnlyAttribute_Constructor); unmanagedCallersAttribute.Fields.Add (new CustomAttributeNamedArgument ("EntryPoint", new CustomAttributeArgument (abr.System_String, entryPoint))); + if (associatedSourceType is not null) + unmanagedCallersAttribute.Fields.Add (new CustomAttributeNamedArgument ("AssociatedSourceType", new CustomAttributeArgument (abr.System_Type, associatedSourceType))); return unmanagedCallersAttribute; }