diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index 296e35c0e754..1ebf7deb2e2d 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -632,6 +632,9 @@
<_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --enable-serialization-discovery
+
+ <_ExtraTrimmerArgs Condition="'$(_UseNativeAot)' == 'true'">$(_ExtraTrimmerArgs) --keep-dep-attributes
+
false
diff --git a/tools/common/ErrorHelper.tools.cs b/tools/common/ErrorHelper.tools.cs
index 8f564d565f35..2b0f0e46cd47 100644
--- a/tools/common/ErrorHelper.tools.cs
+++ b/tools/common/ErrorHelper.tools.cs
@@ -332,7 +332,8 @@ static void ShowInner (Exception e)
if (Verbosity > 3) {
Console.Error.WriteLine ("--- inner exception");
- Console.Error.WriteLine (ie);
+ Console.Error.WriteLine (ie.Message);
+ Console.Error.WriteLine (ie.StackTrace);
Console.Error.WriteLine ("---");
} else if (Verbosity > 0 || ie is ProductException) {
Console.Error.WriteLine ("\t{0}", ie.Message);
diff --git a/tools/create-dotnet-linker-launch-json/create-dotnet-linker-launch-json.csproj b/tools/create-dotnet-linker-launch-json/create-dotnet-linker-launch-json.csproj
index 7a25f66db1fa..8ddd2b65b3ab 100644
--- a/tools/create-dotnet-linker-launch-json/create-dotnet-linker-launch-json.csproj
+++ b/tools/create-dotnet-linker-launch-json/create-dotnet-linker-launch-json.csproj
@@ -2,14 +2,14 @@
Exe
- net7.0
+ net8.0
create_dotnet_linker_launch_json
enable
enable
-
+
diff --git a/tools/dotnet-linker/AppBundleRewriter.cs b/tools/dotnet-linker/AppBundleRewriter.cs
index ae5ad1e0ad1a..322a826b0f39 100644
--- a/tools/dotnet-linker/AppBundleRewriter.cs
+++ b/tools/dotnet-linker/AppBundleRewriter.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Mono.Cecil;
@@ -126,6 +127,10 @@ public MethodReference GetMethodReference (AssemblyDefinition assembly, TypeRefe
md.IsPublic = true;
SaveAssembly (md.Module.Assembly);
}
+
+ // Also mark it
+ // configuration.Context.Annotations.Mark (md);
+ // configuration.Context.Annotations.Mark (tuple.Item2);
}
method = tuple.Item1;
@@ -309,6 +314,12 @@ public TypeReference System_Diagnostics_CodeAnalysis_DynamicDependencyAttribute
}
}
+ public TypeReference System_Diagnostics_CodeAnalysis_DynamicallyAccessedMemberTypes {
+ get {
+ return GetTypeReference (CorlibAssembly, "System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes", out var _);
+ }
+ }
+
public TypeReference System_Reflection_MethodBase {
get {
return GetTypeReference (CorlibAssembly, "System.Reflection.MethodBase", out var _);
@@ -461,17 +472,41 @@ public MethodReference Dictionary2_Add {
}
}
+ public MethodReference DynamicDependencyAttribute_ctor__String {
+ get {
+ return GetMethodReference (CorlibAssembly,
+ System_Diagnostics_CodeAnalysis_DynamicDependencyAttribute,
+ ".ctor",
+ ".ctor(String)",
+ isStatic: false,
+ System_String);
+ }
+ }
+
public MethodReference DynamicDependencyAttribute_ctor__String_Type {
get {
return GetMethodReference (CorlibAssembly,
System_Diagnostics_CodeAnalysis_DynamicDependencyAttribute,
".ctor",
+ ".ctor(String,Type)",
isStatic: false,
System_String,
System_Type);
}
}
+ public MethodReference DynamicDependencyAttribute_ctor__DynamicallyAccessedMemberTypes_Type {
+ get {
+ return GetMethodReference (CorlibAssembly,
+ System_Diagnostics_CodeAnalysis_DynamicDependencyAttribute,
+ ".ctor",
+ ".ctor(DynamicallyAccessedMemberTypes,Type)",
+ isStatic: false,
+ System_Diagnostics_CodeAnalysis_DynamicallyAccessedMemberTypes,
+ System_Type);
+ }
+ }
+
public MethodReference RuntimeTypeHandle_Equals {
get {
return GetMethodReference (CorlibAssembly, System_RuntimeTypeHandle, "Equals", isStatic: false, System_RuntimeTypeHandle);
@@ -1147,5 +1182,29 @@ public void ClearCurrentAssembly ()
method_map.Clear ();
field_map.Clear ();
}
+
+ public CustomAttribute CreateDynamicDependencyAttribute (string memberSignature)
+ {
+ var attribute = new CustomAttribute (DynamicDependencyAttribute_ctor__String);
+ attribute.ConstructorArguments.Add (new CustomAttributeArgument (System_String, memberSignature));
+ return attribute;
+ }
+
+ public CustomAttribute CreateDynamicDependencyAttribute (string memberSignature, TypeDefinition type)
+ {
+ var attribute = new CustomAttribute (DynamicDependencyAttribute_ctor__String_Type);
+ attribute.ConstructorArguments.Add (new CustomAttributeArgument (System_String, memberSignature));
+ attribute.ConstructorArguments.Add (new CustomAttributeArgument (System_Type, type));
+ return attribute;
+ }
+
+ public CustomAttribute CreateDynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, TypeDefinition type)
+ {
+ var attribute = new CustomAttribute (DynamicDependencyAttribute_ctor__DynamicallyAccessedMemberTypes_Type);
+ // typed as 'int' because that's how the linker expects it: https://github.com/dotnet/runtime/blob/3c5ad6c677b4a3d12bc6a776d654558cca2c36a9/src/tools/illink/src/linker/Linker/DynamicDependency.cs#L97
+ attribute.ConstructorArguments.Add (new CustomAttributeArgument (System_Diagnostics_CodeAnalysis_DynamicallyAccessedMemberTypes, (int) memberTypes));
+ attribute.ConstructorArguments.Add (new CustomAttributeArgument (System_Type, type));
+ return attribute;
+ }
}
}
diff --git a/tools/dotnet-linker/ApplyPreserveAttributeBase.cs b/tools/dotnet-linker/ApplyPreserveAttributeBase.cs
index f030e446ca4e..2f2417f6c67d 100644
--- a/tools/dotnet-linker/ApplyPreserveAttributeBase.cs
+++ b/tools/dotnet-linker/ApplyPreserveAttributeBase.cs
@@ -3,18 +3,30 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Text;
using Mono.Linker;
using Mono.Linker.Steps;
using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Bundler;
+using Xamarin.Linker;
#nullable enable
namespace Mono.Tuner {
- public abstract class ApplyPreserveAttributeBase : BaseSubStep {
+ public abstract class ApplyPreserveAttributeBase : ConfigurationAwareSubStep {
+
+ AppBundleRewriter? abr;
+
+ protected override string Name { get => "ApplyPreserveAttribute"; }
+
+ protected override int ErrorCode { get => 2450; }
// set 'removeAttribute' to true if you want the preserved attribute to be removed from the final assembly
protected abstract bool IsPreservedAttribute (ICustomAttributeProvider provider, CustomAttribute attribute, out bool removeAttribute);
@@ -30,28 +42,36 @@ public override SubStepTargets Targets {
}
}
+ public override void Initialize (LinkContext context)
+ {
+ base.Initialize (context);
+
+ if (Configuration.Application.XamarinRuntime == XamarinRuntime.NativeAOT)
+ abr = Configuration.AppBundleRewriter;
+ }
+
public override bool IsActiveFor (AssemblyDefinition assembly)
{
return Annotations.GetAction (assembly) == AssemblyAction.Link;
}
- public override void ProcessType (TypeDefinition type)
+ protected override void Process (TypeDefinition type)
{
TryApplyPreserveAttribute (type);
}
- public override void ProcessField (FieldDefinition field)
+ protected override void Process (FieldDefinition field)
{
foreach (var attribute in GetPreserveAttributes (field))
Mark (field, attribute);
}
- public override void ProcessMethod (MethodDefinition method)
+ protected override void Process (MethodDefinition method)
{
MarkMethodIfPreserved (method);
}
- public override void ProcessProperty (PropertyDefinition property)
+ protected override void Process (PropertyDefinition property)
{
foreach (var attribute in GetPreserveAttributes (property)) {
MarkMethod (property.GetMethod, attribute);
@@ -59,7 +79,7 @@ public override void ProcessProperty (PropertyDefinition property)
}
}
- public override void ProcessEvent (EventDefinition @event)
+ protected override void Process (EventDefinition @event)
{
foreach (var attribute in GetPreserveAttributes (@event)) {
MarkMethod (@event.AddMethod, attribute);
@@ -103,6 +123,7 @@ void PreserveConditional (IMetadataTokenProvider provider)
}
Annotations.AddPreservedMethod (method.DeclaringType, method);
+ AddDynamicDependencyAttribute (method.DeclaringType, method);
}
static bool IsConditionalAttribute (CustomAttribute? attribute)
@@ -120,6 +141,7 @@ static bool IsConditionalAttribute (CustomAttribute? attribute)
void PreserveUnconditional (IMetadataTokenProvider provider)
{
Annotations.Mark (provider);
+ AddDynamicDependencyAttribute (provider);
var member = provider as IMemberDefinition;
if (member is null || member.DeclaringType is null)
@@ -131,14 +153,7 @@ void PreserveUnconditional (IMetadataTokenProvider provider)
void TryApplyPreserveAttribute (TypeDefinition type)
{
foreach (var attribute in GetPreserveAttributes (type)) {
- Annotations.Mark (type);
-
- if (!attribute.HasFields)
- continue;
-
- foreach (var named_argument in attribute.Fields)
- if (named_argument.Name == "AllMembers" && (bool) named_argument.Argument.Value)
- Annotations.SetPreserve (type, TypePreserve.All);
+ PreserveType (type, attribute);
}
}
@@ -165,5 +180,184 @@ List GetPreserveAttributes (ICustomAttributeProvider provider)
return attrs;
}
+
+ protected void PreserveType (TypeDefinition type, CustomAttribute preserveAttribute)
+ {
+ var allMembers = false;
+ if (preserveAttribute.HasFields) {
+ foreach (var named_argument in preserveAttribute.Fields)
+ if (named_argument.Name == "AllMembers" && (bool) named_argument.Argument.Value)
+ allMembers = true;
+ }
+
+ PreserveType (type, allMembers);
+ }
+
+ protected void PreserveType (TypeDefinition type, bool allMembers)
+ {
+ Annotations.Mark (type);
+ if (allMembers)
+ Annotations.SetPreserve (type, TypePreserve.All);
+ AddDynamicDependencyAttribute (type, allMembers);
+ }
+
+ ModuleDefinition GetModule (IMetadataTokenProvider provider)
+ {
+ if (provider is TypeDefinition td)
+ return td.Module;
+
+ if (provider is IMemberDefinition md)
+ return md.DeclaringType.Module;
+
+ throw new NotImplementedException (provider.GetType ().FullName);
+ }
+
+ MethodDefinition GetModuleConstructor (IMetadataTokenProvider provider)
+ {
+ return GetModuleConstructor (GetModule (provider));
+ }
+
+ MethodDefinition GetModuleConstructor (ModuleDefinition @module)
+ {
+ var moduleType = @module.Types.SingleOrDefault (v => v.Name == "");
+ if (moduleType is null)
+ throw ErrorHelper.CreateError (99, $"No type found in {@module.Name}");
+ var moduleConstructor = moduleType.GetTypeConstructor ();
+ if (moduleConstructor is null) {
+ moduleConstructor = moduleType.AddMethod (".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.Static, abr!.System_Void);
+ moduleConstructor.CreateBody (out var il);
+ il.Emit (OpCodes.Ret);
+ }
+ return moduleConstructor;
+ }
+
+ void AddDynamicDependencyAttribute (TypeDefinition type, bool allMembers)
+ {
+ if (abr is null)
+ return;
+
+ abr.ClearCurrentAssembly ();
+ abr.SetCurrentAssembly (type.Module.Assembly);
+
+ var moduleConstructor = GetModuleConstructor (type);
+ var attrib = abr.CreateDynamicDependencyAttribute (allMembers ? DynamicallyAccessedMemberTypes.All : DynamicallyAccessedMemberTypes.None, type);
+ moduleConstructor.CustomAttributes.Add (attrib);
+ Console.WriteLine ($"Added dynamic dependency attribute to module constructor (allMembers: {allMembers}) for: {type} in {type.Module.Assembly.Name}");
+
+ abr.ClearCurrentAssembly ();
+ }
+
+ void AddDynamicDependencyAttribute (TypeDefinition onType, MethodDefinition forMethod)
+ {
+ if (abr is null)
+ return;
+
+ abr.ClearCurrentAssembly ();
+ abr.SetCurrentAssembly (onType.Module.Assembly);
+
+ Console.WriteLine ($"Unable to add dependency from the type {onType.FullName} to its member {forMethod.FullName}");
+
+ abr.ClearCurrentAssembly ();
+ }
+
+ void AddDynamicDependencyAttribute (IMetadataTokenProvider provider)
+ {
+ if (abr is null)
+ return;
+
+ var member = provider as IMemberDefinition;
+ if (member is null) {
+ Console.WriteLine ("Huh?");
+ return;
+ }
+
+ abr.ClearCurrentAssembly ();
+ abr.SetCurrentAssembly (GetModule (member).Assembly);
+
+ var moduleConstructor = GetModuleConstructor (member);
+ var signature = GetSignature (member, false);
+ var attrib = abr.CreateDynamicDependencyAttribute (signature, member.DeclaringType);
+ moduleConstructor.CustomAttributes.Add (attrib);
+ Console.WriteLine ($"Added dynamic dependency attribute to module constructor for: {member}");
+
+ abr.ClearCurrentAssembly ();
+ }
+
+ // signature format: https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d42-id-string-format
+ string GetSignature (IMetadataTokenProvider member, bool withType)
+ {
+ if (member is FieldDefinition fd) {
+ var signature = GetSignature (fd);
+ if (withType)
+ return GetSignature (fd.DeclaringType) + "." + signature;
+ return signature;
+ }
+
+ if (member is MethodDefinition md) {
+ var signature = GetSignature (md);
+ if (withType)
+ return GetSignature (md.DeclaringType) + "." + signature;
+ return signature;
+ }
+
+ if (member is TypeDefinition td)
+ return GetSignature (td);
+
+ throw new NotImplementedException (member.GetType ().FullName);
+ }
+
+ string GetSignature (TypeDefinition type)
+ {
+ if (type.IsNested)
+ return type.Name;
+ return type.FullName;
+ }
+
+ string GetSignature (FieldDefinition field)
+ {
+ return field.Name.Replace ('.', '#');
+ }
+
+ string GetSignature (MethodDefinition method)
+ {
+ var sb = new StringBuilder ();
+ sb.Append (method.Name.Replace ('.', '#'));
+ sb.Append ('(');
+ for (var i = 0; i < method.Parameters.Count; i++) {
+ if (i > 0)
+ sb.Append (',');
+
+ var parameterType = method.Parameters [i].ParameterType;
+ WriteTypeSignature (sb, parameterType);
+ }
+ sb.Append (')');
+
+ Console.WriteLine ($"Created signature '{sb}' for {method.FullName}");
+
+ return sb.ToString ();
+ }
+
+ void WriteTypeSignature (StringBuilder sb, TypeReference type)
+ {
+ if (type is ByReferenceType brt) {
+ WriteTypeSignature (sb, brt.GetElementType ());
+ sb.Append ('@');
+ return;
+ }
+
+ if (type is ArrayType at) {
+ WriteTypeSignature (sb, at.GetElementType ());
+ sb.Append ("[]");
+ return;
+ }
+
+ if (type is PointerType pt) {
+ WriteTypeSignature (sb, pt.GetElementType ());
+ sb.Append ('*');
+ return;
+ }
+
+ sb.Append (type.FullName.Replace ('/', '.'));
+ }
}
}
diff --git a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
index 03d0d81500f1..d262e3b5b373 100644
--- a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
+++ b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
@@ -292,7 +292,7 @@ void CreateUnmanagedCallersMethod (MethodDefinition method, AssemblyTrampolineIn
infos.Add (new TrampolineInfo (callback, method, name));
// If the target method is marked, then we must mark the trampoline as well.
- method.CustomAttributes.Add (CreateDynamicDependencyAttribute (callbackType, callback.Name));
+ method.CustomAttributes.Add (abr.CreateDynamicDependencyAttribute (callback.Name, callbackType));
callback.AddParameter ("pobj", abr.System_IntPtr);
@@ -1122,14 +1122,6 @@ CustomAttribute CreateUnmanagedCallersAttribute (string entryPoint)
return unmanagedCallersAttribute;
}
- CustomAttribute CreateDynamicDependencyAttribute (TypeDefinition type, string member)
- {
- var attribute = new CustomAttribute (abr.DynamicDependencyAttribute_ctor__String_Type);
- attribute.ConstructorArguments.Add (new CustomAttributeArgument (abr.System_String, member));
- attribute.ConstructorArguments.Add (new CustomAttributeArgument (abr.System_Type, type));
- return attribute;
- }
-
void GenerateConversionToManaged (MethodDefinition method, ILProcessor il, TypeReference inputType, TypeReference outputType, string descriptiveMethodName, int parameter, out TypeReference nativeCallerType)
{
// This is a mirror of the native method xamarin_generate_conversion_to_managed (for the dynamic registrar).
diff --git a/tools/linker/ApplyPreserveAttribute.cs b/tools/linker/ApplyPreserveAttribute.cs
index a04c36ab5e97..d2ea827ff674 100644
--- a/tools/linker/ApplyPreserveAttribute.cs
+++ b/tools/linker/ApplyPreserveAttribute.cs
@@ -27,8 +27,9 @@ public override bool IsActiveFor (AssemblyDefinition assembly)
}
#if NET
- public override void ProcessAssembly (AssemblyDefinition assembly)
+ protected override void Process (AssemblyDefinition assembly)
{
+ base.Process (assembly);
ProcessAssemblyAttributes (assembly);
}
#else
@@ -62,6 +63,10 @@ void ProcessAssemblyAttributes (AssemblyDefinition assembly)
// (a) we're potentially processing a different assembly and `is_active` represent the current one
// (b) it will try to fetch the [Preserve] attribute on the type (and it's not there) as `base` would
var type = tr.Resolve ();
+
+#if NET
+ PreserveType (type, attribute);
+#else
Annotations.Mark (type);
if (attribute.HasFields) {
foreach (var named_argument in attribute.Fields) {
@@ -69,6 +74,7 @@ void ProcessAssemblyAttributes (AssemblyDefinition assembly)
Annotations.SetPreserve (type, TypePreserve.All);
}
}
+#endif
// In .NET6, ApplyPreserveAttribute no longer runs on all assemblies.
// [assembly: Preserve (typeof (SomeAttribute))] no longer gives SomeAttribute "Preserve" semantics.