diff options
author | Jb Evain <jbevain@gmail.com> | 2009-11-02 19:19:15 +0300 |
---|---|---|
committer | Jb Evain <jbevain@gmail.com> | 2009-11-02 19:19:15 +0300 |
commit | f21d6449faa5a005d769660de636a5b722ae4597 (patch) | |
tree | cc181700073c15646ada0de34bdb2257c7e9976d /mcs/tools | |
parent | 3e7cea123204e599765433d6c78b0a2521056d91 (diff) |
2009-11-02 Jb Evain <jbevain@novell.com>
Merge the MonoTouch Linker branch.
* monolinker.exe.sources: update
* Mono.Linker/Annotations.cs:
- add an preserved methods annotation on a type.
- add an annotation to get the base methods of a method.
- add an annotation to get the overriden method of a method.
* Mono.Linker/AssemblyAction.cs:
add a Delete action to remove an assembly from the output set.
* Mono.Linker.Steps/TypeMapStep.cs:
new step that create a map of virtual methods implementation.
* Mono.Linker.Steps/MarkStep.cs:
- removal of virtual methods.
- fix for custom attributes assigning properties and field
defined in a base type.
- mark scopes.
- mark default constructors of types used as a generic instance
of a generic parameter constrained with new().
- apply preserved methods.
* Mono.Linker.Steps/SweepStep.cs: remove unused assemblies.
* Mono.Linker.Steps/LoadI18nAssemblies.cs:
fix linking of i18n assemblies.
* Mono.Linker.Steps/OutputStep.cs:
fix the copied assemblies when the output directory
is the same as the origin of the assemblies.
* Mono.Linker.Steps/ResolveFromXmlStep.cs
* Mono.Linker.Steps/ResolveFromAssemblyStep.cs
* Mono.Linker.Steps/BaseStep.cs
* Mono.Linker/Driver.cs
* Mono.Linker/Pipeline.cs:
Cosmetics.
svn path=/branches/mono-2-6/mcs/; revision=145209
Diffstat (limited to 'mcs/tools')
-rw-r--r-- | mcs/tools/linker/ChangeLog | 42 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/BaseStep.cs | 4 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/LoadI18nAssemblies.cs | 2 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/MarkStep.cs | 224 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/OutputStep.cs | 19 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/ResolveFromAssemblyStep.cs | 2 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs | 2 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/SweepStep.cs | 61 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker.Steps/TypeMapStep.cs | 240 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker/Annotations.cs | 57 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker/AssemblyAction.cs | 3 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker/Driver.cs | 3 | ||||
-rw-r--r-- | mcs/tools/linker/Mono.Linker/Pipeline.cs | 3 | ||||
-rw-r--r-- | mcs/tools/linker/monolinker.exe.sources | 1 |
14 files changed, 614 insertions, 49 deletions
diff --git a/mcs/tools/linker/ChangeLog b/mcs/tools/linker/ChangeLog index f7dc1b39b0e..6b2dd5e0c69 100644 --- a/mcs/tools/linker/ChangeLog +++ b/mcs/tools/linker/ChangeLog @@ -1,3 +1,45 @@ +2009-11-02 Jb Evain <jbevain@novell.com> + + Merge the MonoTouch Linker branch. + + * monolinker.exe.sources: update + + * Mono.Linker/Annotations.cs: + - add an preserved methods annotation on a type. + - add an annotation to get the base methods of a method. + - add an annotation to get the overriden method of a method. + + * Mono.Linker/AssemblyAction.cs: + add a Delete action to remove an assembly from the output set. + + * Mono.Linker.Steps/TypeMapStep.cs: + new step that create a map of virtual methods implementation. + + * Mono.Linker.Steps/MarkStep.cs: + - removal of virtual methods. + - fix for custom attributes assigning properties and field + defined in a base type. + - mark scopes. + - mark default constructors of types used as a generic instance + of a generic parameter constrained with new(). + - apply preserved methods. + + * Mono.Linker.Steps/SweepStep.cs: remove unused assemblies. + + * Mono.Linker.Steps/LoadI18nAssemblies.cs: + fix linking of i18n assemblies. + + * Mono.Linker.Steps/OutputStep.cs: + fix the copied assemblies when the output directory + is the same as the origin of the assemblies. + + * Mono.Linker.Steps/ResolveFromXmlStep.cs + * Mono.Linker.Steps/ResolveFromAssemblyStep.cs + * Mono.Linker.Steps/BaseStep.cs + * Mono.Linker/Driver.cs + * Mono.Linker/Pipeline.cs: + Cosmetics. + 2009-09-10 Andrés G. Aragoneses <aaragoneses@novell.com> * Mono.Linker.Steps/MarkStep.cs: Make IgnoreScope() virtual to diff --git a/mcs/tools/linker/Mono.Linker.Steps/BaseStep.cs b/mcs/tools/linker/Mono.Linker.Steps/BaseStep.cs index 40eda6109aa..696740ecd4b 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/BaseStep.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/BaseStep.cs @@ -49,7 +49,7 @@ namespace Mono.Linker.Steps { foreach (AssemblyDefinition assembly in context.GetAssemblies ()) ProcessAssembly (assembly); - + EndProcess (); } @@ -61,7 +61,7 @@ namespace Mono.Linker.Steps { protected virtual void Process () { } - + protected virtual void EndProcess () { } diff --git a/mcs/tools/linker/Mono.Linker.Steps/LoadI18nAssemblies.cs b/mcs/tools/linker/Mono.Linker.Steps/LoadI18nAssemblies.cs index f45f05709ed..c8256a5c720 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/LoadI18nAssemblies.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/LoadI18nAssemblies.cs @@ -77,7 +77,7 @@ namespace Mono.Linker.Steps { void LoadAssembly (AssemblyNameReference name) { AssemblyDefinition assembly = Context.Resolve (name); - Annotations.SetAction (assembly, AssemblyAction.Copy); + ResolveFromAssemblyStep.ProcessLibrary (assembly); } AssemblyNameReference GetAssemblyName (I18nAssemblies assembly) diff --git a/mcs/tools/linker/Mono.Linker.Steps/MarkStep.cs b/mcs/tools/linker/Mono.Linker.Steps/MarkStep.cs index fa6ddc61aad..f68d6039d27 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/MarkStep.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/MarkStep.cs @@ -37,11 +37,13 @@ namespace Mono.Linker.Steps { public class MarkStep : IStep { LinkContext _context; - Queue _queue; + Queue _methods; + ArrayList _virtual_methods; public MarkStep () { - _queue = new Queue (); + _methods = new Queue (); + _virtual_methods = new ArrayList (); } public void Process (LinkContext context) @@ -92,7 +94,7 @@ namespace Mono.Linker.Steps { { foreach (MethodDefinition method in methods) if (Annotations.IsMarked (method)) - _queue.Enqueue (method); + EnqueueMethod (method); } void Process () @@ -101,19 +103,58 @@ namespace Mono.Linker.Steps { throw new InvalidOperationException ("No entry methods"); while (!QueueIsEmpty ()) { - MethodDefinition method = (MethodDefinition) _queue.Dequeue (); + ProcessQueue (); + ProcessVirtualMethods (); + } + } + + void ProcessQueue () + { + while (!QueueIsEmpty ()) { + MethodDefinition method = (MethodDefinition) _methods.Dequeue (); ProcessMethod (method); } } bool QueueIsEmpty () { - return _queue.Count == 0; + return _methods.Count == 0; } protected virtual void EnqueueMethod (MethodDefinition method) { - _queue.Enqueue (method); + _methods.Enqueue (method); + } + + void ProcessVirtualMethods () + { + foreach (MethodDefinition method in _virtual_methods) + ProcessVirtualMethod (method); + } + + void ProcessVirtualMethod (MethodDefinition method) + { + IList overrides = Annotations.GetOverrides (method); + if (overrides == null) + return; + + foreach (MethodDefinition @override in overrides) + ProcessOverride (@override); + } + + void ProcessOverride (MethodDefinition method) + { + if (!Annotations.IsMarked (method.DeclaringType)) + return; + + if (Annotations.IsProcessed (method)) + return; + + if (Annotations.IsMarked (method)) + return; + + MarkMethod (method); + ProcessVirtualMethod (method); } void MarkMethodBody (MethodBody body) @@ -176,22 +217,34 @@ namespace Mono.Linker.Steps { foreach (DictionaryEntry de in ca.Properties) { string propertyname = (string) de.Key; - PropertyDefinition [] properties = attribute.Properties.GetProperties (propertyname); - - if (properties != null && properties.Length != 0 && properties [0].SetMethod != null) - MarkMethod (properties [0].SetMethod); + PropertyDefinition property = GetProperty (attribute, propertyname); + if (property != null) + MarkMethod (property.SetMethod); TypeReference propType = ca.GetPropertyType (propertyname); MarkIfType (propType, de.Value); } } + PropertyDefinition GetProperty (TypeDefinition type, string propertyname) + { + while (type != null) { + PropertyDefinition [] properties = type.Properties.GetProperties (propertyname); + if (properties != null && properties.Length != 0 && properties [0].SetMethod != null) + return properties [0]; + + type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null; + } + + return null; + } + void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute) { foreach (DictionaryEntry de in ca.Fields) { string fieldname = (string) de.Key; - FieldDefinition field = attribute.Fields.GetField (fieldname); + FieldDefinition field = GetField (attribute, fieldname); if (field != null) MarkField (field); @@ -200,6 +253,19 @@ namespace Mono.Linker.Steps { } } + FieldDefinition GetField (TypeDefinition type, string fieldname) + { + while (type != null) { + FieldDefinition field = type.Fields.GetField (fieldname); + if (field != null) + return field; + + type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null; + } + + return null; + } + void MarkCustomAttributeParameters (CustomAttribute ca) { for (int i = 0; i < ca.Constructor.Parameters.Count; i++) { @@ -240,8 +306,8 @@ namespace Mono.Linker.Steps { void MarkField (FieldReference reference) { - if (IgnoreScope (reference.DeclaringType.Scope)) - return; +// if (IgnoreScope (reference.DeclaringType.Scope)) +// return; FieldDefinition field = ResolveFieldDefinition (reference); @@ -274,6 +340,15 @@ namespace Mono.Linker.Steps { return fd; } + void MarkScope (IMetadataScope scope) + { + IAnnotationProvider provider = scope as IAnnotationProvider; + if (provider == null) + return; + + Annotations.Mark (provider); + } + protected virtual void MarkType (TypeReference reference) { if (reference == null) @@ -284,8 +359,8 @@ namespace Mono.Linker.Steps { if (reference is GenericParameter) return; - if (IgnoreScope (reference.Scope)) - return; +// if (IgnoreScope (reference.Scope)) +// return; TypeDefinition type = ResolveTypeDefinition (reference); @@ -295,12 +370,15 @@ namespace Mono.Linker.Steps { if (CheckProcessed (type)) return; + MarkScope (type.Scope); MarkType (type.BaseType); MarkType (type.DeclaringType); - MarkCustomAttributes(type); + MarkCustomAttributes (type); - if (IsMulticastDelegate (type)) + if (IsMulticastDelegate (type)) { MarkMethodCollection (type.Constructors); + MarkMethodCollection (type.Methods); + } if (IsSerializable (type) && type.HasConstructors) { MarkMethodsIf (type.Constructors, IsDefaultConstructorPredicate); @@ -317,12 +395,12 @@ namespace Mono.Linker.Steps { MarkType (iface); } + if (type.HasMethods) + MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent); + if (type.HasConstructors) MarkMethodsIf (type.Constructors, IsStaticConstructorPredicate); - if (type.HasMethods) - MarkMethodsIf (type.Methods, IsVirtualPredicate); - Annotations.Mark (type); ApplyPreserveInfo (type); @@ -344,6 +422,26 @@ namespace Mono.Linker.Steps { MarkType (constraint); } + bool IsVirtualAndHasPreservedParent (MethodDefinition method) + { + if (!method.IsVirtual) + return false; + + var base_list = Annotations.GetBaseMethods (method); + if (base_list == null) + return false; + + foreach (MethodDefinition @base in base_list) { + if (IgnoreScope (@base.DeclaringType.Scope)) + return true; + + if (IsVirtualAndHasPreservedParent (@base)) + return true; + } + + return false; + } + static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor); static bool IsSpecialSerializationConstructor (MethodDefinition method) @@ -381,13 +479,6 @@ namespace Mono.Linker.Steps { method.IsRuntimeSpecialName; } - static MethodPredicate IsVirtualPredicate = new MethodPredicate (IsVirtual); - - static bool IsVirtual (MethodDefinition method) - { - return method.IsVirtual; - } - static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor); static bool IsStaticConstructor (MethodDefinition method) @@ -441,10 +532,55 @@ namespace Mono.Linker.Steps { { foreach (TypeReference argument in instance.GenericArguments) MarkType (argument); + + MarkGenericArgumentConstructors (instance); + } + + void MarkGenericArgumentConstructors (IGenericInstance instance) + { + var arguments = instance.GenericArguments; + + var generic_element = GetGenericProviderFromInstance (instance); + if (generic_element == null) + return; + + var parameters = generic_element.GenericParameters; + + if (arguments.Count != parameters.Count) + return; + + for (int i = 0; i < arguments.Count; i++) { + var argument = arguments [i]; + var parameter = parameters [i]; + + if (!parameter.HasDefaultConstructorConstraint) + continue; + + var argument_definition = ResolveTypeDefinition (argument); + if (argument_definition == null) + continue; + + MarkMethodsIf (argument_definition.Constructors, ctor => !ctor.IsStatic && !ctor.HasParameters); + } + } + + IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance) + { + var method = instance as GenericInstanceMethod; + if (method != null) + return method.ElementMethod; + + var type = instance as GenericInstanceType; + if (type != null) + return type.ElementType; + + return null; } void ApplyPreserveInfo (TypeDefinition type) { + ApplyPreserveMethods (type); + if (!Annotations.IsPreserved (type)) return; @@ -462,6 +598,16 @@ namespace Mono.Linker.Steps { } } + void ApplyPreserveMethods (TypeDefinition type) + { + var list = Annotations.GetPreservedMethods (type); + if (list == null) + return; + + foreach (MethodDefinition method in list) + MarkMethod (method); + } + void MarkFields (TypeDefinition type) { if (!type.HasFields) @@ -492,15 +638,16 @@ namespace Mono.Linker.Steps { if (reference.DeclaringType is ArrayType) return; - if (IgnoreScope (reference.DeclaringType.Scope)) - return; +// if (IgnoreScope (reference.DeclaringType.Scope)) +// return; MethodDefinition method = ResolveMethodDefinition (reference); if (method == null) throw new ResolutionException (reference); - Annotations.SetAction (method, MethodAction.Parse); + if (Annotations.GetAction (method) == MethodAction.Nothing) + Annotations.SetAction (method, MethodAction.Parse); EnqueueMethod (method); } @@ -562,6 +709,11 @@ namespace Mono.Linker.Steps { MarkMethod (ov); } + if (method.IsVirtual) + _virtual_methods.Add (method); + + MarkBaseMethods (method); + MarkType (method.ReturnType.ReturnType); MarkCustomAttributes (method.ReturnType); MarkMarshalSpec (method.ReturnType); @@ -572,6 +724,18 @@ namespace Mono.Linker.Steps { Annotations.Mark (method); } + void MarkBaseMethods (MethodDefinition method) + { + IList base_methods = Annotations.GetBaseMethods (method); + if (base_methods == null) + return; + + foreach (MethodDefinition base_method in base_methods) { + MarkMethod (base_method); + MarkBaseMethods (base_method); + } + } + bool ShouldParseMethodBody (MethodDefinition method) { if (!method.HasBody) diff --git a/mcs/tools/linker/Mono.Linker.Steps/OutputStep.cs b/mcs/tools/linker/Mono.Linker.Steps/OutputStep.cs index 35c1d13ffea..55114991ccb 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/OutputStep.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/OutputStep.cs @@ -26,6 +26,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; using System.IO; using Mono.Cecil; @@ -58,6 +59,8 @@ namespace Mono.Linker.Steps { CopyConfigFileIfNeeded (assembly, directory); + Console.WriteLine ("Output {0} : {1}", assembly, Annotations.GetAction (assembly)); + switch (Annotations.GetAction (assembly)) { case AssemblyAction.Link: SaveSymbols (assembly); @@ -66,6 +69,11 @@ namespace Mono.Linker.Steps { case AssemblyAction.Copy: CopyAssembly (GetOriginalAssemblyFileInfo (assembly), directory); break; + case AssemblyAction.Delete: + var target = GetAssemblyFileName (assembly, directory); + if (File.Exists (target)) + File.Delete (target); + break; } } @@ -86,6 +94,11 @@ namespace Mono.Linker.Steps { if (!File.Exists (config)) return; + string target = Path.GetFullPath (GetConfigFile (GetAssemblyFileName (assembly, directory))); + + if (config == target) + return; + File.Copy (config, GetConfigFile (GetAssemblyFileName (assembly, directory)), true); } @@ -101,7 +114,11 @@ namespace Mono.Linker.Steps { static void CopyAssembly (FileInfo fi, string directory) { - File.Copy (fi.FullName, Path.Combine (directory, fi.Name), true); + string target = Path.GetFullPath (Path.Combine (directory, fi.Name)); + if (fi.FullName == target) + return; + + File.Copy (fi.FullName, target, true); } static string GetAssemblyFileName (AssemblyDefinition assembly, string directory) diff --git a/mcs/tools/linker/Mono.Linker.Steps/ResolveFromAssemblyStep.cs b/mcs/tools/linker/Mono.Linker.Steps/ResolveFromAssemblyStep.cs index 55dfa7d1b96..5cb5614b2b9 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/ResolveFromAssemblyStep.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/ResolveFromAssemblyStep.cs @@ -54,7 +54,7 @@ namespace Mono.Linker.Steps { } } - static void ProcessLibrary (AssemblyDefinition assembly) + public static void ProcessLibrary (AssemblyDefinition assembly) { Annotations.SetAction (assembly, AssemblyAction.Copy); diff --git a/mcs/tools/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs b/mcs/tools/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs index 6a749341508..ee16fa18b69 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs @@ -264,7 +264,7 @@ namespace Mono.Linker.Steps { MarkMethod (type, meth, signature); } - private void MarkMethod (TypeDefinition type, MethodDefinition method, string signature) + void MarkMethod (TypeDefinition type, MethodDefinition method, string signature) { if (method != null) { Annotations.Mark (method); diff --git a/mcs/tools/linker/Mono.Linker.Steps/SweepStep.cs b/mcs/tools/linker/Mono.Linker.Steps/SweepStep.cs index 9ef6d4db043..736f43de6fb 100644 --- a/mcs/tools/linker/Mono.Linker.Steps/SweepStep.cs +++ b/mcs/tools/linker/Mono.Linker.Steps/SweepStep.cs @@ -45,6 +45,11 @@ namespace Mono.Linker.Steps { if (Annotations.GetAction (assembly) != AssemblyAction.Link) return; + if (!IsMarkedAssembly (assembly)) { + RemoveAssembly (assembly); + return; + } + foreach (TypeDefinition type in Clone (assembly.MainModule.Types)) { if (Annotations.IsMarked (type)) { SweepType (type); @@ -56,6 +61,37 @@ namespace Mono.Linker.Steps { } } + static bool IsMarkedAssembly (AssemblyDefinition assembly) + { + return Annotations.IsMarked (assembly.MainModule); + } + + void RemoveAssembly (AssemblyDefinition assembly) + { + Annotations.SetAction (assembly, AssemblyAction.Delete); + + SweepReferences (assembly); + } + + void SweepReferences (AssemblyDefinition target) + { + foreach (var assembly in Context.GetAssemblies ()) + SweepReferences (assembly, target); + } + + void SweepReferences (AssemblyDefinition assembly, AssemblyDefinition target) + { + var references = assembly.MainModule.AssemblyReferences; + for (int i = 0; i < references.Count; i++) { + var reference = references [i]; + if (reference.FullName != target.Name.FullName) + continue; + + references.RemoveAt (i); + return; + } + } + static ICollection Clone (ICollection collection) { return new ArrayList (collection); @@ -78,9 +114,11 @@ namespace Mono.Linker.Steps { static void SweepMemberReferences (ModuleDefinition module, TypeReference reference) { - foreach (MemberReference member in Clone (module.MemberReferences)) { - if (member.DeclaringType == reference) - module.MemberReferences.Remove (member); + var references = module.MemberReferences; + + for (int i = 0; i < references.Count; i++) { + if (references [i].DeclaringType == reference) + references.RemoveAt (i--); } } @@ -95,16 +133,21 @@ namespace Mono.Linker.Steps { static void SweepType (TypeDefinition type) { - SweepCollection (type.Fields); - SweepCollection (type.Constructors); - SweepCollection (type.Methods); + if (type.HasFields) + SweepCollection (type.Fields); + + if (type.HasConstructors) + SweepCollection (type.Constructors); + + if (type.HasMethods) + SweepCollection (type.Methods); } static void SweepCollection (IList list) { - foreach (IAnnotationProvider provider in Clone (list)) - if (!Annotations.IsMarked (provider)) - list.Remove (provider); + for (int i = 0; i < list.Count; i++) + if (!Annotations.IsMarked ((IAnnotationProvider) list [i])) + list.RemoveAt (i--); } } } diff --git a/mcs/tools/linker/Mono.Linker.Steps/TypeMapStep.cs b/mcs/tools/linker/Mono.Linker.Steps/TypeMapStep.cs new file mode 100644 index 00000000000..f92b242bda6 --- /dev/null +++ b/mcs/tools/linker/Mono.Linker.Steps/TypeMapStep.cs @@ -0,0 +1,240 @@ +// +// TypeMapStep.cs +// +// Author: +// Jb Evain (jbevain@novell.com) +// +// (C) 2009 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; + +using Mono.Cecil; + +namespace Mono.Linker.Steps { + + public class TypeMapStep : BaseStep { + + protected override void ProcessAssembly (AssemblyDefinition assembly) + { + foreach (TypeDefinition type in assembly.MainModule.Types) + MapType (type); + } + + static void MapType (TypeDefinition type) + { + MapVirtualMethods (type); + } + + static void MapVirtualMethods (TypeDefinition type) + { + if (!type.HasMethods) + return; + + foreach (MethodDefinition method in type.Methods) { + if (!method.IsVirtual) + continue; + + MapVirtualMethod (method); + + if (method.HasOverrides) + MapOverrides (method); + } + } + + static void MapVirtualMethod (MethodDefinition method) + { + MapVirtualBaseMethod (method); + MapVirtualInterfaceMethod (method); + } + + static void MapVirtualBaseMethod (MethodDefinition method) + { + MethodDefinition @base = GetBaseMethodInTypeHierarchy (method); + if (@base == null) + return; + + AnnotateMethods (@base, method); + } + + static void MapVirtualInterfaceMethod (MethodDefinition method) + { + MethodDefinition @base = GetBaseMethodInInterfaceHierarchy (method); + if (@base == null) + return; + + AnnotateMethods (@base, method); + } + + static void MapOverrides (MethodDefinition method) + { + foreach (MethodReference override_ref in method.Overrides) { + MethodDefinition @override = override_ref.Resolve (); + if (@override == null) + continue; + + AnnotateMethods (@override, method); + } + } + + static void AnnotateMethods (MethodDefinition @base, MethodDefinition @override) + { + Annotations.AddBaseMethod (@override, @base); + Annotations.AddOverride (@base, @override); + } + + static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method) + { + TypeDefinition @base = GetBaseType (method.DeclaringType); + while (@base != null) { + MethodDefinition base_method = TryMatchMethod (@base, method); + if (base_method != null) + return base_method; + + @base = GetBaseType (@base); + } + + return null; + } + + static MethodDefinition GetBaseMethodInInterfaceHierarchy (MethodDefinition method) + { + return GetBaseMethodInInterfaceHierarchy (method.DeclaringType, method); + } + + static MethodDefinition GetBaseMethodInInterfaceHierarchy (TypeDefinition type, MethodDefinition method) + { + if (!type.HasInterfaces) + return null; + + foreach (TypeReference interface_ref in type.Interfaces) { + TypeDefinition @interface = interface_ref.Resolve (); + if (@interface == null) + continue; + + MethodDefinition base_method = TryMatchMethod (@interface, method); + if (base_method != null) + return base_method; + + base_method = GetBaseMethodInInterfaceHierarchy (@interface, method); + if (base_method != null) + return base_method; + } + + return null; + } + + static MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method) + { + if (!type.HasMethods) + return null; + + foreach (MethodDefinition candidate in type.Methods) + if (MethodMatch (candidate, method)) + return candidate; + + return null; + } + + static bool MethodMatch (MethodDefinition candidate, MethodDefinition method) + { + if (!candidate.IsVirtual) + return false; + + if (candidate.Name != method.Name) + return false; + + if (!TypeMatch (candidate.ReturnType.ReturnType, method.ReturnType.ReturnType)) + return false; + + if (candidate.Parameters.Count != method.Parameters.Count) + return false; + + for (int i = 0; i < candidate.Parameters.Count; i++) + if (!TypeMatch (candidate.Parameters [i].ParameterType, method.Parameters [i].ParameterType)) + return false; + + return true; + } + + static bool TypeMatch (ModType a, ModType b) + { + if (!TypeMatch (a.ModifierType, b.ModifierType)) + return false; + + return TypeMatch (a.ElementType, b.ElementType); + } + + static bool TypeMatch (TypeSpecification a, TypeSpecification b) + { + if (a is GenericInstanceType) + return TypeMatch ((GenericInstanceType) a, (GenericInstanceType) b); + + if (a is ModType) + return TypeMatch ((ModType) a, (ModType) b); + + return TypeMatch (a.ElementType, b.ElementType); + } + + static bool TypeMatch (GenericInstanceType a, GenericInstanceType b) + { + if (!TypeMatch (a.ElementType, b.ElementType)) + return false; + + if (a.GenericArguments.Count != b.GenericArguments.Count) + return false; + + if (a.GenericArguments.Count == 0) + return true; + + for (int i = 0; i < a.GenericArguments.Count; i++) + if (!TypeMatch (a.GenericArguments [i], b.GenericArguments [i])) + return false; + + return true; + } + + static bool TypeMatch (TypeReference a, TypeReference b) + { + if (a is GenericParameter) + return true; + + if (a is TypeSpecification || b is TypeSpecification) { + if (a.GetType () != b.GetType ()) + return false; + + return TypeMatch ((TypeSpecification) a, (TypeSpecification) b); + } + + return a.FullName == b.FullName; + } + + static TypeDefinition GetBaseType (TypeDefinition type) + { + if (type == null || type.BaseType == null) + return null; + + return type.BaseType.Resolve (); + } + } +} diff --git a/mcs/tools/linker/Mono.Linker/Annotations.cs b/mcs/tools/linker/Mono.Linker/Annotations.cs index 635e174c2a4..55330d3e276 100644 --- a/mcs/tools/linker/Mono.Linker/Annotations.cs +++ b/mcs/tools/linker/Mono.Linker/Annotations.cs @@ -26,6 +26,9 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System; +using System.Collections; + using Mono.Cecil; namespace Mono.Linker { @@ -36,8 +39,11 @@ namespace Mono.Linker { private static readonly object _markedKey = new object (); private static readonly object _processedKey = new object (); private static readonly object _preservedKey = new object (); + private static readonly object _preservedMethodsKey = new object (); private static readonly object _publicKey = new object (); private static readonly object _symbolsKey = new object (); + private static readonly object _overrideKey = new object (); + private static readonly object _baseKey = new object (); public static AssemblyAction GetAction (AssemblyDefinition assembly) { @@ -46,7 +52,8 @@ namespace Mono.Linker { public static MethodAction GetAction (MethodDefinition method) { - return (MethodAction) GetAction (AsProvider (method)); + var action = GetAction (AsProvider (method)); + return action == null ? MethodAction.Nothing : (MethodAction) action; } static object GetAction (IAnnotationProvider provider) @@ -134,6 +141,54 @@ namespace Mono.Linker { AsProvider (assembly).Annotations [_symbolsKey] = _symbolsKey; } + public static void AddOverride (MethodDefinition @base, MethodDefinition @override) + { + ArrayList methods = (ArrayList) GetOverrides (@base); + if (methods == null) { + methods = new ArrayList (); + AsProvider (@base).Annotations.Add (_overrideKey, methods); + } + + methods.Add (@override); + } + + public static IList GetOverrides (MethodDefinition method) + { + return (IList) AsProvider (method).Annotations [_overrideKey]; + } + + public static void AddBaseMethod (MethodDefinition method, MethodDefinition @base) + { + ArrayList methods = (ArrayList) GetBaseMethods (method); + if (methods == null) { + methods = new ArrayList (); + AsProvider (method).Annotations.Add (_baseKey, methods); + } + + methods.Add (@base); + } + + public static IList GetBaseMethods (MethodDefinition method) + { + return (IList) AsProvider (method).Annotations [_baseKey]; + } + + public static IList GetPreservedMethods (TypeDefinition type) + { + return (IList) AsProvider (type).Annotations [_preservedMethodsKey]; + } + + public static void AddPreservedMethod (TypeDefinition type, MethodDefinition method) + { + ArrayList methods = (ArrayList) GetPreservedMethods (type); + if (methods == null) { + methods = new ArrayList (); + AsProvider (type).Annotations.Add (_preservedMethodsKey, methods); + } + + methods.Add (method); + } + private Annotations () { } diff --git a/mcs/tools/linker/Mono.Linker/AssemblyAction.cs b/mcs/tools/linker/Mono.Linker/AssemblyAction.cs index 9d675f23e4a..8eac19e5e48 100644 --- a/mcs/tools/linker/Mono.Linker/AssemblyAction.cs +++ b/mcs/tools/linker/Mono.Linker/AssemblyAction.cs @@ -31,6 +31,7 @@ namespace Mono.Linker { public enum AssemblyAction { Skip, Copy, - Link + Link, + Delete, } } diff --git a/mcs/tools/linker/Mono.Linker/Driver.cs b/mcs/tools/linker/Mono.Linker/Driver.cs index eb99a9fcd96..7d1963cc3db 100644 --- a/mcs/tools/linker/Mono.Linker/Driver.cs +++ b/mcs/tools/linker/Mono.Linker/Driver.cs @@ -163,7 +163,7 @@ namespace Mono.Linker { foreach (string custom_step in custom_steps) AddCustomStep (p, custom_step); - + p.AddStepAfter (typeof (LoadReferencesStep), new LoadI18nAssemblies (assemblies)); p.Process (context); @@ -310,6 +310,7 @@ namespace Mono.Linker { Pipeline p = new Pipeline (); p.AppendStep (new LoadReferencesStep ()); p.AppendStep (new BlacklistStep ()); + p.AppendStep (new TypeMapStep ()); p.AppendStep (new MarkStep ()); p.AppendStep (new SweepStep ()); p.AppendStep (new CleanStep ()); diff --git a/mcs/tools/linker/Mono.Linker/Pipeline.cs b/mcs/tools/linker/Mono.Linker/Pipeline.cs index f528ddf46a2..7c2b120d4ec 100644 --- a/mcs/tools/linker/Mono.Linker/Pipeline.cs +++ b/mcs/tools/linker/Mono.Linker/Pipeline.cs @@ -61,7 +61,7 @@ namespace Mono.Linker { } } } - + public void ReplaceStep (Type target, IStep step) { AddStepBefore (target, step); @@ -96,6 +96,7 @@ namespace Mono.Linker { { while (_steps.Count > 0) { IStep step = (IStep) _steps [0]; + Console.WriteLine ("Processing {0}", step.GetType ()); step.Process (context); _steps.Remove (step); } diff --git a/mcs/tools/linker/monolinker.exe.sources b/mcs/tools/linker/monolinker.exe.sources index 24b25f13d1e..588cf4ae490 100644 --- a/mcs/tools/linker/monolinker.exe.sources +++ b/mcs/tools/linker/monolinker.exe.sources @@ -24,4 +24,5 @@ ./Mono.Linker.Steps/MarkStep.cs ./Mono.Linker.Steps/BlacklistStep.cs ./Mono.Linker.Steps/OutputStep.cs +./Mono.Linker.Steps/TypeMapStep.cs ./Mono.Linker.Steps/IStep.cs |