|
| 1 | +From d438b2ff6ae4b90424267f8c46f72d25349af76d Mon Sep 17 00:00:00 2001 |
| 2 | +From: Eugene Rozenfeld <erozen@microsoft.com> |
| 3 | +Date: Tue, 4 Apr 2017 23:27:47 -0700 |
| 4 | +Subject: [PATCH] Add an option to use reflection heuristics during marking |
| 5 | + step. |
| 6 | + |
| 7 | +This change adds a -h option that can specify heuristics for keeping |
| 8 | +types/methods/fields that may be needed for reflection. Three simple |
| 9 | +and coarse-grained heuristic options are added initially (all are off by default): |
| 10 | + |
| 11 | +1. "LdtokenTypeMethods": mark all methods of types whose token is used |
| 12 | +in an ldtoken instruction. |
| 13 | +2. "LdtokenTypeFields": mark all fields of types whose token is used |
| 14 | +in an ldtoken instruction. |
| 15 | +3. "InstanceConstructors": mark all instance constructors in types |
| 16 | +where an instance member has been marked but none of the instance |
| 17 | +constructors have been marked. (The type is likely to be instantiated via CreateInstance). |
| 18 | + |
| 19 | +When -h is specified MarkStep is replaced with MarkStepWithReflectionHeuristics that |
| 20 | +derives from MarkStep. The names of heuristics are specified in a comma-separated list. |
| 21 | +More heuristics will be added over time and any subset of them can be used for a particular |
| 22 | +linker invocation. |
| 23 | + |
| 24 | +https://github.com/dotnet/source-build/issues/777 tracks removing this patch. |
| 25 | +--- |
| 26 | + .../MarkStepWithReflectionHeuristics.cs | 98 +++++++++++++++++++ |
| 27 | + linker/Linker/Driver.cs | 22 +++++ |
| 28 | + linker/Mono.Linker.csproj | 1 + |
| 29 | + 3 files changed, 121 insertions(+) |
| 30 | + create mode 100644 linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs |
| 31 | + |
| 32 | +diff --git a/linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs b/linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs |
| 33 | +new file mode 100644 |
| 34 | +index 0000000..3cb98b1 |
| 35 | +--- /dev/null |
| 36 | ++++ b/linker/Linker.Steps/MarkStepWithReflectionHeuristics.cs |
| 37 | +@@ -0,0 +1,98 @@ |
| 38 | ++using System; |
| 39 | ++using System.Collections; |
| 40 | ++using System.Collections.Generic; |
| 41 | ++ |
| 42 | ++using Mono.Cecil; |
| 43 | ++using Mono.Cecil.Cil; |
| 44 | ++ |
| 45 | ++namespace Mono.Linker.Steps { |
| 46 | ++ |
| 47 | ++ public class MarkStepWithReflectionHeuristics : MarkStep { |
| 48 | ++ |
| 49 | ++ protected ICollection<string> _reflectionHeuristics; |
| 50 | ++ |
| 51 | ++ public MarkStepWithReflectionHeuristics (ICollection<string> reflectionHeuristics) |
| 52 | ++ { |
| 53 | ++ _reflectionHeuristics = reflectionHeuristics; |
| 54 | ++ } |
| 55 | ++ |
| 56 | ++ protected override void MarkInstruction (Instruction instruction) |
| 57 | ++ { |
| 58 | ++ base.MarkInstruction (instruction); |
| 59 | ++ |
| 60 | ++ if (instruction.OpCode == OpCodes.Ldtoken) { |
| 61 | ++ object token = instruction.Operand; |
| 62 | ++ if (token is TypeReference) { |
| 63 | ++ TypeDefinition type = ResolveTypeDefinition (GetOriginalType (((TypeReference) token))); |
| 64 | ++ if (type != null) { |
| 65 | ++ if (_reflectionHeuristics.Contains ("LdtokenTypeMethods")) { |
| 66 | ++ MarkMethods (type); |
| 67 | ++ } |
| 68 | ++ if (_reflectionHeuristics.Contains ("LdtokenTypeFields")) { |
| 69 | ++ MarkFields (type, includeStatic: true); |
| 70 | ++ } |
| 71 | ++ } |
| 72 | ++ } |
| 73 | ++ } |
| 74 | ++ } |
| 75 | ++ |
| 76 | ++ protected override void DoAdditionalProcessing() |
| 77 | ++ { |
| 78 | ++ if (_reflectionHeuristics.Contains ("InstanceConstructors")) { |
| 79 | ++ ProcessConstructors (); |
| 80 | ++ } |
| 81 | ++ } |
| 82 | ++ |
| 83 | ++ void ProcessConstructors() |
| 84 | ++ { |
| 85 | ++ foreach (AssemblyDefinition assembly in _context.GetAssemblies ()) { |
| 86 | ++ foreach (TypeDefinition type in assembly.MainModule.Types) { |
| 87 | ++ ProcessConstructors (type); |
| 88 | ++ } |
| 89 | ++ } |
| 90 | ++ } |
| 91 | ++ |
| 92 | ++ void ProcessConstructors(TypeDefinition type) |
| 93 | ++ { |
| 94 | ++ if (Annotations.IsMarked (type)) { |
| 95 | ++ |
| 96 | ++ bool hasMarkedConstructors = false; |
| 97 | ++ bool hasMarkedInstanceMember = false; |
| 98 | ++ foreach (var method in type.Methods) { |
| 99 | ++ if (Annotations.IsMarked (method)) { |
| 100 | ++ if (!method.IsStatic) { |
| 101 | ++ hasMarkedInstanceMember = true; |
| 102 | ++ } |
| 103 | ++ |
| 104 | ++ if (IsInstanceConstructor (method)) { |
| 105 | ++ hasMarkedConstructors = true; |
| 106 | ++ } |
| 107 | ++ |
| 108 | ++ if (hasMarkedInstanceMember && hasMarkedConstructors) { |
| 109 | ++ break; |
| 110 | ++ } |
| 111 | ++ } |
| 112 | ++ } |
| 113 | ++ |
| 114 | ++ if (!hasMarkedConstructors) { |
| 115 | ++ if (!hasMarkedInstanceMember) { |
| 116 | ++ foreach (var field in type.Fields) { |
| 117 | ++ if (!field.IsStatic && Annotations.IsMarked (field)) { |
| 118 | ++ hasMarkedInstanceMember = true; |
| 119 | ++ break; |
| 120 | ++ } |
| 121 | ++ } |
| 122 | ++ } |
| 123 | ++ |
| 124 | ++ if (hasMarkedInstanceMember) { |
| 125 | ++ MarkMethodsIf (type.Methods, IsInstanceConstructor); |
| 126 | ++ } |
| 127 | ++ } |
| 128 | ++ |
| 129 | ++ foreach (var nestedType in type.NestedTypes) { |
| 130 | ++ ProcessConstructors (nestedType); |
| 131 | ++ } |
| 132 | ++ } |
| 133 | ++ } |
| 134 | ++ } |
| 135 | ++} |
| 136 | +diff --git a/linker/Linker/Driver.cs b/linker/Linker/Driver.cs |
| 137 | +index 8a380db..0d6a9f6 100644 |
| 138 | +--- a/linker/Linker/Driver.cs |
| 139 | ++++ b/linker/Linker/Driver.cs |
| 140 | +@@ -232,6 +232,10 @@ namespace Mono.Linker { |
| 141 | + case 'v': |
| 142 | + context.KeepMembersForDebugger = bool.Parse (GetParam ()); |
| 143 | + break; |
| 144 | ++ case 'h': |
| 145 | ++ ICollection<string> reflectionHeuristics = ParseReflectionHeuristics (GetParam ()); |
| 146 | ++ p.ReplaceStep (typeof (MarkStep), new MarkStepWithReflectionHeuristics (reflectionHeuristics)); |
| 147 | ++ break; |
| 148 | + default: |
| 149 | + Usage ("Unknown option: `" + token [1] + "'"); |
| 150 | + break; |
| 151 | +@@ -340,6 +344,15 @@ namespace Mono.Linker { |
| 152 | + return assemblies; |
| 153 | + } |
| 154 | + |
| 155 | ++ protected static ICollection<string> ParseReflectionHeuristics(string str) |
| 156 | ++ { |
| 157 | ++ HashSet<string> heuristics = new HashSet<string> (StringComparer.OrdinalIgnoreCase); |
| 158 | ++ string[] parts = str.Split (','); |
| 159 | ++ foreach (string part in parts) |
| 160 | ++ heuristics.Add (part); |
| 161 | ++ |
| 162 | ++ return heuristics; |
| 163 | ++ } |
| 164 | + |
| 165 | + AssemblyAction ParseAssemblyAction (string s) |
| 166 | + { |
| 167 | +@@ -399,6 +412,15 @@ namespace Mono.Linker { |
| 168 | + Console.WriteLine (" -b Generate debug symbols for each linked module (true or false)"); |
| 169 | + Console.WriteLine (" -g Generate a new unique guid for each linked module (true or false)"); |
| 170 | + Console.WriteLine (" -v Keep members needed by debugger (true or false)"); |
| 171 | ++ Console.WriteLine (" -h List of reflection heuristics separated with a comma."); |
| 172 | ++ Console.WriteLine (" Supported heuristics:"); |
| 173 | ++ Console.WriteLine (" LdtokenTypeMethods: mark all methods of types whose token is used"); |
| 174 | ++ Console.WriteLine (" in an ldtoken instruction"); |
| 175 | ++ Console.WriteLine (" LdtokenTypeFields: mark all fields of types whose token is used"); |
| 176 | ++ Console.WriteLine (" in an ldtoken instruction"); |
| 177 | ++ Console.WriteLine (" InstanceConstructors: mark all instance constructors in types"); |
| 178 | ++ Console.WriteLine (" where an instance member has been marked but"); |
| 179 | ++ Console.WriteLine (" none of the instance constructors have been marked"); |
| 180 | + Console.WriteLine (" -l List of i18n assemblies to copy to the output directory"); |
| 181 | + Console.WriteLine (" separated with a comma: none,all,cjk,mideast,other,rare,west"); |
| 182 | + Console.WriteLine (" default is all"); |
| 183 | +diff --git a/linker/Mono.Linker.csproj b/linker/Mono.Linker.csproj |
| 184 | +index d328491..4e8f143 100644 |
| 185 | +--- a/linker/Mono.Linker.csproj |
| 186 | ++++ b/linker/Mono.Linker.csproj |
| 187 | +@@ -70,6 +70,7 @@ |
| 188 | + <Compile Include="Linker.Steps\IStep.cs" /> |
| 189 | + <Compile Include="Linker.Steps\LoadReferencesStep.cs" /> |
| 190 | + <Compile Include="Linker.Steps\MarkStep.cs" /> |
| 191 | ++ <Compile Include="Linker.Steps\MarkStepWithReflectionHeuristics.cs" /> |
| 192 | + <Compile Include="Linker.Steps\OutputStep.cs" /> |
| 193 | + <Compile Include="Linker.Steps\ResolveFromXApiStep.cs" /> |
| 194 | + <Compile Include="Linker.Steps\ResolveFromAssemblyStep.cs" /> |
| 195 | +-- |
| 196 | +2.17.1.windows.2 |
| 197 | + |
0 commit comments