Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to new linker custom steps API #5748

Merged
merged 36 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9c3ffb9
Build locally against new IMarkHandler interface
sbomer Feb 19, 2021
88a3607
Fix up custom steps
sbomer Feb 22, 2021
bac562c
Update to latest interface
sbomer Mar 3, 2021
8fd0cb3
Cleanup
sbomer Mar 3, 2021
ab2949f
Remove unused code under defines
sbomer Mar 3, 2021
cc8a654
Fix whitespace
sbomer Mar 10, 2021
5d8d897
Remove workaround
sbomer Mar 16, 2021
6e941ee
Clean up targets
sbomer Mar 16, 2021
05df054
Don't duplicate MonoDroid.Tuner steps
sbomer Mar 23, 2021
e90b93a
Use LinkContext's type resolve cache
sbomer Apr 27, 2021
3dfe570
Undo TrimmerDefaultAction change
sbomer Apr 27, 2021
d6aaa38
PR feedback
sbomer Apr 28, 2021
41de20f
PR feedback
sbomer Apr 29, 2021
e0c002e
PR feedback
sbomer Apr 30, 2021
f26d8dd
Don't pass --verbose argument
sbomer May 4, 2021
3b616b6
Fix nullref in GenerateProguardConfiguration
sbomer May 7, 2021
cec24b8
Fix RemoveDesigner test
sbomer May 10, 2021
3111a94
Fix typo
sbomer May 10, 2021
b1d9ec7
_CustomStepDll -> _AndroidLinkerCustomStepAssembly
sbomer May 12, 2021
b41545a
Fix code style
sbomer May 18, 2021
5643dfa
Add BaseMarkHandler
sbomer May 18, 2021
20d1ca6
Fix overrides
sbomer May 19, 2021
3a1efaa
Subclass TypeDefinitionCache
sbomer May 19, 2021
6bb719e
Merge remote-tracking branch 'origin/main' into illinkMarkHandler2
sbomer May 25, 2021
1cc2d5a
Implement IMetadataResolver for LinkContextMetadataResolver
sbomer May 25, 2021
67c9593
PR feedback
sbomer May 28, 2021
01b56ec
Fix indentation
jonpryor May 28, 2021
7c70a52
Fix indentation
jonpryor May 28, 2021
6c6d4c8
Fix indentation
jonpryor May 28, 2021
d83a793
Fix indentation
jonpryor May 28, 2021
b13b50c
Add comment for why we're setting _TrimmerDumpDependencies
jonpryor May 28, 2021
8b4c908
Fix indentation
jonpryor May 28, 2021
7501a0c
Merge remote-tracking branch 'origin/main' into illinkMarkHandler2
jonpryor May 28, 2021
bda4b4f
Remove LinkContextMetadataResolver
sbomer May 28, 2021
ff9ea51
Remove reflection workaround
sbomer Jun 2, 2021
742507a
Merge remote-tracking branch 'origin/main' into illinkMarkHandler2
sbomer Jun 2, 2021
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
19 changes: 19 additions & 0 deletions src/Microsoft.Android.Sdk.ILLink/BaseMarkHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Android.Sdk.ILLink;
using Mono.Cecil;
using Mono.Linker.Steps;

namespace Mono.Linker
{
public class BaseMarkHandler : IMarkHandler
{
protected LinkContext Context;
protected AnnotationStore Annotations => Context?.Annotations;
protected IMetadataResolver cache;

public virtual void Initialize (LinkContext context, MarkContext markContext)
{
Context = context;
cache = new LinkContextMetadataResolver (context);
}
}
}
30 changes: 30 additions & 0 deletions src/Microsoft.Android.Sdk.ILLink/LinkContextMetadataResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Java.Interop.Tools.Cecil;
using Mono.Cecil;
using Mono.Linker;

