2009-01-28 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / linker / Mono.Linker.Steps / MarkStep.cs
blobcadc1116f8dc1462e726f007f4436eeea5e9885e
1 //
2 // MarkStep.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 Jb Evain
8 // (C) 2007 Novell, Inc.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System;
31 using System.Collections;
32 using Mono.Cecil;
33 using Mono.Cecil.Cil;
35 namespace Mono.Linker.Steps {
37 public class MarkStep : IStep {
39 LinkContext _context;
40 Queue _queue;
42 public MarkStep ()
44 _queue = new Queue ();
47 public void Process (LinkContext context)
49 _context = context;
51 Initialize ();
52 Process ();
55 void Initialize ()
57 foreach (AssemblyDefinition assembly in _context.GetAssemblies ())
58 InitializeAssembly (assembly);
61 void InitializeAssembly (AssemblyDefinition assembly)
63 MarkAssembly (assembly);
64 foreach (TypeDefinition type in assembly.MainModule.Types) {
65 if (!Annotations.IsMarked (type))
66 continue;
68 InitializeType (type);
72 void InitializeType (TypeDefinition type)
74 MarkType (type);
76 if (type.HasFields)
77 InitializeFields (type);
78 if (type.HasMethods)
79 InitializeMethods (type.Methods);
80 if (type.HasConstructors)
81 InitializeMethods (type.Constructors);
84 void InitializeFields (TypeDefinition type)
86 foreach (FieldDefinition field in type.Fields)
87 if (Annotations.IsMarked (field))
88 MarkField (field);
91 void InitializeMethods (ICollection methods)
93 foreach (MethodDefinition method in methods)
94 if (Annotations.IsMarked (method))
95 _queue.Enqueue (method);
98 void Process ()
100 if (QueueIsEmpty ())
101 throw new InvalidOperationException ("No entry methods");
103 while (!QueueIsEmpty ()) {
104 MethodDefinition method = (MethodDefinition) _queue.Dequeue ();
105 ProcessMethod (method);
109 bool QueueIsEmpty ()
111 return _queue.Count == 0;
114 void MarkMethodBody (MethodBody body)
116 foreach (VariableDefinition var in body.Variables)
117 MarkType (var.VariableType);
119 foreach (ExceptionHandler eh in body.ExceptionHandlers)
120 if (eh.Type == ExceptionHandlerType.Catch)
121 MarkType (eh.CatchType);
123 foreach (Instruction instruction in body.Instructions)
124 MarkInstruction (instruction);
127 void MarkMarshalSpec (IHasMarshalSpec spec)
129 CustomMarshalerSpec marshaler = spec.MarshalSpec as CustomMarshalerSpec;
130 if (marshaler == null)
131 return;
133 TypeDefinition type = _context.GetType (marshaler.ManagedType);
134 MarkType (type);
137 void MarkCustomAttributes (ICustomAttributeProvider provider)
139 if (!provider.HasCustomAttributes)
140 return;
142 foreach (CustomAttribute ca in provider.CustomAttributes)
143 MarkCustomAttribute (ca);
146 void MarkCustomAttribute (CustomAttribute ca)
148 MarkMethod (ca.Constructor);
150 if (!ca.Resolved) {
151 ca = ca.Clone ();
152 ca.Resolve ();
155 if (!ca.Resolved)
156 return;
158 MarkCustomAttributeParameters (ca);
160 TypeDefinition type = ca.Constructor.DeclaringType.Resolve ();
162 MarkCustomAttributeProperties (ca, type);
163 MarkCustomAttributeFields (ca, type);
166 void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute)
168 foreach (DictionaryEntry de in ca.Properties) {
169 string propertyname = (string) de.Key;
171 PropertyDefinition [] properties = attribute.Properties.GetProperties (propertyname);
173 if (properties != null && properties.Length != 0 && properties [0].SetMethod != null)
174 MarkMethod (properties [0].SetMethod);
176 TypeReference propType = ca.GetPropertyType (propertyname);
177 MarkIfType (propType, de.Value);
181 void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute)
183 foreach (DictionaryEntry de in ca.Fields) {
184 string fieldname = (string) de.Key;
186 FieldDefinition field = attribute.Fields.GetField (fieldname);
187 if (field != null)
188 MarkField (field);
190 TypeReference fieldType = ca.GetFieldType (fieldname);
191 MarkIfType (fieldType, de.Value);
195 void MarkCustomAttributeParameters (CustomAttribute ca)
197 for (int i = 0; i < ca.Constructor.Parameters.Count; i++) {
198 ParameterDefinition param = ca.Constructor.Parameters [i];
199 MarkIfType (param.ParameterType, ca.ConstructorParameters [i]);
203 void MarkIfType (TypeReference slotType, object value)
205 if (slotType.FullName != Constants.Type)
206 return;
208 TypeDefinition type = _context.GetType ((string) value);
210 MarkType (type);
213 static bool CheckProcessed (IAnnotationProvider provider)
215 if (Annotations.IsProcessed (provider))
216 return true;
218 Annotations.Processed (provider);
219 return false;
222 void MarkAssembly (AssemblyDefinition assembly)
224 if (CheckProcessed (assembly))
225 return;
227 MarkCustomAttributes (assembly);
229 foreach (ModuleDefinition module in assembly.Modules)
230 MarkCustomAttributes (module);
233 void MarkField (FieldReference reference)
235 if (IgnoreScope (reference.DeclaringType.Scope))
236 return;
238 FieldDefinition field = ResolveFieldDefinition (reference);
240 if (field == null)
241 throw new ResolutionException (reference);
243 if (CheckProcessed (field))
244 return;
246 MarkType (field.DeclaringType);
247 MarkType (field.FieldType);
248 MarkCustomAttributes (field);
249 MarkMarshalSpec (field);
251 Annotations.Mark (field);
254 bool IgnoreScope (IMetadataScope scope)
256 AssemblyDefinition assembly = ResolveAssembly (scope);
257 return Annotations.GetAction (assembly) != AssemblyAction.Link;
260 FieldDefinition ResolveFieldDefinition (FieldReference field)
262 FieldDefinition fd = field as FieldDefinition;
263 if (fd == null)
264 fd = field.Resolve ();
266 return fd;
269 void MarkType (TypeReference reference)
271 if (reference == null)
272 return;
274 reference = GetOriginalType (reference);
276 if (reference is GenericParameter)
277 return;
279 if (IgnoreScope (reference.Scope))
280 return;
282 TypeDefinition type = ResolveTypeDefinition (reference);
284 if (type == null)
285 throw new ResolutionException (reference);
287 if (CheckProcessed (type))
288 return;
290 MarkType (type.BaseType);
291 MarkType (type.DeclaringType);
292 MarkCustomAttributes(type);
294 if (IsMulticastDelegate (type))
295 MarkMethodCollection (type.Constructors);
297 if (IsSerializable (type) && type.HasConstructors) {
298 MarkMethodsIf (type.Constructors, IsDefaultConstructorPredicate);
299 MarkMethodsIf (type.Constructors, IsSpecialSerializationConstructorPredicate);
302 MarkGenericParameterProvider (type);
304 if (type.IsValueType)
305 MarkFields (type);
307 if (type.HasInterfaces) {
308 foreach (TypeReference iface in type.Interfaces)
309 MarkType (iface);
312 if (type.HasConstructors)
313 MarkMethodsIf (type.Constructors, IsStaticConstructorPredicate);
315 if (type.HasMethods)
316 MarkMethodsIf (type.Methods, IsVirtualPredicate);
318 Annotations.Mark (type);
320 ApplyPreserveInfo (type);
323 void MarkGenericParameterProvider (IGenericParameterProvider provider)
325 if (!provider.HasGenericParameters)
326 return;
328 foreach (GenericParameter parameter in provider.GenericParameters)
329 MarkGenericParameter (parameter);
332 void MarkGenericParameter (GenericParameter parameter)
334 MarkCustomAttributes (parameter);
335 foreach (TypeReference constraint in parameter.Constraints)
336 MarkType (constraint);
339 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
341 static bool IsSpecialSerializationConstructor (MethodDefinition method)
343 if (!IsConstructor (method))
344 return false;
346 ParameterDefinitionCollection parameters = method.Parameters;
347 if (parameters.Count != 2)
348 return false;
350 return parameters [0].ParameterType.Name == "SerializationInfo" &&
351 parameters [1].ParameterType.Name == "StreamingContext";
354 delegate bool MethodPredicate (MethodDefinition method);
356 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
358 foreach (MethodDefinition method in methods)
359 if (predicate (method))
360 MarkMethod (method);
363 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
365 static bool IsDefaultConstructor (MethodDefinition method)
367 return IsConstructor (method) && method.Parameters.Count == 0;
370 static bool IsConstructor (MethodDefinition method)
372 return method.Name == MethodDefinition.Ctor && method.IsSpecialName &&
373 method.IsRuntimeSpecialName;
376 static MethodPredicate IsVirtualPredicate = new MethodPredicate (IsVirtual);
378 static bool IsVirtual (MethodDefinition method)
380 return method.IsVirtual;
383 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
385 static bool IsStaticConstructor (MethodDefinition method)
387 return method.Name == MethodDefinition.Cctor && method.IsSpecialName &&
388 method.IsRuntimeSpecialName;
391 static bool IsSerializable (TypeDefinition td)
393 return (td.Attributes & TypeAttributes.Serializable) != 0;
396 static bool IsMulticastDelegate (TypeDefinition td)
398 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
401 TypeDefinition ResolveTypeDefinition (TypeReference type)
403 TypeDefinition td = type as TypeDefinition;
404 if (td == null)
405 td = type.Resolve ();
407 return td;
410 TypeReference GetOriginalType (TypeReference type)
412 while (type is TypeSpecification) {
413 GenericInstanceType git = type as GenericInstanceType;
414 if (git != null)
415 MarkGenericArguments (git);
417 ModType mod = type as ModType;
418 if (mod != null)
419 MarkModifierType (mod);
421 type = ((TypeSpecification) type).ElementType;
424 return type;
427 void MarkModifierType (ModType mod)
429 MarkType (mod.ModifierType);
432 void MarkGenericArguments (IGenericInstance instance)
434 foreach (TypeReference argument in instance.GenericArguments)
435 MarkType (argument);
438 void ApplyPreserveInfo (TypeDefinition type)
440 if (!Annotations.IsPreserved (type))
441 return;
443 switch (Annotations.GetPreserve (type)) {
444 case TypePreserve.All:
445 MarkFields (type);
446 MarkMethods (type);
447 break;
448 case TypePreserve.Fields:
449 MarkFields (type);
450 break;
451 case TypePreserve.Methods:
452 MarkMethods (type);
453 break;
457 void MarkFields (TypeDefinition type)
459 if (!type.HasFields)
460 return;
462 foreach (FieldDefinition field in type.Fields)
463 MarkField (field);
466 void MarkMethods (TypeDefinition type)
468 if (type.HasMethods)
469 MarkMethodCollection (type.Methods);
470 if (type.HasConstructors)
471 MarkMethodCollection (type.Constructors);
474 void MarkMethodCollection (IEnumerable methods)
476 foreach (MethodDefinition method in methods)
477 MarkMethod (method);
480 void MarkMethod (MethodReference reference)
482 reference = GetOriginalMethod (reference);
484 if (reference.DeclaringType is ArrayType)
485 return;
487 if (IgnoreScope (reference.DeclaringType.Scope))
488 return;
490 MethodDefinition method = ResolveMethodDefinition (reference);
492 if (method == null)
493 throw new ResolutionException (reference);
495 Annotations.SetAction (method, MethodAction.Parse);
497 _queue.Enqueue (method);
500 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
502 AssemblyDefinition assembly = _context.Resolve (scope);
503 MarkAssembly (assembly);
504 return assembly;
507 MethodReference GetOriginalMethod (MethodReference method)
509 while (method is MethodSpecification) {
510 GenericInstanceMethod gim = method as GenericInstanceMethod;
511 if (gim != null)
512 MarkGenericArguments (gim);
514 method = ((MethodSpecification) method).ElementMethod;
517 return method;
520 MethodDefinition ResolveMethodDefinition (MethodReference method)
522 MethodDefinition md = method as MethodDefinition;
523 if (md == null)
524 md = method.Resolve ();
526 return md;
529 void ProcessMethod (MethodDefinition method)
531 if (CheckProcessed (method))
532 return;
534 MarkType (method.DeclaringType);
535 MarkCustomAttributes (method);
537 MarkGenericParameterProvider (method);
539 if (IsPropertyMethod (method))
540 MarkProperty (GetProperty (method));
541 else if (IsEventMethod (method))
542 MarkEvent (GetEvent (method));
544 if (method.HasParameters) {
545 foreach (ParameterDefinition pd in method.Parameters) {
546 MarkType (pd.ParameterType);
547 MarkCustomAttributes (pd);
548 MarkMarshalSpec (pd);
552 if (method.HasOverrides) {
553 foreach (MethodReference ov in method.Overrides)
554 MarkMethod (ov);
557 MarkType (method.ReturnType.ReturnType);
558 MarkCustomAttributes (method.ReturnType);
559 MarkMarshalSpec (method.ReturnType);
561 if (ShouldParseMethodBody (method))
562 MarkMethodBody (method.Body);
564 Annotations.Mark (method);
567 bool ShouldParseMethodBody (MethodDefinition method)
569 if (!method.HasBody)
570 return false;
572 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
573 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
574 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
577 static bool IsPropertyMethod (MethodDefinition md)
579 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
580 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
583 static bool IsEventMethod (MethodDefinition md)
585 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
586 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
587 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
590 static PropertyDefinition GetProperty (MethodDefinition md)
592 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
593 foreach (PropertyDefinition prop in declaringType.Properties)
594 if (prop.GetMethod == md || prop.SetMethod == md)
595 return prop;
597 return null;
600 static EventDefinition GetEvent (MethodDefinition md)
602 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
603 foreach (EventDefinition evt in declaringType.Events)
604 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
605 return evt;
607 return null;
610 void MarkProperty (PropertyDefinition prop)
612 MarkCustomAttributes (prop);
615 void MarkEvent (EventDefinition evt)
617 MarkCustomAttributes (evt);
618 MarkMethodIfNotNull (evt.AddMethod);
619 MarkMethodIfNotNull (evt.InvokeMethod);
620 MarkMethodIfNotNull (evt.RemoveMethod);
623 void MarkMethodIfNotNull (MethodReference method)
625 if (method == null)
626 return;
628 MarkMethod (method);
631 void MarkInstruction (Instruction instruction)
633 switch (instruction.OpCode.OperandType) {
634 case OperandType.InlineField:
635 MarkField ((FieldReference) instruction.Operand);
636 break;
637 case OperandType.InlineMethod:
638 MarkMethod ((MethodReference) instruction.Operand);
639 break;
640 case OperandType.InlineTok:
641 object token = instruction.Operand;
642 if (token is TypeReference)
643 MarkType ((TypeReference) token);
644 else if (token is MethodReference)
645 MarkMethod ((MethodReference) token);
646 else
647 MarkField ((FieldReference) token);
648 break;
649 case OperandType.InlineType:
650 MarkType ((TypeReference) instruction.Operand);
651 break;
652 default:
653 break;