update tuner
authorJb Evain <jbevain@gmail.com>
Sat, 4 Jun 2011 10:38:41 +0000 (12:38 +0200)
committerJb Evain <jbevain@gmail.com>
Sat, 4 Jun 2011 10:40:16 +0000 (12:40 +0200)
14 files changed:
mcs/tools/tuner/Mono.Tuner/ApplyPreserveAttributeBase.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/CecilRocks.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/CustomizeActions.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/Dispatcher.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/Extensions.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/FixModuleFlags.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/PreserveCrypto.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/PreserveHttps.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/PreserveSoapHttpClients.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/PrintTypeMap.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/Profile.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/RemoveAttributesBase.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/RemoveResources.cs [new file with mode: 0644]
mcs/tools/tuner/Mono.Tuner/RemoveSecurity.cs [new file with mode: 0644]

diff --git a/mcs/tools/tuner/Mono.Tuner/ApplyPreserveAttributeBase.cs b/mcs/tools/tuner/Mono.Tuner/ApplyPreserveAttributeBase.cs
new file mode 100644 (file)
index 0000000..3ac17d0
--- /dev/null
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public abstract class ApplyPreserveAttributeBase : BaseSubStep {
+
+               protected abstract string PreserveAttribute { get; }
+
+               public override SubStepTargets Targets {
+                       get {
+                               return SubStepTargets.Type
+                                       | SubStepTargets.Field
+                                       | SubStepTargets.Method
+                                       | SubStepTargets.Property
+                                       | SubStepTargets.Event;
+                       }
+               }
+
+               public override bool IsActiveFor (AssemblyDefinition assembly)
+               {
+                       return !Profile.IsSdkAssembly (assembly) && Annotations.GetAction (assembly) == AssemblyAction.Link;
+               }
+
+               public override void ProcessType (TypeDefinition type)
+               {
+                       TryApplyPreserveAttribute (type);
+               }
+
+               public override void ProcessField (FieldDefinition field)
+               {
+                       var attribute = GetPreserveAttribute (field);
+                       if (attribute == null)
+                               return;
+
+                       Mark (field, attribute);
+               }
+
+               public override void ProcessMethod (MethodDefinition method)
+               {
+                       MarkMethodIfPreserved (method);
+               }
+
+               public override void ProcessProperty (PropertyDefinition property)
+               {
+                       var attribute = GetPreserveAttribute (property);
+                       if (attribute == null)
+                               return;
+
+                       MarkMethod (property.GetMethod, attribute);
+                       MarkMethod (property.SetMethod, attribute);
+               }
+
+               public override void ProcessEvent (EventDefinition @event)
+               {
+                       var attribute = GetPreserveAttribute (@event);
+                       if (attribute == null)
+                               return;
+
+                       MarkMethod (@event.AddMethod, attribute);
+                       MarkMethod (@event.InvokeMethod, attribute);
+                       MarkMethod (@event.RemoveMethod, attribute);
+               }
+
+               void MarkMethodIfPreserved (MethodDefinition method)
+               {
+                       var attribute = GetPreserveAttribute (method);
+                       if (attribute == null)
+                               return;
+
+                       MarkMethod (method, attribute);
+               }
+
+               void MarkMethod (MethodDefinition method, CustomAttribute preserve_attribute)
+               {
+                       if (method == null)
+                               return;
+
+                       Mark (method, preserve_attribute);
+                       Annotations.SetAction (method, MethodAction.Parse);
+               }
+
+               void Mark (IMetadataTokenProvider provider, CustomAttribute preserve_attribute)
+               {
+                       if (IsConditionalAttribute (preserve_attribute)) {
+                               PreserveConditional (provider);
+                               return;
+                       }
+
+                       PreserveUnconditional (provider);
+               }
+
+               void PreserveConditional (IMetadataTokenProvider provider)
+               {
+                       var method = provider as MethodDefinition;
+                       if (method == null)
+                               return;
+
+                       Annotations.AddPreservedMethod (method.DeclaringType, method);
+               }
+
+               static bool IsConditionalAttribute (CustomAttribute attribute)
+               {
+                       if (attribute == null)
+                               return false;
+
+                       foreach (var named_argument in attribute.Fields)
+                               if (named_argument.Name == "Conditional")
+                                       return (bool) named_argument.Argument.Value;
+
+                       return false;
+               }
+
+               void PreserveUnconditional (IMetadataTokenProvider provider)
+               {
+                       Annotations.Mark (provider);
+
+                       var member = provider as IMemberDefinition;
+                       if (member == null || member.DeclaringType == null)
+                               return;
+
+                       Mark (member.DeclaringType, null);
+               }
+
+               void TryApplyPreserveAttribute (TypeDefinition type)
+               {
+                       var attribute = GetPreserveAttribute (type);
+                       if (attribute == null)
+                               return;
+
+                       Annotations.Mark (type);
+
+                       foreach (var named_argument in attribute.Fields)
+                               if (named_argument.Name == "AllMembers" && (bool) named_argument.Argument.Value)
+                                       Annotations.SetPreserve (type, TypePreserve.All);
+               }
+
+               CustomAttribute GetPreserveAttribute (ICustomAttributeProvider provider)
+               {
+                       if (!provider.HasCustomAttributes)
+                               return null;
+
+                       var attributes = provider.CustomAttributes;
+
+                       for (int i = 0; i < attributes.Count; i++) {
+                               var attribute = attributes [i];
+
+                               if (attribute.Constructor.DeclaringType.FullName != PreserveAttribute)
+                                       continue;
+
+                               attributes.RemoveAt (i);
+                               return attribute;
+                       }
+
+                       return null;
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/CecilRocks.cs b/mcs/tools/tuner/Mono.Tuner/CecilRocks.cs
new file mode 100644 (file)
index 0000000..75d6159
--- /dev/null
@@ -0,0 +1,518 @@
+//
+// 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 {
+
+       static class MethodBodyRocks {
+
+               public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
+               {
+                       return self.Types.SelectMany (t => t.GetAllTypes ());
+               }
+
+               static IEnumerable<TypeDefinition> 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<MethodDefinition> GetMethods (this TypeDefinition self)
+               {
+                       return self.Methods.Where (m => !m.IsConstructor);
+               }
+
+               public static IEnumerable<MethodDefinition> 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 (TypeReference iface in type.Interfaces) {
+                                               string fullname = (generic) ? iface.GetElementType ().FullName : iface.FullName;
+                                               if (fullname == interfaceName)
+                                                       return true;
+                                               //if not, then maybe one of its parent interfaces does
+                                               if (Implements (iface.Resolve (), interfaceName, generic))
+                                                       return true;
+                                       }
+                               }
+
+                               type = type.BaseType != null ? type.BaseType.Resolve () : null;
+                       }
+                       return false;
+               }
+
+               public static bool Inherits (this TypeReference self, string className)
+               {
+                       if (className == null)
+                               throw new ArgumentNullException ("className");
+                       if (self == null)
+                               return false;
+
+                       TypeReference current = self.Resolve ();
+                       while (current != null) {
+                               string fullname = current.FullName;
+                               if (fullname == className)
+                                       return true;
+                               if (fullname == "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/mcs/tools/tuner/Mono.Tuner/CustomizeActions.cs b/mcs/tools/tuner/Mono.Tuner/CustomizeActions.cs
new file mode 100644 (file)
index 0000000..3f0da18
--- /dev/null
@@ -0,0 +1,58 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Mono.Tuner {
+
+       public class CustomizeActions : BaseStep {
+
+               readonly bool link_sdk_only;
+               readonly HashSet<string> skipped_assemblies;
+
+               public CustomizeActions (bool link_sdk_only, IEnumerable<string> skipped_assemblies)
+               {
+                       this.link_sdk_only = link_sdk_only;
+                       this.skipped_assemblies = new HashSet<string> (skipped_assemblies);
+               }
+
+               protected override void ProcessAssembly (AssemblyDefinition assembly)
+               {
+                       if (IsSkipped (assembly)) {
+                               ProcessUserAssembly (assembly);
+                               return;
+                       }
+
+                       if (!link_sdk_only) {
+                               if (!Annotations.HasAction (assembly)) // stray assembly not picked up when resolving references
+                                       Annotations.SetAction (assembly, AssemblyAction.Link);
+
+                               return;
+                       }
+
+                       if (Profile.IsSdkAssembly (assembly) || Profile.IsProductAssembly (assembly)) {
+                               Annotations.SetAction (assembly, AssemblyAction.Link);
+                               return;
+                       }
+
+                       ProcessUserAssembly (assembly);
+               }
+
+               bool IsSkipped (AssemblyDefinition assembly)
+               {
+                       return skipped_assemblies.Contains (assembly.Name.Name);
+               }
+
+               void ProcessUserAssembly (AssemblyDefinition assembly)
+               {
+                       ResolveFromAssemblyStep.ProcessLibrary (Context, assembly);
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/Dispatcher.cs b/mcs/tools/tuner/Mono.Tuner/Dispatcher.cs
new file mode 100644 (file)
index 0000000..0aea81d
--- /dev/null
@@ -0,0 +1,276 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       [Flags]
+       public enum SubStepTargets {
+               None = 0,
+
+               Assembly = 1,
+               Type = 2,
+               Field = 4,
+               Method = 8,
+               Property = 16,
+               Event = 32,
+       }
+
+       public interface ISubStep {
+
+               SubStepTargets Targets { get; }
+
+               void Initialize (LinkContext context);
+               bool IsActiveFor (AssemblyDefinition assembly);
+
+               void ProcessAssembly (AssemblyDefinition assembly);
+               void ProcessType (TypeDefinition type);
+               void ProcessField (FieldDefinition field);
+               void ProcessMethod (MethodDefinition method);
+               void ProcessProperty (PropertyDefinition property);
+               void ProcessEvent (EventDefinition @event);
+       }
+
+       public abstract class BaseSubStep : ISubStep {
+
+               protected LinkContext context;
+
+               public AnnotationStore Annotations {
+                       get { return context.Annotations; }
+               }
+
+               public abstract SubStepTargets Targets { get; }
+
+               void ISubStep.Initialize (LinkContext context)
+               {
+                       this.context = context;
+               }
+
+               public virtual bool IsActiveFor (AssemblyDefinition assembly)
+               {
+                       return true;
+               }
+
+               public virtual void ProcessAssembly (AssemblyDefinition assembly)
+               {
+               }
+
+               public virtual void ProcessType (TypeDefinition type)
+               {
+               }
+
+               public virtual void ProcessField (FieldDefinition field)
+               {
+               }
+
+               public virtual void ProcessMethod (MethodDefinition method)
+               {
+               }
+
+               public virtual void ProcessProperty (PropertyDefinition property)
+               {
+               }
+
+               public virtual void ProcessEvent (EventDefinition @event)
+               {
+               }
+       }
+
+       public class SubStepDispatcher : IStep, IEnumerable<ISubStep> {
+
+               List<ISubStep> substeps = new List<ISubStep> ();
+
+               List<ISubStep> on_assemblies;
+               List<ISubStep> on_types;
+               List<ISubStep> on_fields;
+               List<ISubStep> on_methods;
+               List<ISubStep> on_properties;
+               List<ISubStep> on_events;
+
+               public void Add (ISubStep substep)
+               {
+                       substeps.Add (substep);
+               }
+
+               public void Process (LinkContext context)
+               {
+                       InitializeSubSteps (context);
+
+                       BrowseAssemblies (context.GetAssemblies ());
+               }
+
+               static bool HasSubSteps (List<ISubStep> substeps)
+               {
+                       return substeps != null && substeps.Count > 0;
+               }
+
+               void BrowseAssemblies (IEnumerable<AssemblyDefinition> assemblies)
+               {
+                       foreach (var assembly in assemblies) {
+                               CategorizeSubSteps (assembly);
+
+                               if (HasSubSteps (on_assemblies))
+                                       DispatchAssembly (assembly);
+
+                               if (!ShouldDispatchTypes ())
+                                       continue;
+
+                               BrowseTypes (assembly.MainModule.Types);
+                       }
+               }
+
+               bool ShouldDispatchTypes ()
+               {
+                       return HasSubSteps (on_types)
+                               || HasSubSteps (on_fields)
+                               || HasSubSteps (on_methods)
+                               || HasSubSteps (on_properties)
+                               || HasSubSteps (on_events);
+               }
+
+               void BrowseTypes (ICollection types)
+               {
+                       foreach (TypeDefinition type in types) {
+                               DispatchType (type);
+
+                               if (type.HasFields && HasSubSteps (on_fields))
+                                       BrowseFields (type.Fields);
+
+                               if (type.HasMethods && HasSubSteps (on_methods))
+                                       BrowseMethods (type.Methods);
+
+                               if (type.HasProperties && HasSubSteps (on_properties))
+                                       BrowseProperties (type.Properties);
+
+                               if (type.HasEvents && HasSubSteps (on_events))
+                                       BrowseEvents (type.Events);
+
+                               if (type.HasNestedTypes)
+                                       BrowseTypes (type.NestedTypes);
+                       }
+               }
+
+               void BrowseFields (ICollection fields)
+               {
+                       foreach (FieldDefinition field in fields)
+                               DispatchField (field);
+               }
+
+               void BrowseMethods (ICollection methods)
+               {
+                       foreach (MethodDefinition method in methods)
+                               DispatchMethod (method);
+               }
+
+               void BrowseProperties (ICollection properties)
+               {
+                       foreach (PropertyDefinition property in properties)
+                               DispatchProperty (property);
+               }
+
+               void BrowseEvents (ICollection events)
+               {
+                       foreach (EventDefinition @event in events)
+                               DispatchEvent (@event);
+               }
+
+               void DispatchAssembly (AssemblyDefinition assembly)
+               {
+                       foreach (var substep in on_assemblies)
+                               substep.ProcessAssembly (assembly);
+               }
+
+               void DispatchType (TypeDefinition type)
+               {
+                       foreach (var substep in on_types)
+                               substep.ProcessType (type);
+               }
+
+               void DispatchField (FieldDefinition field)
+               {
+                       foreach (var substep in on_fields)
+                               substep.ProcessField (field);
+               }
+
+               void DispatchMethod (MethodDefinition method)
+               {
+                       foreach (var substep in on_methods)
+                               substep.ProcessMethod (method);
+               }
+
+               void DispatchProperty (PropertyDefinition property)
+               {
+                       foreach (var substep in on_properties)
+                               substep.ProcessProperty (property);
+               }
+
+               void DispatchEvent (EventDefinition @event)
+               {
+                       foreach (var substep in on_events)
+                               substep.ProcessEvent (@event);
+               }
+
+               void InitializeSubSteps (LinkContext context)
+               {
+                       foreach (var substep in substeps)
+                               substep.Initialize (context);
+               }
+
+               void CategorizeSubSteps (AssemblyDefinition assembly)
+               {
+                       on_assemblies = null;
+                       on_types = null;
+                       on_fields = null;
+                       on_methods = null;
+                       on_properties = null;
+                       on_events = null;
+
+                       foreach (var substep in substeps)
+                               CategorizeSubStep (substep, assembly);
+               }
+
+               void CategorizeSubStep (ISubStep substep, AssemblyDefinition assembly)
+               {
+                       if (!substep.IsActiveFor (assembly))
+                               return;
+
+                       CategorizeTarget (substep, SubStepTargets.Assembly, ref on_assemblies);
+                       CategorizeTarget (substep, SubStepTargets.Type, ref on_types);
+                       CategorizeTarget (substep, SubStepTargets.Field, ref on_fields);
+                       CategorizeTarget (substep, SubStepTargets.Method, ref on_methods);
+                       CategorizeTarget (substep, SubStepTargets.Property, ref on_properties);
+                       CategorizeTarget (substep, SubStepTargets.Event, ref on_events);
+               }
+
+               static void CategorizeTarget (ISubStep substep, SubStepTargets target, ref List<ISubStep> list)
+               {
+                       if (!Targets (substep, target))
+                               return;
+
+                       if (list == null)
+                               list = new List<ISubStep> ();
+
+                       list.Add (substep);
+               }
+
+               static bool Targets (ISubStep substep, SubStepTargets target)
+               {
+                       return (substep.Targets & target) == target;
+               }
+
+               IEnumerator IEnumerable.GetEnumerator ()
+               {
+                       return GetEnumerator ();
+               }
+
+               public IEnumerator<ISubStep> GetEnumerator ()
+               {
+                       return substeps.GetEnumerator ();
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/Extensions.cs b/mcs/tools/tuner/Mono.Tuner/Extensions.cs
new file mode 100644 (file)
index 0000000..5c3dd86
--- /dev/null
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+
+using Mono.Linker;
+
+namespace Mono.Tuner {
+
+       static class Extensions {
+
+               public static bool TryGetLinkedAssembly (this LinkContext context, string name, out AssemblyDefinition assembly)
+               {
+                       assembly = GetAssembly (context, name);
+                       if (assembly == null)
+                               return false;
+
+                       return context.Annotations.GetAction (assembly) == AssemblyAction.Link;
+               }
+
+               public static AssemblyDefinition GetAssembly (this LinkContext context, string assembly_name)
+               {
+                       foreach (var assembly in context.GetAssemblies ())
+                               if (assembly.Name.Name == assembly_name)
+                                       return assembly;
+
+                       return null;
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/FixModuleFlags.cs b/mcs/tools/tuner/Mono.Tuner/FixModuleFlags.cs
new file mode 100644 (file)
index 0000000..2bb01ab
--- /dev/null
@@ -0,0 +1,20 @@
+using System;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public class FixModuleFlags : BaseStep {
+
+               protected override void ProcessAssembly (AssemblyDefinition assembly)
+               {
+                       if (Annotations.GetAction (assembly) != AssemblyAction.Link)
+                               return;
+
+                       assembly.MainModule.Attributes = ModuleAttributes.ILOnly;
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/PreserveCrypto.cs b/mcs/tools/tuner/Mono.Tuner/PreserveCrypto.cs
new file mode 100644 (file)
index 0000000..35dda5c
--- /dev/null
@@ -0,0 +1,113 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Mono.Tuner {
+
+       public class PreserveCrypto : IStep {
+
+               AnnotationStore annotations;
+
+               public void Process (LinkContext context)
+               {
+                       annotations = context.Annotations;
+
+                       ProcessCorlib (context);
+                       ProcessSystemCore (context);
+               }
+
+               void ProcessCorlib (LinkContext context)
+               {
+                       AssemblyDefinition corlib;
+                       if (!context.TryGetLinkedAssembly ("mscorlib", out corlib))
+                               return;
+
+                       AddPreserveInfo (corlib, "DES", "DESCryptoServiceProvider");
+                       AddPreserveInfo (corlib, "DSA", "DSACryptoServiceProvider");
+                       AddPreserveInfo (corlib, "RandomNumberGenerator", "RNGCryptoServiceProvider");
+                       AddPreserveInfo (corlib, "SHA1", "SHA1CryptoServiceProvider");
+                       AddPreserveInfo (corlib, "SHA1", "SHA1Managed");
+                       AddPreserveInfo (corlib, "MD5", "MD5CryptoServiceProvider");
+                       AddPreserveInfo (corlib, "RC2", "RC2CryptoServiceProvider");
+                       AddPreserveInfo (corlib, "TripleDES", "TripleDESCryptoServiceProvider");
+
+                       AddPreserveInfo (corlib, "Rijndael", "RijndaelManaged");
+                       AddPreserveInfo (corlib, "RIPEMD160", "RIPEMD160Managed");
+                       AddPreserveInfo (corlib, "SHA256", "SHA256Managed");
+                       AddPreserveInfo (corlib, "SHA384", "SHA384Managed");
+                       AddPreserveInfo (corlib, "SHA512", "SHA512Managed");
+
+                       AddPreserveInfo (corlib, "HMAC", "HMACMD5");
+                       AddPreserveInfo (corlib, "HMAC", "HMACRIPEMD160");
+                       AddPreserveInfo (corlib, "HMAC", "HMACSHA1");
+                       AddPreserveInfo (corlib, "HMAC", "HMACSHA256");
+                       AddPreserveInfo (corlib, "HMAC", "HMACSHA384");
+                       AddPreserveInfo (corlib, "HMAC", "HMACSHA512");
+
+                       AddPreserveInfo (corlib, "HMACMD5", "MD5CryptoServiceProvider");
+                       AddPreserveInfo (corlib, "HMACRIPEMD160", "RIPEMD160Managed");
+                       AddPreserveInfo (corlib, "HMACSHA1", "SHA1CryptoServiceProvider");
+                       AddPreserveInfo (corlib, "HMACSHA1", "SHA1Managed");
+                       AddPreserveInfo (corlib, "HMACSHA256", "SHA256Managed");
+                       AddPreserveInfo (corlib, "HMACSHA384", "SHA384Managed");
+                       AddPreserveInfo (corlib, "HMACSHA512", "SHA512Managed");
+
+                       TryAddPreserveInfo (corlib, "Aes", "AesManaged");
+               }
+
+               void ProcessSystemCore (LinkContext context)
+               {
+                       AssemblyDefinition syscore;
+                       if (!context.TryGetLinkedAssembly ("System.Core", out syscore))
+                               return;
+
+                       // AddPreserveInfo (syscore, "Aes", "AesCryptoServiceProvider");
+                       TryAddPreserveInfo (syscore, "Aes", "AesManaged");
+               }
+
+               bool TryAddPreserveInfo (AssemblyDefinition assembly, string name, string type)
+               {
+                       var marker = GetCryptoType (assembly, name);
+                       if (marker == null)
+                               return false;
+
+                       var implementation = GetCryptoType (assembly, type);
+                       if (implementation == null)
+                               return false;
+
+                       Preserve (marker, implementation);
+                       return true;
+               }
+
+               void AddPreserveInfo (AssemblyDefinition assembly, string name, string type)
+               {
+                       var marker = GetCryptoType (assembly, name);
+                       if (marker == null)
+                               throw new ArgumentException (name);
+
+                       var implementation = GetCryptoType (assembly, type);
+                       if (implementation == null)
+                               throw new ArgumentException (type);
+
+                       Preserve (marker, implementation);
+               }
+
+               void Preserve (TypeDefinition marker, TypeDefinition implementation)
+               {
+                       foreach (var constructor in implementation.GetConstructors ())
+                               annotations.AddPreservedMethod (marker, constructor);
+               }
+
+               TypeDefinition GetCryptoType (AssemblyDefinition assembly, string name)
+               {
+                       return assembly.MainModule.GetType ("System.Security.Cryptography." + name);
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/PreserveHttps.cs b/mcs/tools/tuner/Mono.Tuner/PreserveHttps.cs
new file mode 100644 (file)
index 0000000..509e548
--- /dev/null
@@ -0,0 +1,91 @@
+using System;
+using System.IO;
+using System.Xml.XPath;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public class PreserveHttps : BaseStep {
+
+               static string [] types = new [] {
+                       "System.Net.WebRequest",
+                       "System.Net.WebClient",
+                       "System.Net.Security.RemoteCertificateValidationCallback",
+                       "System.Web.Services.Protocols.WebClientProtocol",
+                       "System.Security.Cryptography.X509Certificates.X509Certificate",
+                       "System.Web.Services.WebServiceBindingAttribute",
+                       "System.Web.Services.Protocols.SoapHttpClientProtocol",
+               };
+
+               bool need_https;
+
+               protected override void ProcessAssembly (AssemblyDefinition assembly)
+               {
+                       if (need_https)
+                               return;
+
+                       if (Profile.IsSdkAssembly (assembly))
+                               return;
+
+                       if (HasNeededReference (assembly.MainModule))
+                               need_https = true;
+               }
+
+               static bool HasNeededReference (ModuleDefinition module)
+               {
+                       foreach (var type in types)
+                               if (module.HasTypeReference (type))
+                                       return true;
+
+                       return false;
+               }
+
+               protected override void EndProcess ()
+               {
+                       if (!need_https)
+                               return;
+
+                       var mono_security = Context.Resolve ("Mono.Security");
+                       if (mono_security == null)
+                               return;
+
+                       if (Annotations.GetAction (mono_security) != AssemblyAction.Link)
+                               return;
+
+                       var xml_preserve = CreatePreserveStep ();
+                       Context.Pipeline.AddStepAfter (typeof (PreserveHttps), xml_preserve);
+//                     Context.Pipeline.AddStepAfter (xml_preserve, new PreserveCrypto ());
+               }
+
+               static IStep CreatePreserveStep ()
+               {
+                       return new ResolveFromXmlStep (
+                               new XPathDocument (
+                                       new StringReader (descriptor)));
+               }
+
+               const string descriptor = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
+<linker>
+       <assembly fullname=""mscorlib"">
+               <namespace fullname=""System.Security.Cryptography"" />
+       </assembly>
+       <assembly fullname=""System"">
+               <namespace fullname=""System.Security.Cryptography"" />
+       </assembly>
+       <assembly fullname=""Mono.Security"">
+               <type fullname=""Mono.Security.Protocol.Tls.HttpsClientStream"" />
+               <type fullname=""Mono.Security.Protocol.Tls.SslClientStream"">
+                       <method name=""get_SelectedClientCertificate"" />
+               </type>
+               <type fullname=""Mono.Security.Protocol.Tls.SslStreamBase"">
+                       <method name=""get_ServerCertificate"" />
+               </type>
+       </assembly>
+</linker>
+";
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/PreserveSoapHttpClients.cs b/mcs/tools/tuner/Mono.Tuner/PreserveSoapHttpClients.cs
new file mode 100644 (file)
index 0000000..c418623
--- /dev/null
@@ -0,0 +1,90 @@
+using System;
+
+using Mono.Linker;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public class PreserveSoapHttpClients : BaseSubStep {
+
+               public override SubStepTargets Targets {
+                       get { return SubStepTargets.Type; }
+               }
+
+               public override bool IsActiveFor (AssemblyDefinition assembly)
+               {
+                       return Annotations.GetAction (assembly) == AssemblyAction.Link && !Profile.IsSdkAssembly (assembly);
+               }
+
+               public override void ProcessType (TypeDefinition type)
+               {
+                       if (IsWebServiceClient (type))
+                               PreserveClient (type);
+               }
+
+               void PreserveClient (TypeDefinition type)
+               {
+                       if (!type.HasMethods)
+                               return;
+
+                       foreach (MethodDefinition method in type.Methods) {
+                               string sync_method;
+                               if (!TryExtractSyncMethod (method, out sync_method))
+                                       continue;
+
+                               AddPreservedMethod (method, sync_method);
+                       }
+               }
+
+               void AddPreservedMethod (MethodDefinition target, string methodName)
+               {
+                       foreach (MethodDefinition method in target.DeclaringType.Methods)
+                               if (method.Name == methodName)
+                                       Annotations.AddPreservedMethod (target, method);
+               }
+
+               static bool TryExtractSyncMethod (MethodDefinition method, out string sync_method)
+               {
+                       if (TryExtractPrefixedMethodName ("Begin", method.Name, out sync_method))
+                               return true;
+
+                       if (TryExtractPrefixedMethodName ("End", method.Name, out sync_method))
+                               return true;
+
+                       if (TryExtractSuffixedMethodName ("Async", method.Name, out sync_method))
+                               return true;
+
+                       return false;
+               }
+
+               static bool TryExtractPrefixedMethodName (string prefix, string fullName, out string methodName)
+               {
+                       methodName = null;
+
+                       int pos = fullName.IndexOf (prefix);
+                       if (pos == -1)
+                               return false;
+
+                       methodName = fullName.Substring (prefix.Length);
+                       return true;
+               }
+
+               static bool TryExtractSuffixedMethodName (string suffix, string fullName, out string methodName)
+               {
+                       methodName = null;
+
+                       int pos = fullName.LastIndexOf (suffix);
+                       if (pos == -1)
+                               return false;
+
+                       methodName = fullName.Substring (0, pos);
+                       return true;
+               }
+
+               static bool IsWebServiceClient (TypeDefinition type)
+               {
+                       return type.Inherits ("System.Web.Services.Protocols.SoapHttpClientProtocol");
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/tools/tuner/Mono.Tuner/PrintTypeMap.cs b/mcs/tools/tuner/Mono.Tuner/PrintTypeMap.cs
new file mode 100644 (file)
index 0000000..8838b1a
--- /dev/null
@@ -0,0 +1,71 @@
+//
+// PrintTypeMap.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 System.Collections.Generic;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public class PrintTypeMap : BaseStep {
+
+               protected override void ProcessAssembly (AssemblyDefinition assembly)
+               {
+                       foreach (TypeDefinition type in assembly.MainModule.GetAllTypes ())
+                               PrintMap (type);
+               }
+
+               void PrintMap (TypeDefinition type)
+               {
+                       if (!type.HasMethods)
+                               return;
+
+                       Console.WriteLine ("Type {0} map", type);
+
+                       foreach (MethodDefinition method in type.Methods) {
+                               if (!method.IsVirtual)
+                                       continue;
+
+                               Console.WriteLine ("  Method {0} map", method);
+
+                               IEnumerable<MethodDefinition> overrides = Annotations.GetOverrides (method);
+                               foreach (var @override in overrides ?? new MethodDefinition [0])
+                                       Console.WriteLine ("    HasOverride {0}", @override);
+
+                               IEnumerable<MethodDefinition> bases = Annotations.GetBaseMethods (method);
+                               foreach (var @base in bases ?? new MethodDefinition [0])
+                                       Console.WriteLine ("    Base {0}", @base);
+                       }
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/Profile.cs b/mcs/tools/tuner/Mono.Tuner/Profile.cs
new file mode 100644 (file)
index 0000000..095da26
--- /dev/null
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       abstract class Profile {
+
+               static Profile current;
+
+               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");
+                       }
+               }
+
+               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 IsProductAssembly (AssemblyDefinition assembly)
+               {
+                       return Current.IsProduct (assembly);
+               }
+
+               protected abstract bool IsSdk (AssemblyDefinition assembly);
+               protected abstract bool IsProduct (AssemblyDefinition assembly);
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/RemoveAttributesBase.cs b/mcs/tools/tuner/Mono.Tuner/RemoveAttributesBase.cs
new file mode 100644 (file)
index 0000000..9f7872f
--- /dev/null
@@ -0,0 +1,100 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Tuner;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public abstract class RemoveAttributesBase : BaseSubStep {
+
+               public override SubStepTargets Targets {
+                       get {
+                               return SubStepTargets.Assembly
+                                       | SubStepTargets.Type
+                                       | SubStepTargets.Field
+                                       | SubStepTargets.Method
+                                       | SubStepTargets.Property
+                                       | SubStepTargets.Event;
+                       }
+               }
+
+               public override bool IsActiveFor (AssemblyDefinition assembly)
+               {
+                       return Annotations.GetAction (assembly) == AssemblyAction.Link;
+               }
+
+               public override void ProcessAssembly (AssemblyDefinition assembly)
+               {
+                       ProcessAttributeProvider (assembly);
+                       ProcessAttributeProvider (assembly.MainModule);
+               }
+
+               public override void ProcessType (TypeDefinition type)
+               {
+                       ProcessAttributeProvider (type);
+
+                       if (type.HasGenericParameters)
+                               ProcessAttributeProviderCollection (type.GenericParameters);
+               }
+
+               void ProcessAttributeProviderCollection (IList list)
+               {
+                       for (int i = 0; i < list.Count; i++)
+                               ProcessAttributeProvider ((ICustomAttributeProvider) list [i]);
+               }
+
+               public override void ProcessField (FieldDefinition field)
+               {
+                       ProcessAttributeProvider (field);
+               }
+
+               public override void ProcessMethod (MethodDefinition method)
+               {
+                       ProcessMethodAttributeProvider (method);
+               }
+
+               void ProcessMethodAttributeProvider (MethodDefinition method)
+               {
+                       ProcessAttributeProvider (method);
+                       ProcessAttributeProvider (method.MethodReturnType);
+
+                       if (method.HasParameters)
+                               ProcessAttributeProviderCollection (method.Parameters);
+
+                       if (method.HasGenericParameters)
+                               ProcessAttributeProviderCollection (method.GenericParameters);
+               }
+
+               public override void ProcessProperty (PropertyDefinition property)
+               {
+                       ProcessAttributeProvider (property);
+               }
+
+               public override void ProcessEvent (EventDefinition @event)
+               {
+                       ProcessAttributeProvider (@event);
+               }
+
+               void ProcessAttributeProvider (ICustomAttributeProvider provider)
+               {
+                       if (!provider.HasCustomAttributes)
+                               return;
+
+                       for (int i = 0; i < provider.CustomAttributes.Count; i++) {
+                               if (!IsRemovedAttribute (provider.CustomAttributes [i]))
+                                       continue;
+
+                               provider.CustomAttributes.RemoveAt (i--);
+                       }
+               }
+
+               protected abstract bool IsRemovedAttribute (CustomAttribute attribute);
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/RemoveResources.cs b/mcs/tools/tuner/Mono.Tuner/RemoveResources.cs
new file mode 100644 (file)
index 0000000..3922f91
--- /dev/null
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public class RemoveResources : IStep {
+
+               I18nAssemblies assemblies;
+
+               public RemoveResources (I18nAssemblies assemblies)
+               {
+                       this.assemblies = assemblies;
+               }
+
+               public void Process (LinkContext context)
+               {
+                       AssemblyDefinition assembly;
+                       if (!context.TryGetLinkedAssembly ("mscorlib", out assembly))
+                               return;
+
+                       var resources = assembly.MainModule.Resources;
+
+                       for (int i = 0; i < resources.Count; i++) {
+                               var resource = resources [i] as EmbeddedResource;
+                               if (resource == null)
+                                       continue;
+
+                               switch (resource.Name) {
+                               case "collation.core.bin":
+                               case "collation.tailoring.bin":
+                                       continue;
+                               default:
+                                       if (!resource.Name.Contains ("cjk"))
+                                               continue;
+                                       if (IncludeCJK ())
+                                               continue;
+
+                                       resources.RemoveAt (i--);
+                                       break;
+                               }
+                       }
+               }
+
+               bool IncludeCJK ()
+               {
+                       return (assemblies & I18nAssemblies.CJK) != 0;
+               }
+       }
+}
diff --git a/mcs/tools/tuner/Mono.Tuner/RemoveSecurity.cs b/mcs/tools/tuner/Mono.Tuner/RemoveSecurity.cs
new file mode 100644 (file)
index 0000000..2704564
--- /dev/null
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Linker;
+using Mono.Linker.Steps;
+
+using Mono.Cecil;
+
+namespace Mono.Tuner {
+
+       public class RemoveSecurity : BaseSubStep {
+
+               public override SubStepTargets Targets {
+                       get {
+                               return SubStepTargets.Assembly
+                                       | SubStepTargets.Type
+                                       | SubStepTargets.Method;
+                       }
+               }
+
+               public override bool IsActiveFor (AssemblyDefinition assembly)
+               {
+                       return Annotations.GetAction (assembly) == AssemblyAction.Link;
+               }
+
+               public override void ProcessAssembly (AssemblyDefinition assembly)
+               {
+                       ProcessSecurityProvider (assembly);
+               }
+
+               public override void ProcessType (TypeDefinition type)
+               {
+                       ProcessSecurityProvider (type);
+               }
+
+               public override void ProcessMethod (MethodDefinition method)
+               {
+                       ProcessSecurityProvider (method);
+               }
+
+               static void ProcessSecurityProvider (ISecurityDeclarationProvider provider)
+               {
+                       if (!provider.HasSecurityDeclarations)
+                               return;
+
+                       provider.SecurityDeclarations.Clear ();
+               }
+       }
+}