namespace Microsoft.Android.Sdk.ILLink
{
public class LinkContextMetadataResolver : IMetadataResolver {
LinkContext context;

public LinkContextMetadataResolver (LinkContext context)
{
this.context = context;
}

public virtual TypeDefinition Resolve (TypeReference type)
{
return context.ResolveTypeDefinition (type);
}

public virtual FieldDefinition Resolve (FieldReference field)
{
return context.ResolveFieldDefinition (field);
}

public virtual MethodDefinition Resolve (MethodReference method)
{
return context.ResolveMethodDefinition (method);
}
}
}
18 changes: 13 additions & 5 deletions src/Microsoft.Android.Sdk.ILLink/PreserveJavaInterfaces.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
using Mono.Cecil;
using Mono.Linker;
using Mono.Linker.Steps;
using MonoDroid.Tuner;

namespace Microsoft.Android.Sdk.ILLink
{
class PreserveJavaInterfaces : BaseSubStep
class PreserveJavaInterfaces : BaseMarkHandler
{
public override bool IsActiveFor (AssemblyDefinition assembly)
public override void Initialize (LinkContext context, MarkContext markContext)
{
return assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.IJavaObject");
base.Initialize (context, markContext);
markContext.RegisterMarkTypeAction (type => ProcessType (type));
}

public override SubStepTargets Targets { get { return SubStepTargets.Type; } }
bool IsActiveFor (AssemblyDefinition assembly)
{
return assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.IJavaObject");
}

public override void ProcessType (TypeDefinition type)
void ProcessType (TypeDefinition type)
{
if (!IsActiveFor (type.Module.Assembly))
return;

// If we are preserving a Mono.Android interface,
// preserve all members on the interface.
if (!type.IsInterface)
Expand Down
35 changes: 13 additions & 22 deletions src/Microsoft.Android.Sdk.ILLink/PreserveRegistrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,19 @@

namespace Microsoft.Android.Sdk.ILLink
{
class PreserveRegistrations : BaseSubStep
class PreserveRegistrations : BaseMarkHandler
{
delegate void AddPreservedMethodDelegate (AnnotationStore store, MethodDefinition key, MethodDefinition method);

static readonly AddPreservedMethodDelegate addPreservedMethod;

readonly TypeDefinitionCache cache;

public PreserveRegistrations (TypeDefinitionCache cache) => this.cache = cache;

static PreserveRegistrations ()
public override void Initialize (LinkContext context, MarkContext markContext)
{
// temporarily use reflection to get void AnnotationStore::AddPreservedMethod (MethodDefinition key, MethodDefinition method)
// this can be removed once we have newer Microsoft.NET.ILLink containing https://github.com/mono/linker/commit/e6dadc995a834603e1178f9a1918f0ae38056b29
var method = typeof (AnnotationStore).GetMethod ("AddPreservedMethod", new Type [] { typeof (MethodDefinition), typeof (MethodDefinition) });
addPreservedMethod = (AddPreservedMethodDelegate)(method != null ? Delegate.CreateDelegate (typeof (AddPreservedMethodDelegate), null, method, false) : null);
base.Initialize (context, markContext);
markContext.RegisterMarkMethodAction (method => ProcessMethod (method));
}

public override bool IsActiveFor (AssemblyDefinition assembly)
bool IsActiveFor (AssemblyDefinition assembly)
{
return addPreservedMethod != null && (assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.RegisterAttribute"));
return assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.RegisterAttribute");
}

public override SubStepTargets Targets { get { return SubStepTargets.Method; } }

bool PreserveJniMarshalMethods ()
{
if (Context.TryGetCustomData ("XAPreserveJniMarshalMethods", out var boolValue))
Expand Down Expand Up @@ -78,13 +66,16 @@ void PreserveRegisteredMethod (TypeDefinition type, string member, MethodDefinit
type = type.BaseType.Resolve ();
}

public override void ProcessMethod (MethodDefinition method)
void ProcessMethod (MethodDefinition method)
{
if (!IsActiveFor (method.Module.Assembly))
return;

bool preserveJniMarshalMethodOnly = false;
if (!method.TryGetRegisterMember (out var member, out var nativeMethod, out var signature)) {
if (PreserveJniMarshalMethods () &&
method.DeclaringType.GetMarshalMethodsType () != null &&
method.TryGetBaseOrInterfaceRegisterMember (cache, out member, out nativeMethod, out signature)) {
method.DeclaringType.GetMarshalMethodsType () != null &&
method.TryGetBaseOrInterfaceRegisterMember (cache, out member, out nativeMethod, out signature)) {
preserveJniMarshalMethodOnly = true;
} else {
return;
Expand All @@ -105,7 +96,7 @@ public override void ProcessMethod (MethodDefinition method)

void AddPreservedMethod (MethodDefinition key, MethodDefinition method)
{
addPreservedMethod.Invoke (Context.Annotations, key, method);
Annotations.AddPreservedMethod (key, method);
}
}
}
19 changes: 19 additions & 0 deletions src/Microsoft.Android.Sdk.ILLink/PreserveSubStepDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using Mono.Linker.Steps;
using Mono.Tuner;

namespace Microsoft.Android.Sdk.ILLink
{
public class PreserveSubStepDispatcher : MarkSubStepsDispatcher
{
public PreserveSubStepDispatcher ()
: base (new ISubStep[] {
new ApplyPreserveAttribute (),
new PreserveExportedTypes ()
})
{
}
}
}
39 changes: 3 additions & 36 deletions src/Microsoft.Android.Sdk.ILLink/SetupStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,51 +26,18 @@ List<IStep> Steps {
}
}

static MethodInfo getReferencedAssembliesMethod = typeof (LinkContext).GetMethod ("GetReferencedAssemblies", BindingFlags.Public | BindingFlags.Instance);

protected override void Process ()
{
string tfmPaths;
if (Context.TryGetCustomData ("XATargetFrameworkDirectories", out tfmPaths))
if (Context.TryGetCustomData ("XATargetFrameworkDirectories", out string tfmPaths))
Xamarin.Android.Tasks.MonoAndroidHelper.TargetFrameworkDirectories = tfmPaths.Split (new char [] { ';' });

var subSteps1 = new SubStepDispatcher ();
subSteps1.Add (new ApplyPreserveAttribute ());

var cache = new TypeDefinitionCache ();
var subSteps2 = new SubStepDispatcher ();
subSteps2.Add (new PreserveExportedTypes ());
subSteps2.Add (new MarkJavaObjects ());
subSteps2.Add (new PreserveJavaExceptions ());
subSteps2.Add (new PreserveApplications ());
subSteps2.Add (new PreserveRegistrations (cache));
subSteps2.Add (new PreserveJavaInterfaces ());

InsertAfter (new FixAbstractMethodsStep (cache), "SetupStep");
InsertAfter (subSteps2, "SetupStep");
InsertAfter (subSteps1, "SetupStep");

// temporary workaround: this call forces illink to process all the assemblies
if (getReferencedAssembliesMethod == null)
throw new InvalidOperationException ($"Temporary linker workaround failed, {nameof (getReferencedAssembliesMethod)} is null.");

foreach (var assembly in (IEnumerable<AssemblyDefinition>)getReferencedAssembliesMethod.Invoke (Context, null))
Context.LogMessage ($"Reference assembly to process: {assembly}");

string proguardPath;
if (Context.TryGetCustomData ("ProguardConfiguration", out proguardPath))
InsertAfter (new GenerateProguardConfiguration (proguardPath), "CleanStep");

string addKeepAlivesStep;
if (Context.TryGetCustomData ("AddKeepAlivesStep", out addKeepAlivesStep) && bool.TryParse (addKeepAlivesStep, out var bv) && bv)
InsertAfter (new AddKeepAlivesStep (cache), "CleanStep");

// The following steps share state and must be injected via reflection until we get
// a linker with the fix from https://github.com/mono/linker/pull/2019.
string androidLinkResources;
if (Context.TryGetCustomData ("AndroidLinkResources", out androidLinkResources) && bool.TryParse (androidLinkResources, out var linkResources) && linkResources) {
InsertAfter (new RemoveResourceDesignerStep (), "CleanStep");
InsertAfter (new GetAssembliesStep (), "CleanStep");
}
InsertAfter (new StripEmbeddedLibraries (), "CleanStep");
}

void InsertAfter (IStep step, string stepName)
Expand Down
10 changes: 0 additions & 10 deletions src/Microsoft.Android.Sdk.ILLink/SubStepDispatcher.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@
using Mono.Linker.Steps;

using Mono.Cecil.Cil;
#if NET5_LINKER
using Microsoft.Android.Sdk.ILLink;
#endif // NET5_LINKER

namespace MonoDroid.Tuner
{
public class AddKeepAlivesStep : BaseStep
{
readonly TypeDefinitionCache cache;

public AddKeepAlivesStep (TypeDefinitionCache cache)
#if NET5_LINKER
protected override void Process ()
{
cache = new LinkContextMetadataResolver (Context);
}
#else // !NET5_LINKER
public AddKeepAlivesStep (IMetadataResolver cache)
{
this.cache = cache;
}

readonly
#endif // !NET5_LINKER
IMetadataResolver cache;

protected override void ProcessAssembly (AssemblyDefinition assembly)
{
var action = Annotations.HasAction (assembly) ? Annotations.GetAction (assembly) : AssemblyAction.Skip;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@

using Mono.Cecil;

#if NET5_LINKER
using Microsoft.Android.Sdk.ILLink;
#endif

namespace MonoDroid.Tuner {

public class ApplyPreserveAttribute : ApplyPreserveAttributeBase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public static TypeDefinition GetMarshalMethodsType (this TypeDefinition type)
return null;
}

public static bool TryGetBaseOrInterfaceRegisterMember (this MethodDefinition method, TypeDefinitionCache cache, out string member, out string nativeMethod, out string signature)
public static bool TryGetBaseOrInterfaceRegisterMember (this MethodDefinition method, IMetadataResolver resolver, out string member, out string nativeMethod, out string signature)
{
var type = method.DeclaringType;

Expand All @@ -264,45 +264,45 @@ public static bool TryGetBaseOrInterfaceRegisterMember (this MethodDefinition me
if (method.IsConstructor || type == null || !type.HasNestedTypes)
return false;

var m = method.GetBaseDefinition (cache);
var m = method.GetBaseDefinition (resolver);

while (m != null) {
if (m == method)
break;
break;

method = m;

if (m.TryGetRegisterMember (out member, out nativeMethod, out signature))
return true;

m = m.GetBaseDefinition (cache);
m = m.GetBaseDefinition (resolver);
}

if (!method.DeclaringType.HasInterfaces || !method.IsNewSlot)
return false;

foreach (var iface in method.DeclaringType.Interfaces) {
if (iface.InterfaceType.IsGenericInstance)
continue;
continue;

var itype = iface.InterfaceType.Resolve ();
if (itype == null || !itype.HasMethods)
continue;

foreach (var im in itype.Methods)
if (im.IsEqual (method, cache))
if (im.IsEqual (method, resolver))
return im.TryGetRegisterMember (out member, out nativeMethod, out signature);
}
}

return false;
return false;
}

public static bool IsEqual (this MethodDefinition m1, MethodDefinition m2, TypeDefinitionCache cache)
public static bool IsEqual (this MethodDefinition m1, MethodDefinition m2, IMetadataResolver resolver)
{
if (m1.Name != m2.Name || m1.ReturnType.Name != m2.ReturnType.Name)
return false;

return m1.Parameters.AreParametersCompatibleWith (m2.Parameters, cache);
return m1.Parameters.AreParametersCompatibleWith (m2.Parameters, resolver);
}

public static bool TryGetMarshalMethod (this MethodDefinition method, string nativeMethod, string signature, out MethodDefinition marshalMethod)
Expand Down
Loading