From 5daf1027666098ef43e21d7692daf1513024819e Mon Sep 17 00:00:00 2001 From: Peter Collins Date: Thu, 9 Nov 2023 16:00:49 -0500 Subject: [PATCH] [Build Tasks] Import mono linker sources (#8482) The `Xamarin.Android.Build.Tasks` and `Microsoft.Android.Sdk.ILLink` projects have been updated to only compile the linker sources that they require, rather than including everything from the `src/Xamarin.Android.Build.Tasks/Linker` folder. Linker sources from https://github.com/mono/mono/commit/6dd9def57ce969ca04a0ecd9ef72c0a8f069112d have been added to `src/Xamarin.Android.Build.Tasks/Linker/External`. Adding the couple dozen files we still depend on directly to the repo removes one of the last dependencies we have on the mono bundle. The `LinkAssembliesNoShrink` task is the main piece of XABT that depends on these mono linker sources. In the future we should try to see if we can migrate this tasks functionality to some ILLink tool/task invocation. --- Configuration.props | 2 - .../Microsoft.Android.Sdk.ILLink.csproj | 44 +- src/Microsoft.Android.Sdk.ILLink/SetupStep.cs | 1 - .../Linker/External/Linker.Steps/BaseStep.cs | 83 +++ .../Linker/External/Linker.Steps/IStep.cs | 34 ++ .../Linker/External/Linker/Annotations.cs | 452 +++++++++++++++ .../Linker/External/Linker/AssemblyAction.cs | 55 ++ .../External/Linker/AssemblyResolver.cs | 157 ++++++ .../Linker/External/Linker/ConsoleLogger.cs | 11 + .../External/Linker/IDependencyRecorder.cs | 44 ++ .../Linker/External/Linker/ILogger.cs | 15 + .../Linker/IReflectionPatternRecorder.cs | 62 +++ .../Linker/External/Linker/KnownMembers.cs | 31 ++ .../Linker/External/Linker/LinkContext.cs | 447 +++++++++++++++ .../LoggingReflectionPatternRecorder.cs | 49 ++ .../Linker/External/Linker/MarkingHelpers.cs | 20 + .../Linker/External/Linker/MethodAction.cs | 38 ++ .../External/Linker/OverrideInformation.cs | 43 ++ .../Linker/External/Linker/Pipeline.cs | 152 +++++ .../Linker/External/Linker/Tracer.cs | 115 ++++ .../Linker/External/Linker/TypePreserve.cs | 38 ++ .../Linker/External/Mono.Tuner/CecilRocks.cs | 519 ++++++++++++++++++ .../Linker/External}/Mono.Tuner/Extensions.cs | 7 +- .../Linker/External/Mono.Tuner/Profile.cs | 78 +++ .../Utilities/ManifestDocumentElement.cs | 1 - .../Xamarin.Android.Build.Tasks.csproj | 238 ++------ 26 files changed, 2499 insertions(+), 237 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/IStep.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Annotations.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyAction.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyResolver.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ConsoleLogger.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IDependencyRecorder.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ILogger.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IReflectionPatternRecorder.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/KnownMembers.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LinkContext.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LoggingReflectionPatternRecorder.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MarkingHelpers.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MethodAction.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/OverrideInformation.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Pipeline.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Tracer.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Linker/TypePreserve.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/CecilRocks.cs rename src/{Microsoft.Android.Sdk.ILLink => Xamarin.Android.Build.Tasks/Linker/External}/Mono.Tuner/Extensions.cs (92%) create mode 100644 src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Profile.cs diff --git a/Configuration.props b/Configuration.props index 46fbf558151..5c4a2f321fe 100644 --- a/Configuration.props +++ b/Configuration.props @@ -113,7 +113,6 @@ $(MonoRequiredMinimumVersion) False True - $(MSBuildThisFileDirectory)external\mono\sdks\out\android-sources\external\linker\src $(MSBuildThisFileDirectory)external\opentk \usr $(HostHomebrewPrefix)\opt\mingw-zlib\usr @@ -165,7 +164,6 @@ $([System.IO.Path]::GetFullPath ('$(AndroidSdkDirectory)')) $([System.IO.Path]::GetFullPath ('$(JavaInteropSourceDirectory)')) $([System.IO.Path]::GetFullPath ('$(MonoSourceDirectory)')) - $([System.IO.Path]::GetFullPath ('$(LinkerSourceDirectory)')) $([System.IO.Path]::GetFullPath ('$(SqliteSourceDirectory)')) $([System.IO.Path]::GetFullPath ('$(OpenTKSourceDirectory)')) diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj index aa8694c7a3c..bee005cab0c 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -13,32 +13,26 @@ - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + diff --git a/src/Microsoft.Android.Sdk.ILLink/SetupStep.cs b/src/Microsoft.Android.Sdk.ILLink/SetupStep.cs index c8f56b575be..53ee2f3017f 100644 --- a/src/Microsoft.Android.Sdk.ILLink/SetupStep.cs +++ b/src/Microsoft.Android.Sdk.ILLink/SetupStep.cs @@ -5,7 +5,6 @@ using Mono.Cecil; using Mono.Linker; using Mono.Linker.Steps; -using Mono.Tuner; using MonoDroid.Tuner; namespace Microsoft.Android.Sdk.ILLink diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs new file mode 100644 index 00000000000..39210adc9ee --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs @@ -0,0 +1,83 @@ +// +// BaseStep.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Cecil; + +namespace Mono.Linker.Steps { + + public abstract class BaseStep : IStep { + + private LinkContext _context; + + public LinkContext Context { + get { return _context; } + } + + public AnnotationStore Annotations { + get { return _context.Annotations; } + } + + public Tracer Tracer { + get { return _context.Tracer; } + } + + public MarkingHelpers MarkingHelpers => _context.MarkingHelpers; + + public void Process (LinkContext context) + { + _context = context; + + if (!ConditionToProcess ()) + return; + + Process (); + + foreach (AssemblyDefinition assembly in context.GetAssemblies ()) + ProcessAssembly (assembly); + + EndProcess (); + } + + protected virtual bool ConditionToProcess () + { + return true; + } + + protected virtual void Process () + { + } + + protected virtual void EndProcess () + { + } + + protected virtual void ProcessAssembly (AssemblyDefinition assembly) + { + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/IStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/IStep.cs new file mode 100644 index 00000000000..c01ef1e6b3f --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/IStep.cs @@ -0,0 +1,34 @@ +// +// IStep.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Linker.Steps { + + public interface IStep { + void Process (LinkContext context); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Annotations.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Annotations.cs new file mode 100644 index 00000000000..95bc5eb5b15 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Annotations.cs @@ -0,0 +1,452 @@ +// +// Annotations.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Mono.Linker { + + public partial class AnnotationStore { + + protected readonly LinkContext context; + + protected readonly Dictionary assembly_actions = new Dictionary (); + protected readonly Dictionary method_actions = new Dictionary (); + protected readonly Dictionary method_stub_values = new Dictionary (); + protected readonly Dictionary field_values = new Dictionary (); + protected readonly HashSet field_init = new HashSet (); + protected readonly HashSet fieldType_init = new HashSet (); + protected readonly HashSet marked = new HashSet (); + protected readonly HashSet processed = new HashSet (); + protected readonly Dictionary preserved_types = new Dictionary (); + protected readonly Dictionary> preserved_methods = new Dictionary> (); + protected readonly HashSet public_api = new HashSet (); + protected readonly Dictionary> override_methods = new Dictionary> (); + protected readonly Dictionary> base_methods = new Dictionary> (); + protected readonly Dictionary symbol_readers = new Dictionary (); + protected readonly Dictionary> class_type_base_hierarchy = new Dictionary> (); + protected readonly Dictionary> derived_interfaces = new Dictionary>(); + + protected readonly Dictionary> custom_annotations = new Dictionary> (); + protected readonly Dictionary> resources_to_remove = new Dictionary> (); + protected readonly HashSet marked_attributes = new HashSet (); + readonly HashSet marked_types_with_cctor = new HashSet (); + protected readonly HashSet marked_instantiated = new HashSet (); + protected readonly HashSet indirectly_called = new HashSet(); + + + public AnnotationStore (LinkContext context) => this.context = context; + + public bool ProcessSatelliteAssemblies { get; set; } + + protected Tracer Tracer { + get { + return context.Tracer; + } + } + + public ICollection GetAssemblies () + { + return assembly_actions.Keys; + } + + public AssemblyAction GetAction (AssemblyDefinition assembly) + { + AssemblyAction action; + if (assembly_actions.TryGetValue (assembly, out action)) + return action; + + throw new InvalidOperationException($"No action for the assembly {assembly.Name} defined"); + } + + public MethodAction GetAction (MethodDefinition method) + { + MethodAction action; + if (method_actions.TryGetValue (method, out action)) + return action; + + return MethodAction.Nothing; + } + + public void SetAction (AssemblyDefinition assembly, AssemblyAction action) + { + assembly_actions [assembly] = action; + } + + public bool HasAction (AssemblyDefinition assembly) + { + return assembly_actions.ContainsKey (assembly); + } + + public void SetAction (MethodDefinition method, MethodAction action) + { + method_actions [method] = action; + } + + public void SetMethodStubValue (MethodDefinition method, object value) + { + method_stub_values [method] = value; + } + + public void SetFieldValue (FieldDefinition field, object value) + { + field_values [field] = value; + } + + public void SetSubstitutedInit (FieldDefinition field) + { + field_init.Add (field); + } + + public bool HasSubstitutedInit (FieldDefinition field) + { + return field_init.Contains (field); + } + + public void SetSubstitutedInit (TypeDefinition type) + { + fieldType_init.Add (type); + } + + public bool HasSubstitutedInit (TypeDefinition type) + { + return fieldType_init.Contains (type); + } + + public void Mark (IMetadataTokenProvider provider) + { + marked.Add (provider); + Tracer.AddDependency (provider, true); + } + + public void Mark (CustomAttribute attribute) + { + marked_attributes.Add (attribute); + } + + public void MarkAndPush (IMetadataTokenProvider provider) + { + Mark (provider); + Tracer.Push (provider, false); + } + + public bool IsMarked (IMetadataTokenProvider provider) + { + return marked.Contains (provider); + } + + public bool IsMarked (CustomAttribute attribute) + { + return marked_attributes.Contains (attribute); + } + + public void MarkIndirectlyCalledMethod (MethodDefinition method) + { + if (!context.AddReflectionAnnotations) + return; + + indirectly_called.Add (method); + } + + public bool HasMarkedAnyIndirectlyCalledMethods () + { + return indirectly_called.Count != 0; + } + + public bool IsIndirectlyCalled (MethodDefinition method) + { + return indirectly_called.Contains (method); + } + + public void MarkInstantiated (TypeDefinition type) + { + marked_instantiated.Add (type); + } + + public bool IsInstantiated (TypeDefinition type) + { + return marked_instantiated.Contains (type); + } + + public void Processed (IMetadataTokenProvider provider) + { + processed.Add (provider); + } + + public bool IsProcessed (IMetadataTokenProvider provider) + { + return processed.Contains (provider); + } + + public bool IsPreserved (TypeDefinition type) + { + return preserved_types.ContainsKey (type); + } + + public void SetPreserve (TypeDefinition type, TypePreserve preserve) + { + TypePreserve existing; + if (preserved_types.TryGetValue (type, out existing)) + preserved_types [type] = ChoosePreserveActionWhichPreservesTheMost (existing, preserve); + else + preserved_types.Add (type, preserve); + } + + public static TypePreserve ChoosePreserveActionWhichPreservesTheMost (TypePreserve leftPreserveAction, TypePreserve rightPreserveAction) + { + if (leftPreserveAction == rightPreserveAction) + return leftPreserveAction; + + if (leftPreserveAction == TypePreserve.All || rightPreserveAction == TypePreserve.All) + return TypePreserve.All; + + if (leftPreserveAction == TypePreserve.Nothing) + return rightPreserveAction; + + if (rightPreserveAction == TypePreserve.Nothing) + return leftPreserveAction; + + if ((leftPreserveAction == TypePreserve.Methods && rightPreserveAction == TypePreserve.Fields) || + (leftPreserveAction == TypePreserve.Fields && rightPreserveAction == TypePreserve.Methods)) + return TypePreserve.All; + + return rightPreserveAction; + } + + public TypePreserve GetPreserve (TypeDefinition type) + { + TypePreserve preserve; + if (preserved_types.TryGetValue (type, out preserve)) + return preserve; + + throw new NotSupportedException ($"No type preserve information for `{type}`"); + } + + public bool TryGetPreserve (TypeDefinition type, out TypePreserve preserve) + { + return preserved_types.TryGetValue (type, out preserve); + } + + public bool TryGetMethodStubValue (MethodDefinition method, out object value) + { + return method_stub_values.TryGetValue (method, out value); + } + + public bool TryGetFieldUserValue (FieldDefinition field, out object value) + { + return field_values.TryGetValue (field, out value); + } + + public HashSet GetResourcesToRemove (AssemblyDefinition assembly) + { + HashSet resources; + if (resources_to_remove.TryGetValue (assembly, out resources)) + return resources; + + return null; + } + + public void AddResourceToRemove (AssemblyDefinition assembly, string name) + { + HashSet resources; + if (!resources_to_remove.TryGetValue (assembly, out resources)) { + resources = resources_to_remove [assembly] = new HashSet (); + } + + resources.Add (name); + } + + public void SetPublic (IMetadataTokenProvider provider) + { + public_api.Add (provider); + } + + public bool IsPublic (IMetadataTokenProvider provider) + { + return public_api.Contains (provider); + } + + public void AddOverride (MethodDefinition @base, MethodDefinition @override, InterfaceImplementation matchingInterfaceImplementation = null) + { + var methods = GetOverrides (@base); + if (methods == null) { + methods = new List (); + override_methods [@base] = methods; + } + + methods.Add (new OverrideInformation (@base, @override, matchingInterfaceImplementation)); + } + + public List GetOverrides (MethodDefinition method) + { + List overrides; + if (override_methods.TryGetValue (method, out overrides)) + return overrides; + + return null; + } + + public void AddBaseMethod (MethodDefinition method, MethodDefinition @base) + { + var methods = GetBaseMethods (method); + if (methods == null) { + methods = new List (); + base_methods [method] = methods; + } + + methods.Add (@base); + } + + public List GetBaseMethods (MethodDefinition method) + { + List bases; + if (base_methods.TryGetValue (method, out bases)) + return bases; + + return null; + } + + public List GetPreservedMethods (TypeDefinition type) + { + return GetPreservedMethods (type as IMemberDefinition); + } + + public void AddPreservedMethod (TypeDefinition type, MethodDefinition method) + { + AddPreservedMethod (type as IMemberDefinition, method); + } + + public List GetPreservedMethods (MethodDefinition method) + { + return GetPreservedMethods (method as IMemberDefinition); + } + + public void AddPreservedMethod (MethodDefinition key, MethodDefinition method) + { + AddPreservedMethod (key as IMemberDefinition, method); + } + + List GetPreservedMethods (IMemberDefinition definition) + { + List preserved; + if (preserved_methods.TryGetValue (definition, out preserved)) + return preserved; + + return null; + } + + void AddPreservedMethod (IMemberDefinition definition, MethodDefinition method) + { + var methods = GetPreservedMethods (definition); + if (methods == null) { + methods = new List (); + preserved_methods [definition] = methods; + } + + methods.Add (method); + } + + public void AddSymbolReader (AssemblyDefinition assembly, ISymbolReader symbolReader) + { + symbol_readers [assembly] = symbolReader; + } + + public void CloseSymbolReader (AssemblyDefinition assembly) + { + ISymbolReader symbolReader; + if (!symbol_readers.TryGetValue (assembly, out symbolReader)) + return; + + symbol_readers.Remove (assembly); + symbolReader.Dispose (); + } + + public Dictionary GetCustomAnnotations (object key) + { + Dictionary slots; + if (custom_annotations.TryGetValue (key, out slots)) + return slots; + + slots = new Dictionary (); + custom_annotations.Add (key, slots); + return slots; + } + + public bool HasPreservedStaticCtor (TypeDefinition type) + { + return marked_types_with_cctor.Contains (type); + } + + public bool SetPreservedStaticCtor (TypeDefinition type) + { + return marked_types_with_cctor.Add (type); + } + + public void SetClassHierarchy (TypeDefinition type, List bases) + { + class_type_base_hierarchy [type] = bases; + } + + public List GetClassHierarchy (TypeDefinition type) + { + if (class_type_base_hierarchy.TryGetValue (type, out List bases)) + return bases; + + return null; + } + + public void AddDerivedInterfaceForInterface (TypeDefinition @base, TypeDefinition derived) + { + if (!@base.IsInterface) + throw new ArgumentException ($"{nameof (@base)} must be an interface"); + + if (!derived.IsInterface) + throw new ArgumentException ($"{nameof (derived)} must be an interface"); + + List derivedInterfaces; + if (!derived_interfaces.TryGetValue (@base, out derivedInterfaces)) + derived_interfaces [@base] = derivedInterfaces = new List (); + + derivedInterfaces.Add(derived); + } + + public List GetDerivedInterfacesForInterface (TypeDefinition @interface) + { + if (!@interface.IsInterface) + throw new ArgumentException ($"{nameof (@interface)} must be an interface"); + + List derivedInterfaces; + if (derived_interfaces.TryGetValue (@interface, out derivedInterfaces)) + return derivedInterfaces; + + return null; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyAction.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyAction.cs new file mode 100644 index 00000000000..341339cd159 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyAction.cs @@ -0,0 +1,55 @@ +// +// AssemblyAction.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Linker { + + public enum AssemblyAction { + // Ignore the assembly + Skip, + // Copy the existing files, assembly and symbols, into the output destination. E.g. .dll and .mdb + // The linker still analyzes the assemblies (to know what they require) but does not modify them. + Copy, + // Copy the existing files, assembly and symbols, into the output destination if and only if + // anything from the assembly is used. + // The linker still analyzes the assemblies (to know what they require) but does not modify them. + CopyUsed, + // Link the assembly + Link, + // Remove the assembly from the output + Delete, + // Save the assembly/symbols in memory without linking it. + // E.g. useful to remove unneeded assembly references (as done in SweepStep), + // resolving [TypeForwardedTo] attributes (like PCL) to their final location + Save, + // Keep all types, methods, and fields but add System.Runtime.BypassNGenAttribute to unmarked methods. + AddBypassNGen, + // Keep all types, methods, and fields in marked assemblies but add System.Runtime.BypassNGenAttribute to unmarked methods. + // Delete unmarked assemblies. + AddBypassNGenUsed + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyResolver.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyResolver.cs new file mode 100644 index 00000000000..143a7559f1b --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/AssemblyResolver.cs @@ -0,0 +1,157 @@ +// +// AssemblyResolver.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace Mono.Linker { + +#if FEATURE_ILLINK + public class AssemblyResolver : DirectoryAssemblyResolver { +#else + public class AssemblyResolver : BaseAssemblyResolver { +#endif + + readonly Dictionary _assemblies; + HashSet _unresolvedAssemblies; + bool _ignoreUnresolved; + LinkContext _context; + readonly Collection _references; + + + public IDictionary AssemblyCache { + get { return _assemblies; } + } + + public AssemblyResolver () + : this (new Dictionary (StringComparer.OrdinalIgnoreCase)) + { + } + + public AssemblyResolver (Dictionary assembly_cache) + { + _assemblies = assembly_cache; + _references = new Collection () { }; + } + + public bool IgnoreUnresolved { + get { return _ignoreUnresolved; } + set { _ignoreUnresolved = value; } + } + + public LinkContext Context { + get { return _context; } + set { _context = value; } + } + +#if !FEATURE_ILLINK + // The base class's definition of GetAssembly is visible when using DirectoryAssemblyResolver. + AssemblyDefinition GetAssembly (string file, ReaderParameters parameters) + { + if (parameters.AssemblyResolver == null) + parameters.AssemblyResolver = this; + + return ModuleDefinition.ReadModule (file, parameters).Assembly; + } +#endif + + AssemblyDefinition ResolveFromReferences (AssemblyNameReference name, Collection references, ReaderParameters parameters) + { + var fileName = name.Name + ".dll"; + foreach (var reference in references) { + if (Path.GetFileName (reference) != fileName) + continue; + try { + return GetAssembly (reference, parameters); + } catch (BadImageFormatException) { + continue; + } + } + + return null; + } + + public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters) + { + // Validate arguments, similarly to how the base class does it. + if (name == null) + throw new ArgumentNullException ("name"); + if (parameters == null) + throw new ArgumentNullException ("parameters"); + + AssemblyDefinition asm = null; + if (!_assemblies.TryGetValue (name.Name, out asm) && (_unresolvedAssemblies == null || !_unresolvedAssemblies.Contains (name.Name))) { + try { + // Any full path explicit reference takes precedence over other look up logic + asm = ResolveFromReferences (name, _references, parameters); + + // Fall back to the base class resolution logic + if (asm == null) + asm = base.Resolve (name, parameters); + + _assemblies [name.Name] = asm; + } catch (AssemblyResolutionException) { + if (!_ignoreUnresolved) + throw; + _context.LogMessage ($"warning: Ignoring unresolved assembly '{name.Name}'."); + if (_unresolvedAssemblies == null) + _unresolvedAssemblies = new HashSet (); + _unresolvedAssemblies.Add (name.Name); + } + } + + return asm; + } + + public virtual AssemblyDefinition CacheAssembly (AssemblyDefinition assembly) + { + _assemblies [assembly.Name.Name] = assembly; + base.AddSearchDirectory (Path.GetDirectoryName (assembly.MainModule.FileName)); + return assembly; + } + + public void AddReferenceAssembly (string referencePath) + { + _references.Add (referencePath); + } + + protected override void Dispose (bool disposing) + { + foreach (var asm in _assemblies.Values) { + asm.Dispose (); + } + + _assemblies.Clear (); + if (_unresolvedAssemblies != null) + _unresolvedAssemblies.Clear (); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ConsoleLogger.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ConsoleLogger.cs new file mode 100644 index 00000000000..f7059f2b89f --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ConsoleLogger.cs @@ -0,0 +1,11 @@ +using System; +namespace Mono.Linker +{ + public class ConsoleLogger : ILogger + { + public void LogMessage (MessageImportance importance, string message, params object[] values) + { + Console.WriteLine (message, values); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IDependencyRecorder.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IDependencyRecorder.cs new file mode 100644 index 00000000000..de4e4616e94 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IDependencyRecorder.cs @@ -0,0 +1,44 @@ +// +// IDependencyRecorder.cs +// +// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Linker +{ + /// + /// Abstraction exposed by the linker (mostly MarkStep, but not only) - it will call this interface + /// every time it finds a dependency between two parts of the dependency graph. + /// + public interface IDependencyRecorder + { + /// + /// Reports a dependency detected by the linker. + /// + /// The source of the dependency (for example the caller method). + /// The target of the dependency (for example the callee method). + /// true if the target is also marked by the MarkStep. + /// The source and target are typically Cecil metadata objects (MethodDefinition, TypeDefinition, ...) + /// but they can also be the linker steps or really any other object. + void RecordDependency (object source, object target, bool marked); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ILogger.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ILogger.cs new file mode 100644 index 00000000000..d4f610fbb53 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/ILogger.cs @@ -0,0 +1,15 @@ +using System; +namespace Mono.Linker +{ + public enum MessageImportance + { + High, + Low, + Normal, + } + + public interface ILogger + { + void LogMessage (MessageImportance importance, string message, params object[] values); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IReflectionPatternRecorder.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IReflectionPatternRecorder.cs new file mode 100644 index 00000000000..b3aae2b2ea7 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/IReflectionPatternRecorder.cs @@ -0,0 +1,62 @@ +// +// IReflectionPatternRecorder.cs +// +// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Cecil; + +namespace Mono.Linker +{ + /// + /// Interface which is called every time the linker inspects a pattern of code involving reflection to determine a more complex + /// dependency. + /// + /// + /// The rules are such that if a given callsite of a "reflectionMethod" gets examined + /// linker will always report it one way or another: + /// - it will either call RecognizedReflectionAccessPattern method when it can figure out exactly the dependency. + /// - or it will call UnrecognizedReflectionAccessPattern with an optional message describing why it could not recognize + /// the pattern. + /// + public interface IReflectionPatternRecorder + { + /// + /// Called when the linker recognized a reflection access pattern (and thus was able to correctly apply marking to the accessed item). + /// + /// The method which contains the reflection access pattern. + /// The reflection method which is at the heart of the access pattern. + /// The item accessed through reflection. This can be one of: + /// TypeDefinition, MethodDefinition, PropertyDefinition, FieldDefinition, EventDefinition. + void RecognizedReflectionAccessPattern (MethodDefinition sourceMethod, MethodDefinition reflectionMethod, IMemberDefinition accessedItem); + + /// + /// Called when the linker detected a reflection access but was not able to recognize the entire pattern. + /// + /// The method which contains the reflection access code. + /// The reflection method which is at the heart of the access code. + /// Humanly readable message describing what failed during the pattern recognition. + /// This effectively means that there's a potential hole in the linker marking - some items which are accessed only through + /// reflection may not be marked correctly and thus may fail at runtime. + void UnrecognizedReflectionAccessPattern (MethodDefinition sourceMethod, MethodDefinition reflectionMethod, string message); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/KnownMembers.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/KnownMembers.cs new file mode 100644 index 00000000000..02dcf6469ad --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/KnownMembers.cs @@ -0,0 +1,31 @@ +using Mono.Cecil; + +namespace Mono.Linker +{ + public class KnownMembers + { + public MethodDefinition NotSupportedExceptionCtorString { get; set; } + public MethodDefinition DisablePrivateReflectionAttributeCtor { get; set; } + public MethodDefinition ObjectCtor { get; set; } + + public static bool IsNotSupportedExceptionCtorString (MethodDefinition method) + { + if (!method.IsConstructor || method.IsStatic || !method.HasParameters) + return false; + + if (method.Parameters.Count != 1 || method.Parameters [0].ParameterType.MetadataType != MetadataType.String) + return false; + + return true; + } + + public static bool IsSatelliteAssemblyMarker (MethodDefinition method) + { + if (!method.IsConstructor || method.IsStatic) + return false; + + var declaringType = method.DeclaringType; + return declaringType.Name == "ResourceManager" && declaringType.Namespace == "System.Resources"; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LinkContext.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LinkContext.cs new file mode 100644 index 00000000000..b05afc29cb7 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LinkContext.cs @@ -0,0 +1,447 @@ +// +// LinkContext.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.IO; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Mono.Linker { + + public class UnintializedContextFactory { + virtual public AnnotationStore CreateAnnotationStore (LinkContext context) => new AnnotationStore (context); + virtual public MarkingHelpers CreateMarkingHelpers (LinkContext context) => new MarkingHelpers (context); + virtual public Tracer CreateTracer (LinkContext context) => new Tracer (context); + } + + public class LinkContext : IDisposable { + + Pipeline _pipeline; + AssemblyAction _coreAction; + AssemblyAction _userAction; + Dictionary _actions; + string _outputDirectory; + readonly Dictionary _parameters; + bool _linkSymbols; + bool _keepTypeForwarderOnlyAssemblies; + bool _keepMembersForDebugger; + bool _ignoreUnresolved; + + AssemblyResolver _resolver; + + ReaderParameters _readerParameters; + ISymbolReaderProvider _symbolReaderProvider; + ISymbolWriterProvider _symbolWriterProvider; + + AnnotationStore _annotations; + + public Pipeline Pipeline { + get { return _pipeline; } + } + + public AnnotationStore Annotations { + get { return _annotations; } + } + + public bool DeterministicOutput { get; set; } + + public string OutputDirectory { + get { return _outputDirectory; } + set { _outputDirectory = value; } + } + + public AssemblyAction CoreAction { + get { return _coreAction; } + set { _coreAction = value; } + } + + public AssemblyAction UserAction { + get { return _userAction; } + set { _userAction = value; } + } + + public bool LinkSymbols { + get { return _linkSymbols; } + set { _linkSymbols = value; } + } + + public bool KeepTypeForwarderOnlyAssemblies + { + get { return _keepTypeForwarderOnlyAssemblies; } + set { _keepTypeForwarderOnlyAssemblies = value; } + } + + public bool KeepMembersForDebugger + { + get { return _keepMembersForDebugger; } + set { _keepMembersForDebugger = value; } + } + + public bool IgnoreUnresolved + { + get { return _ignoreUnresolved; } + set { _ignoreUnresolved = value; } + } + + public bool EnableReducedTracing { get; set; } + + public bool KeepUsedAttributeTypesOnly { get; set; } + + public bool KeepDependencyAttributes { get; set; } + + public bool StripResources { get; set; } + + public List Substitutions { get; private set; } + + public System.Collections.IDictionary Actions { + get { return _actions; } + } + + public AssemblyResolver Resolver { + get { return _resolver; } + } + + public ReaderParameters ReaderParameters { + get { return _readerParameters; } + } + + public ISymbolReaderProvider SymbolReaderProvider { + get { return _symbolReaderProvider; } + set { _symbolReaderProvider = value; } + } + + public ISymbolWriterProvider SymbolWriterProvider { + get { return _symbolWriterProvider; } + set { _symbolWriterProvider = value; } + } + + public bool LogMessages { get; set; } + + public ILogger Logger { private get; set; } = new ConsoleLogger (); + + public MarkingHelpers MarkingHelpers { get; private set; } + + public KnownMembers MarkedKnownMembers { get; private set; } + + public Tracer Tracer { get; private set; } + + public IReflectionPatternRecorder ReflectionPatternRecorder { get; set; } + + public string [] ExcludedFeatures { get; set; } + + public CodeOptimizations DisabledOptimizations { get; set; } + + public bool AddReflectionAnnotations { get; set; } + + public string AssemblyListFile { get; set; } + + public LinkContext (Pipeline pipeline) + : this (pipeline, new AssemblyResolver ()) + { + } + + public LinkContext (Pipeline pipeline, AssemblyResolver resolver) + : this(pipeline, resolver, new ReaderParameters + { + AssemblyResolver = resolver + }, new UnintializedContextFactory ()) + { + } + + public LinkContext (Pipeline pipeline, AssemblyResolver resolver, ReaderParameters readerParameters, UnintializedContextFactory factory) + { + _pipeline = pipeline; + _resolver = resolver; + _resolver.Context = this; + _actions = new Dictionary (); + _parameters = new Dictionary (); + _readerParameters = readerParameters; + + SymbolReaderProvider = new DefaultSymbolReaderProvider (false); + + if (factory == null) + throw new ArgumentNullException (nameof (factory)); + + _annotations = factory.CreateAnnotationStore (this); + MarkingHelpers = factory.CreateMarkingHelpers (this); + Tracer = factory.CreateTracer (this); + ReflectionPatternRecorder = new LoggingReflectionPatternRecorder (this); + MarkedKnownMembers = new KnownMembers (); + StripResources = true; + + // See https://github.com/mono/linker/issues/612 + DisabledOptimizations |= CodeOptimizations.UnreachableBodies; + DisabledOptimizations |= CodeOptimizations.ClearInitLocals; + DisabledOptimizations |= CodeOptimizations.IPConstantPropagation; + } + + public void AddSubstitutionFile (string file) + { + if (Substitutions == null) { + Substitutions = new List (); + Substitutions.Add (file); + return; + } + + if (Substitutions.Contains (file)) + return; + + Substitutions.Add (file); + } + + public AssemblyDefinition Resolve (string name) + { + if (File.Exists (name)) { + try { + AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly (name, _readerParameters); + return _resolver.CacheAssembly (assembly); + } catch (Exception e) { + throw new AssemblyResolutionException (new AssemblyNameReference (name, new Version ()), e); + } + } + + return Resolve (new AssemblyNameReference (name, new Version ())); + } + + public AssemblyDefinition Resolve (IMetadataScope scope) + { + AssemblyNameReference reference = GetReference (scope); + try { + AssemblyDefinition assembly = _resolver.Resolve (reference, _readerParameters); + + if (assembly != null) + RegisterAssembly (assembly); + + return assembly; + } + catch (Exception e) { + throw new AssemblyResolutionException (reference, e); + } + } + + public void RegisterAssembly (AssemblyDefinition assembly) + { + if (SeenFirstTime (assembly)) { + SafeReadSymbols (assembly); + SetDefaultAction (assembly); + } + } + + protected bool SeenFirstTime (AssemblyDefinition assembly) + { + return !_annotations.HasAction (assembly); + } + + public virtual void SafeReadSymbols (AssemblyDefinition assembly) + { + if (assembly.MainModule.HasSymbols) + return; + + if (_symbolReaderProvider == null) + throw new ArgumentNullException (nameof (_symbolReaderProvider)); + + try { + var symbolReader = _symbolReaderProvider.GetSymbolReader ( + assembly.MainModule, + assembly.MainModule.FileName); + + if (symbolReader == null) + return; + + try { + assembly.MainModule.ReadSymbols (symbolReader); + } catch { + symbolReader.Dispose (); + return; + } + + // Add symbol reader to annotations only if we have successfully read it + _annotations.AddSymbolReader (assembly, symbolReader); + } catch { } + } + + public virtual ICollection ResolveReferences (AssemblyDefinition assembly) + { + List references = new List (); + if (assembly == null) + return references; + foreach (AssemblyNameReference reference in assembly.MainModule.AssemblyReferences) { + AssemblyDefinition definition = Resolve (reference); + if (definition != null) + references.Add (definition); + } + return references; + } + + static AssemblyNameReference GetReference (IMetadataScope scope) + { + AssemblyNameReference reference; + if (scope is ModuleDefinition) { + AssemblyDefinition asm = ((ModuleDefinition) scope).Assembly; + reference = asm.Name; + } else + reference = (AssemblyNameReference) scope; + + return reference; + } + + public void SetAction (AssemblyDefinition assembly, AssemblyAction defaultAction) + { + RegisterAssembly (assembly); + + if (!_actions.TryGetValue (assembly.Name.Name, out AssemblyAction action)) + action = defaultAction; + + Annotations.SetAction (assembly, action); + } + + protected void SetDefaultAction (AssemblyDefinition assembly) + { + AssemblyAction action; + + AssemblyNameDefinition name = assembly.Name; + + if (_actions.TryGetValue (name.Name, out action)) { + } else if (IsCore (name)) { + action = _coreAction; + } else { + action = _userAction; + } + + _annotations.SetAction (assembly, action); + } + + public static bool IsCore (AssemblyNameReference name) + { + switch (name.Name) { + case "mscorlib": + case "Accessibility": + case "Mono.Security": + // WPF + case "PresentationFramework": + case "PresentationCore": + case "WindowsBase": + case "UIAutomationProvider": + case "UIAutomationTypes": + case "PresentationUI": + case "ReachFramework": + case "netstandard": + return true; + default: + return name.Name.StartsWith ("System") + || name.Name.StartsWith ("Microsoft"); + } + } + + public virtual AssemblyDefinition [] GetAssemblies () + { + var cache = _resolver.AssemblyCache; + AssemblyDefinition [] asms = new AssemblyDefinition [cache.Count]; + cache.Values.CopyTo (asms, 0); + return asms; + } + + public void SetParameter (string key, string value) + { + _parameters [key] = value; + } + + public bool HasParameter (string key) + { + return _parameters.ContainsKey (key); + } + + public string GetParameter (string key) + { + string val = null; + _parameters.TryGetValue (key, out val); + return val; + } + + public void Dispose () + { + _resolver.Dispose (); + } + + public bool IsFeatureExcluded (string featureName) + { + return ExcludedFeatures != null && Array.IndexOf (ExcludedFeatures, featureName) >= 0; + } + + public bool IsOptimizationEnabled (CodeOptimizations optimization) + { + return (DisabledOptimizations & optimization) == 0; + } + + public void LogMessage (string message) + { + LogMessage (MessageImportance.Normal, message); + } + + public void LogMessage (MessageImportance importance, string message) + { + if (LogMessages && Logger != null) + Logger.LogMessage (importance, "{0}", message); + } + } + + [Flags] + public enum CodeOptimizations + { + BeforeFieldInit = 1 << 0, + + /// + /// Option to disable removal of overrides of virtual methods when a type is never instantiated + /// + /// Being able to disable this optimization is helpful when trying to troubleshoot problems caused by types created via reflection or from native + /// that do not get an instance constructor marked. + /// + OverrideRemoval = 1 << 1, + + /// + /// Option to disable delaying marking of instance methods until an instance of that type could exist + /// + UnreachableBodies = 1 << 2, + + /// + /// Option to clear the initlocals flag on methods + /// + ClearInitLocals = 1 << 3, + + /// + /// Option to remove .interfaceimpl for interface types that are not used + /// + UnusedInterfaces = 1 << 4, + + /// + /// Option to do interprocedural constant propagation on return values + /// + IPConstantPropagation = 1 << 5 + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LoggingReflectionPatternRecorder.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LoggingReflectionPatternRecorder.cs new file mode 100644 index 00000000000..f9c0d89e938 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/LoggingReflectionPatternRecorder.cs @@ -0,0 +1,49 @@ +// +// LoggingReflectionPatternRecorder.cs +// +// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Cecil; + +namespace Mono.Linker +{ + class LoggingReflectionPatternRecorder : IReflectionPatternRecorder + { + private readonly LinkContext _context; + + public LoggingReflectionPatternRecorder (LinkContext context) + { + _context = context; + } + + public void RecognizedReflectionAccessPattern (MethodDefinition sourceMethod, MethodDefinition reflectionMethod, IMemberDefinition accessedItem) + { + // Do nothing - there's no logging for successfully recognized patterns + } + + public void UnrecognizedReflectionAccessPattern (MethodDefinition sourceMethod, MethodDefinition reflectionMethod, string message) + { + _context.LogMessage (MessageImportance.Low, message); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MarkingHelpers.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MarkingHelpers.cs new file mode 100644 index 00000000000..b477a5ce389 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MarkingHelpers.cs @@ -0,0 +1,20 @@ +using System; +using Mono.Cecil; + +namespace Mono.Linker { + public class MarkingHelpers { + protected readonly LinkContext _context; + + public MarkingHelpers (LinkContext context) + { + _context = context; + } + + public void MarkExportedType (ExportedType type, ModuleDefinition module) + { + _context.Annotations.Mark (type); + if (_context.KeepTypeForwarderOnlyAssemblies) + _context.Annotations.Mark (module); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MethodAction.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MethodAction.cs new file mode 100644 index 00000000000..a3550e78396 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/MethodAction.cs @@ -0,0 +1,38 @@ +// +// MethodAction.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Linker { + + public enum MethodAction { + Nothing, + Parse, + ForceParse, + ConvertToStub, + ConvertToThrow, + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/OverrideInformation.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/OverrideInformation.cs new file mode 100644 index 00000000000..f73d8bc1c63 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/OverrideInformation.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using Mono.Cecil; + +namespace Mono.Linker { + [DebuggerDisplay ("{Override}")] + public class OverrideInformation { + public readonly MethodDefinition Base; + public readonly MethodDefinition Override; + public readonly InterfaceImplementation MatchingInterfaceImplementation; + + public OverrideInformation (MethodDefinition @base, MethodDefinition @override, InterfaceImplementation matchingInterfaceImplementation = null) + { + Base = @base; + Override = @override; + MatchingInterfaceImplementation = matchingInterfaceImplementation; + } + + public bool IsOverrideOfInterfaceMember + { + get + { + if (MatchingInterfaceImplementation != null) + return true; + + return Base.DeclaringType.IsInterface; + } + } + + public TypeDefinition InterfaceType + { + get + { + if (!IsOverrideOfInterfaceMember) + return null; + + if (MatchingInterfaceImplementation != null) + return MatchingInterfaceImplementation.InterfaceType.Resolve (); + + return Base.DeclaringType; + } + } + } +} \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Pipeline.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Pipeline.cs new file mode 100644 index 00000000000..a28de3ba1b2 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Pipeline.cs @@ -0,0 +1,152 @@ +// +// Pipeline.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +using Mono.Linker.Steps; + +namespace Mono.Linker { + + public class Pipeline { + + readonly List _steps; + + public Pipeline () + { + _steps = new List(); + } + + public void PrependStep (IStep step) + { + _steps.Insert (0, step); + } + + public void AppendStep (IStep step) + { + _steps.Add (step); + } + + public void AddStepBefore (Type target, IStep step) + { + for (int i = 0; i < _steps.Count; i++) { + if (target.IsInstanceOfType (_steps [i])) { + _steps.Insert (i, step); + return; + } + } + string msg = String.Format ("Step {0} could not be inserted before (not found) {1}", step, target); + throw new InvalidOperationException (msg); + } + + public void AddStepBefore (IStep target, IStep step) + { + for (int i = 0; i < _steps.Count; i++) { + if (_steps [i] == target) { + _steps.Insert (i, step); + return; + } + } + } + + public void ReplaceStep (Type target, IStep step) + { + AddStepBefore (target, step); + RemoveStep (target); + } + + public void AddStepAfter (Type target, IStep step) + { + for (int i = 0; i < _steps.Count; i++) { + if (target.IsInstanceOfType (_steps [i])) { + if (i == _steps.Count - 1) + _steps.Add (step); + else + _steps.Insert (i + 1, step); + return; + } + } + string msg = String.Format ("Step {0} could not be inserted after (not found) {1}", step, target); + throw new InvalidOperationException (msg); + } + + public void AddStepAfter (IStep target, IStep step) + { + for (int i = 0; i < _steps.Count; i++) { + if (_steps [i] == target) { + if (i == _steps.Count - 1) + _steps.Add (step); + else + _steps.Insert (i + 1, step); + return; + } + } + } + + public void RemoveStep (Type target) + { + for (int i = 0; i < _steps.Count; i++) { + if (_steps [i].GetType () != target) + continue; + + _steps.RemoveAt (i); + break; + } + } + + public void Process (LinkContext context) + { + while (_steps.Count > 0) { + IStep step = _steps [0]; + ProcessStep (context, step); + _steps.Remove (step); + } + } + + protected virtual void ProcessStep (LinkContext context, IStep step) + { + context.Tracer.Push (step); + step.Process (context); + context.Tracer.Pop (); + } + + public IStep [] GetSteps () + { + return _steps.ToArray (); + } + + public bool ContainsStep (Type type) + { + foreach (IStep step in _steps) + if (step.GetType () == type) + return true; + + return false; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Tracer.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Tracer.cs new file mode 100644 index 00000000000..1a6b7109fe9 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/Tracer.cs @@ -0,0 +1,115 @@ +// +// Tracer.cs +// +// Author: +// Radek Doulik +// +// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; + +namespace Mono.Linker +{ + public class Tracer + { + protected readonly LinkContext context; + + Stack dependency_stack; + List recorders; + + public Tracer (LinkContext context) + { + this.context = context; + dependency_stack = new Stack (); + } + + public void Finish () + { + dependency_stack = null; + if (recorders != null) { + foreach (var recorder in recorders) { + if (recorder is IDisposable disposableRecorder) + disposableRecorder.Dispose (); + } + } + + recorders = null; + } + + public void AddRecorder (IDependencyRecorder recorder) + { + if (recorders == null) { + recorders = new List (); + } + + recorders.Add (recorder); + } + + public void Push (object o, bool addDependency = true) + { + if (!IsRecordingEnabled ()) + return; + + if (addDependency && dependency_stack.Count > 0) + AddDependency (o); + + dependency_stack.Push (o); + } + + public void Pop () + { + if (!IsRecordingEnabled ()) + return; + + dependency_stack.Pop (); + } + + bool IsRecordingEnabled () + { + return recorders != null; + } + + public void AddDirectDependency (object b, object e) + { + ReportDependency (b, e, false); + } + + public void AddDependency (object o, bool marked = false) + { + if (!IsRecordingEnabled ()) + return; + + ReportDependency (dependency_stack.Count > 0 ? dependency_stack.Peek () : null, o, marked); + } + + private void ReportDependency (object source, object target, bool marked) + { + if (IsRecordingEnabled ()) { + foreach (IDependencyRecorder recorder in recorders) { + recorder.RecordDependency (source, target, marked); + } + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/TypePreserve.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/TypePreserve.cs new file mode 100644 index 00000000000..bc743c65a18 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker/TypePreserve.cs @@ -0,0 +1,38 @@ +// +// TypePreserve.cs +// +// Author: +// Jb Evain (jb@nurv.fr) +// +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Linker { + + public enum TypePreserve + { + Nothing, // This is actually Declaration + All, + Fields, + Methods + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/CecilRocks.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/CecilRocks.cs new file mode 100644 index 00000000000..69958598dda --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/CecilRocks.cs @@ -0,0 +1,519 @@ +// +// MethodBodyRocks.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// Copyright (c) 2008 - 2011 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Linq; + +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Mono.Tuner { + + public static class MethodBodyRocks { + + public static IEnumerable GetAllTypes (this ModuleDefinition self) + { + return self.Types.SelectMany (t => t.GetAllTypes ()); + } + + static IEnumerable GetAllTypes (this TypeDefinition self) + { + yield return self; + + if (!self.HasNestedTypes) + yield break; + + foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ())) + yield return type; + } + + public static IEnumerable GetMethods (this TypeDefinition self) + { + return self.Methods.Where (m => !m.IsConstructor); + } + + public static IEnumerable GetConstructors (this TypeDefinition self) + { + return self.Methods.Where (m => m.IsConstructor); + } + + public static MethodDefinition GetTypeConstructor (this TypeDefinition self) + { + return self.GetConstructors ().FirstOrDefault (c => c.IsStatic); + } + + public static void SimplifyMacros (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + foreach (var instruction in self.Instructions) { + if (instruction.OpCode.OpCodeType != OpCodeType.Macro) + continue; + + switch (instruction.OpCode.Code) { + case Code.Ldarg_0: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (0)); + break; + case Code.Ldarg_1: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (1)); + break; + case Code.Ldarg_2: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (2)); + break; + case Code.Ldarg_3: + ExpandMacro (instruction, OpCodes.Ldarg, self.GetParameter (3)); + break; + case Code.Ldloc_0: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [0]); + break; + case Code.Ldloc_1: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [1]); + break; + case Code.Ldloc_2: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [2]); + break; + case Code.Ldloc_3: + ExpandMacro (instruction, OpCodes.Ldloc, self.Variables [3]); + break; + case Code.Stloc_0: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [0]); + break; + case Code.Stloc_1: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [1]); + break; + case Code.Stloc_2: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [2]); + break; + case Code.Stloc_3: + ExpandMacro (instruction, OpCodes.Stloc, self.Variables [3]); + break; + case Code.Ldarg_S: + instruction.OpCode = OpCodes.Ldarg; + break; + case Code.Ldarga_S: + instruction.OpCode = OpCodes.Ldarga; + break; + case Code.Starg_S: + instruction.OpCode = OpCodes.Starg; + break; + case Code.Ldloc_S: + instruction.OpCode = OpCodes.Ldloc; + break; + case Code.Ldloca_S: + instruction.OpCode = OpCodes.Ldloca; + break; + case Code.Stloc_S: + instruction.OpCode = OpCodes.Stloc; + break; + case Code.Ldc_I4_M1: + ExpandMacro (instruction, OpCodes.Ldc_I4, -1); + break; + case Code.Ldc_I4_0: + ExpandMacro (instruction, OpCodes.Ldc_I4, 0); + break; + case Code.Ldc_I4_1: + ExpandMacro (instruction, OpCodes.Ldc_I4, 1); + break; + case Code.Ldc_I4_2: + ExpandMacro (instruction, OpCodes.Ldc_I4, 2); + break; + case Code.Ldc_I4_3: + ExpandMacro (instruction, OpCodes.Ldc_I4, 3); + break; + case Code.Ldc_I4_4: + ExpandMacro (instruction, OpCodes.Ldc_I4, 4); + break; + case Code.Ldc_I4_5: + ExpandMacro (instruction, OpCodes.Ldc_I4, 5); + break; + case Code.Ldc_I4_6: + ExpandMacro (instruction, OpCodes.Ldc_I4, 6); + break; + case Code.Ldc_I4_7: + ExpandMacro (instruction, OpCodes.Ldc_I4, 7); + break; + case Code.Ldc_I4_8: + ExpandMacro (instruction, OpCodes.Ldc_I4, 8); + break; + case Code.Ldc_I4_S: + ExpandMacro (instruction, OpCodes.Ldc_I4, (int) (sbyte) instruction.Operand); + break; + case Code.Br_S: + instruction.OpCode = OpCodes.Br; + break; + case Code.Brfalse_S: + instruction.OpCode = OpCodes.Brfalse; + break; + case Code.Brtrue_S: + instruction.OpCode = OpCodes.Brtrue; + break; + case Code.Beq_S: + instruction.OpCode = OpCodes.Beq; + break; + case Code.Bge_S: + instruction.OpCode = OpCodes.Bge; + break; + case Code.Bgt_S: + instruction.OpCode = OpCodes.Bgt; + break; + case Code.Ble_S: + instruction.OpCode = OpCodes.Ble; + break; + case Code.Blt_S: + instruction.OpCode = OpCodes.Blt; + break; + case Code.Bne_Un_S: + instruction.OpCode = OpCodes.Bne_Un; + break; + case Code.Bge_Un_S: + instruction.OpCode = OpCodes.Bge_Un; + break; + case Code.Bgt_Un_S: + instruction.OpCode = OpCodes.Bgt_Un; + break; + case Code.Ble_Un_S: + instruction.OpCode = OpCodes.Ble_Un; + break; + case Code.Blt_Un_S: + instruction.OpCode = OpCodes.Blt_Un; + break; + case Code.Leave_S: + instruction.OpCode = OpCodes.Leave; + break; + } + } + } + + static void ExpandMacro (Instruction instruction, OpCode opcode, object operand) + { + instruction.OpCode = opcode; + instruction.Operand = operand; + } + + static void MakeMacro (Instruction instruction, OpCode opcode) + { + instruction.OpCode = opcode; + instruction.Operand = null; + } + + public static void OptimizeMacros (this MethodBody self) + { + if (self == null) + throw new ArgumentNullException ("self"); + + var method = self.Method; + + foreach (var instruction in self.Instructions) { + int index; + switch (instruction.OpCode.Code) { + case Code.Ldarg: + index = ((ParameterDefinition) instruction.Operand).Index; + if (index == -1 && instruction.Operand == self.ThisParameter) + index = 0; + else if (method.HasThis) + index++; + + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Ldarg_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldarg_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldarg_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldarg_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldarg_S, instruction.Operand); + break; + } + break; + case Code.Ldloc: + index = ((VariableDefinition) instruction.Operand).Index; + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Ldloc_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldloc_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldloc_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldloc_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldloc_S, instruction.Operand); + break; + } + break; + case Code.Stloc: + index = ((VariableDefinition) instruction.Operand).Index; + switch (index) { + case 0: + MakeMacro (instruction, OpCodes.Stloc_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Stloc_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Stloc_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Stloc_3); + break; + default: + if (index < 256) + ExpandMacro (instruction, OpCodes.Stloc_S, instruction.Operand); + break; + } + break; + case Code.Ldarga: + index = ((ParameterDefinition) instruction.Operand).Index; + if (index == -1 && instruction.Operand == self.ThisParameter) + index = 0; + else if (method.HasThis) + index++; + if (index < 256) + ExpandMacro (instruction, OpCodes.Ldarga_S, instruction.Operand); + break; + case Code.Ldloca: + if (((VariableDefinition) instruction.Operand).Index < 256) + ExpandMacro (instruction, OpCodes.Ldloca_S, instruction.Operand); + break; + case Code.Ldc_I4: + int i = (int) instruction.Operand; + switch (i) { + case -1: + MakeMacro (instruction, OpCodes.Ldc_I4_M1); + break; + case 0: + MakeMacro (instruction, OpCodes.Ldc_I4_0); + break; + case 1: + MakeMacro (instruction, OpCodes.Ldc_I4_1); + break; + case 2: + MakeMacro (instruction, OpCodes.Ldc_I4_2); + break; + case 3: + MakeMacro (instruction, OpCodes.Ldc_I4_3); + break; + case 4: + MakeMacro (instruction, OpCodes.Ldc_I4_4); + break; + case 5: + MakeMacro (instruction, OpCodes.Ldc_I4_5); + break; + case 6: + MakeMacro (instruction, OpCodes.Ldc_I4_6); + break; + case 7: + MakeMacro (instruction, OpCodes.Ldc_I4_7); + break; + case 8: + MakeMacro (instruction, OpCodes.Ldc_I4_8); + break; + default: + if (i >= -128 && i < 128) + ExpandMacro (instruction, OpCodes.Ldc_I4_S, (sbyte) i); + break; + } + break; + } + } + + OptimizeBranches (self); + } + + static void OptimizeBranches (MethodBody body) + { + ComputeOffsets (body); + + foreach (var instruction in body.Instructions) { + if (instruction.OpCode.OperandType != OperandType.InlineBrTarget) + continue; + + if (OptimizeBranch (instruction)) + ComputeOffsets (body); + } + } + + static bool OptimizeBranch (Instruction instruction) + { + var offset = ((Instruction) instruction.Operand).Offset - (instruction.Offset + instruction.OpCode.Size + 4); + if (!(offset >= -128 && offset <= 127)) + return false; + + switch (instruction.OpCode.Code) { + case Code.Br: + instruction.OpCode = OpCodes.Br_S; + break; + case Code.Brfalse: + instruction.OpCode = OpCodes.Brfalse_S; + break; + case Code.Brtrue: + instruction.OpCode = OpCodes.Brtrue_S; + break; + case Code.Beq: + instruction.OpCode = OpCodes.Beq_S; + break; + case Code.Bge: + instruction.OpCode = OpCodes.Bge_S; + break; + case Code.Bgt: + instruction.OpCode = OpCodes.Bgt_S; + break; + case Code.Ble: + instruction.OpCode = OpCodes.Ble_S; + break; + case Code.Blt: + instruction.OpCode = OpCodes.Blt_S; + break; + case Code.Bne_Un: + instruction.OpCode = OpCodes.Bne_Un_S; + break; + case Code.Bge_Un: + instruction.OpCode = OpCodes.Bge_Un_S; + break; + case Code.Bgt_Un: + instruction.OpCode = OpCodes.Bgt_Un_S; + break; + case Code.Ble_Un: + instruction.OpCode = OpCodes.Ble_Un_S; + break; + case Code.Blt_Un: + instruction.OpCode = OpCodes.Blt_Un_S; + break; + case Code.Leave: + instruction.OpCode = OpCodes.Leave_S; + break; + } + + return true; + } + + static void ComputeOffsets (MethodBody body) + { + var offset = 0; + foreach (var instruction in body.Instructions) { + instruction.Offset = offset; + offset += instruction.GetSize (); + } + } + + public static ParameterDefinition GetParameter (this MethodBody self, int index) + { + var method = self.Method; + + if (method.HasThis) { + if (index == 0) + return self.ThisParameter; + + index--; + } + + var parameters = method.Parameters; + + if (index < 0 || index >= parameters.Count) + return null; + + return parameters [index]; + } + + public static bool Implements (this TypeReference self, string interfaceName) + { + if (interfaceName == null) + throw new ArgumentNullException ("interfaceName"); + if (self == null) + return false; + + TypeDefinition type = self.Resolve (); + if (type == null) + return false; // not enough information available + + // special case, check if we implement ourselves + if (type.IsInterface && (type.FullName == interfaceName)) + return true; + + return Implements (type, interfaceName, (interfaceName.IndexOf ('`') >= 0)); + } + + public static bool Implements (TypeDefinition type, string interfaceName, bool generic) + { + while (type != null) { + // does the type implements it itself + if (type.HasInterfaces) { + foreach (var iface in type.Interfaces) { + string fullname = (generic) ? iface.InterfaceType.GetElementType ().FullName : iface.InterfaceType.FullName; + if (fullname == interfaceName) + return true; + //if not, then maybe one of its parent interfaces does + if (Implements (iface.InterfaceType.Resolve (), interfaceName, generic)) + return true; + } + } + + type = type.BaseType != null ? type.BaseType.Resolve () : null; + } + return false; + } + + public static bool Inherits (this TypeReference self, string @namespace, string name) + { + if (@namespace == null) + throw new ArgumentNullException ("namespace"); + if (name == null) + throw new ArgumentNullException ("name"); + if (self == null) + return false; + + TypeReference current = self.Resolve (); + while (current != null) { + if (current.Is (@namespace, name)) + return true; + if (current.Is ("System", "Object")) + return false; + + TypeDefinition td = current.Resolve (); + if (td == null) + return false; // could not resolve type + current = td.BaseType; + } + return false; + } + } +} diff --git a/src/Microsoft.Android.Sdk.ILLink/Mono.Tuner/Extensions.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Extensions.cs similarity index 92% rename from src/Microsoft.Android.Sdk.ILLink/Mono.Tuner/Extensions.cs rename to src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Extensions.cs index f6af83d8b95..3e3b312133b 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Mono.Tuner/Extensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Extensions.cs @@ -5,11 +5,10 @@ using Mono.Linker; -namespace Mono.Tuner -{ +namespace Mono.Tuner { + + public static partial class Extensions { - public static partial class Extensions - { public static bool TryGetLinkedAssembly (this LinkContext context, string name, out AssemblyDefinition assembly) { assembly = GetAssembly (context, name); diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Profile.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Profile.cs new file mode 100644 index 00000000000..54cfffa64f1 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Mono.Tuner/Profile.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; + +using Mono.Cecil; + +namespace Mono.Tuner { + + public abstract class Profile { + + static Profile current; + + public static Profile Current { + get { + if (current != null) + return current; + + current = CreateProfile ("MonoTouch"); + if (current != null) + return current; + + current = CreateProfile ("MonoDroid"); + if (current != null) + return current; + + current = CreateProfile ("MonoMac"); + if (current != null) + return current; + + throw new NotSupportedException ("No active profile"); + } + set { + current = value; + } + } + + static Profile CreateProfile (string name) + { + var type = Type.GetType (string.Format ("{0}.Tuner.{0}Profile", name)); + if (type == null) + return null; + + return (Profile) Activator.CreateInstance (type); + } + + public static bool IsSdkAssembly (AssemblyDefinition assembly) + { + return Current.IsSdk (assembly); + } + + public static bool IsSdkAssembly (string assemblyName) + { + return Current.IsSdk (assemblyName); + } + + public static bool IsProductAssembly (AssemblyDefinition assembly) + { + return Current.IsProduct (assembly); + } + + public static bool IsProductAssembly (string assemblyName) + { + return Current.IsProduct (assemblyName); + } + + protected virtual bool IsSdk (AssemblyDefinition assembly) + { + return IsSdk (assembly.Name.Name); + } + + protected virtual bool IsProduct (AssemblyDefinition assembly) + { + return IsProduct (assembly.Name.Name); + } + + protected abstract bool IsSdk (string assemblyName); + protected abstract bool IsProduct (string assemblyName); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocumentElement.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocumentElement.cs index 6b685a996c9..cf51a75094f 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocumentElement.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocumentElement.cs @@ -8,7 +8,6 @@ using Monodroid; using MonoDroid.Tuner; -using MonoDroid.Utils; using Java.Interop.Tools.Cecil; using Java.Interop.Tools.TypeNameMappings; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index c94ad582680..92132281396 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -51,195 +51,40 @@ - - Linker\Mono.Tuner\AdjustVisibility.cs - - - Linker\Mono.Tuner\CecilRocks.cs - - - Linker\Mono.Tuner\CheckVisibility.cs - - - Linker\Linker\Annotations.cs - - - Linker\Linker\AssemblyAction.cs - - - Linker\Linker\AssemblyResolver.cs - - - Linker\Linker\AssemblyUtilities.cs - - - Linker\Linker\I18nAssemblies.cs - - - Linker\Linker\Inflater.cs - - - Linker\Linker\IXApiVisitor.cs - - - Linker\Linker\LinkContext.cs - - - Linker\Linker\MethodAction.cs - - - Linker\Linker\MethodReferenceExtensions.cs - - - Linker\Linker\OutputException.cs - - - Linker\Linker\OverrideInformation.cs - - - Linker\Linker\Pipeline.cs - - - Linker\Linker\TypeNameParser.cs - - - Linker\Linker\TypePreserve.cs - - - Linker\Linker\TypeReferenceExtensions.cs - - - Linker\Linker\XApiReader.cs - - - Linker\Linker.Steps\BlacklistStep.cs - - - Linker\Linker.Steps\BaseStep.cs - - - Linker\Linker.Steps\CleanStep.cs - - - Linker\Linker.Steps\IStep.cs - - - Linker\Linker.Steps\LoadI18nAssemblies.cs - - - Linker\Linker.Steps\LoadReferencesStep.cs - - - Linker\Linker.Steps\OutputStep.cs - - - Linker\Linker.Steps\RegenerateGuidStep.cs - - - Linker\Linker.Steps\ResolveFromAssemblyStep.cs - - - Linker\Linker.Steps\ResolveFromXApiStep.cs - - - Linker\Linker.Steps\ResolveFromXmlStep.cs - - - Linker\Linker.Steps\ResolveStep.cs - - - Linker\Linker.Steps\TypeMapStep.cs - - - Linker\Linker.Steps\SweepStep.cs - - - Linker\Linker.Steps\MarkStep.cs - - - Linker\Linker.Steps\PreserveDependencyLookupStep.cs - - - Linker\Linker.Steps\BodySubstituterStep.cs - - - Linker\Linker\IDependencyRecorder.cs - - - Linker\Linker\IReflectionPatternRecorder.cs - - - Linker\Linker\LoggingReflectionPatternRecorder.cs - - - Linker\Linker\XmlDependencyRecorder.cs - - - Linker\Linker\LoadException.cs - - - Linker\Linker\MarkException.cs - - - Linker\Linker\ConsoleLogger.cs - - - Linker\Linker\ILogger.cs - - - Linker\Linker\Tracer.cs - - - Linker\Linker\MarkingHelpers.cs - - - Linker\Linker\KnownMembers.cs - - - Linker\Linker\MethodDefinitionExtensions.cs - - - Linker\Linker\MethodBodyScanner.cs - - - Linker\Linker\TypeDefinitionExtensions.cs - - - Linker\Linker\BCL.cs - - - Linker\Mono.Tuner\ApplyPreserveAttributeBase.cs - - - Linker\Mono.Tuner\Dispatcher.cs - - - Linker\Mono.Tuner\CustomizeActions.cs - - - Linker\Mono.Tuner\Extensions.cs - - - Linker\Mono.Tuner\FixModuleFlags.cs - - - Linker\Mono.Tuner\PreserveCrypto.cs - - - Linker\Mono.Tuner\PreserveSoapHttpClients.cs - - - Linker\Mono.Tuner\Profile.cs - - - Linker\Mono.Tuner\RemoveAttributesBase.cs - - - Linker\Mono.Tuner\RemoveResources.cs - - - Linker\Mono.Tuner\RemoveSecurity.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mono.Android\IntentFilterAttribute.cs @@ -258,21 +103,6 @@ Utilities\StringRocks.cs - - Linker\Mono.Tuner\FilterAttributes.cs - - - Linker\Mono.Tuner\InjectSecurityAttributes.cs - - - Linker\Mono.Tuner\PrintStatus.cs - - - Linker\Mono.Tuner\RemoveSerialization.cs - - - Linker\Mono.Tuner\TunerAnnotations.cs - Mono.Android\UsesLibraryAttribute.cs