5 // Jb Evain (jbevain@gmail.com)
8 // (C) 2007 Novell, Inc.
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.
31 using System.Collections;
37 namespace Mono.Linker.Steps {
39 public class MarkStep : IStep {
41 protected LinkContext _context;
42 protected Queue _methods;
43 protected ArrayList _virtual_methods;
45 public AnnotationStore Annotations {
46 get { return _context.Annotations; }
51 _methods = new Queue ();
52 _virtual_methods = new ArrayList ();
55 public virtual void Process (LinkContext context)
65 foreach (AssemblyDefinition assembly in _context.GetAssemblies ())
66 InitializeAssembly (assembly);
69 protected virtual void InitializeAssembly (AssemblyDefinition assembly)
71 MarkAssembly (assembly);
72 foreach (TypeDefinition type in assembly.MainModule.Types) {
73 if (!Annotations.IsMarked (type))
76 InitializeType (type);
80 void InitializeType (TypeDefinition type)
85 InitializeFields (type);
87 InitializeMethods (type.Methods);
89 if (type.HasNestedTypes) {
90 foreach (var nested in type.NestedTypes) {
91 if (Annotations.IsMarked (nested))
92 InitializeType (nested);
97 void InitializeFields (TypeDefinition type)
99 foreach (FieldDefinition field in type.Fields)
100 if (Annotations.IsMarked (field))
104 void InitializeMethods (ICollection methods)
106 foreach (MethodDefinition method in methods)
107 if (Annotations.IsMarked (method))
108 EnqueueMethod (method);
114 throw new InvalidOperationException ("No entry methods");
116 while (!QueueIsEmpty ()) {
118 ProcessVirtualMethods ();
124 while (!QueueIsEmpty ()) {
125 MethodDefinition method = (MethodDefinition) _methods.Dequeue ();
126 ProcessMethod (method);
132 return _methods.Count == 0;
135 protected virtual void EnqueueMethod (MethodDefinition method)
137 _methods.Enqueue (method);
140 void ProcessVirtualMethods ()
142 foreach (MethodDefinition method in _virtual_methods)
143 ProcessVirtualMethod (method);
146 void ProcessVirtualMethod (MethodDefinition method)
148 IList overrides = Annotations.GetOverrides (method);
149 if (overrides == null)
152 foreach (MethodDefinition @override in overrides)
153 ProcessOverride (@override);
156 void ProcessOverride (MethodDefinition method)
158 if (!Annotations.IsMarked (method.DeclaringType))
161 if (Annotations.IsProcessed (method))
164 if (Annotations.IsMarked (method))
168 ProcessVirtualMethod (method);
171 void MarkMarshalSpec (IMarshalInfoProvider spec)
173 if (!spec.HasMarshalInfo)
176 var marshaler = spec.MarshalInfo as CustomMarshalInfo;
177 if (marshaler == null)
180 MarkType (marshaler.ManagedType);
183 void MarkCustomAttributes (ICustomAttributeProvider provider)
185 if (!provider.HasCustomAttributes)
188 foreach (CustomAttribute ca in provider.CustomAttributes)
189 MarkCustomAttribute (ca);
192 protected virtual void MarkCustomAttribute (CustomAttribute ca)
194 MarkMethod (ca.Constructor);
196 MarkCustomAttributeArguments (ca);
198 TypeReference constructor_type = ca.Constructor.DeclaringType;
199 TypeDefinition type = constructor_type.Resolve ();
201 throw new ResolutionException (constructor_type);
203 MarkCustomAttributeProperties (ca, type);
204 MarkCustomAttributeFields (ca, type);
207 void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute)
209 if (!ca.HasProperties)
212 foreach (var named_argument in ca.Properties) {
213 PropertyDefinition property = GetProperty (attribute, named_argument.Name);
214 if (property != null)
215 MarkMethod (property.SetMethod);
217 MarkIfType (named_argument.Argument);
221 PropertyDefinition GetProperty (TypeDefinition type, string propertyname)
223 while (type != null) {
224 PropertyDefinition property = type.Properties.FirstOrDefault (p => p.Name == propertyname);
225 if (property != null)
228 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
234 void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute)
239 foreach (var named_argument in ca.Fields) {
240 FieldDefinition field = GetField (attribute, named_argument.Name);
244 MarkIfType (named_argument.Argument);
248 FieldDefinition GetField (TypeDefinition type, string fieldname)
250 while (type != null) {
251 FieldDefinition field = type.Fields.FirstOrDefault (f => f.Name == fieldname);
255 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
261 void MarkCustomAttributeArguments (CustomAttribute ca)
263 if (!ca.HasConstructorArguments)
266 foreach (var argument in ca.ConstructorArguments)
267 MarkIfType (argument);
270 void MarkIfType (CustomAttributeArgument argument)
272 if (argument.Type.FullName != "System.Type")
275 MarkType (argument.Type);
276 MarkType ((TypeReference) argument.Value);
279 protected bool CheckProcessed (IMetadataTokenProvider provider)
281 if (Annotations.IsProcessed (provider))
284 Annotations.Processed (provider);
288 void MarkAssembly (AssemblyDefinition assembly)
290 if (CheckProcessed (assembly))
293 ProcessModule (assembly);
295 MarkCustomAttributes (assembly);
297 foreach (ModuleDefinition module in assembly.Modules)
298 MarkCustomAttributes (module);
301 void ProcessModule (AssemblyDefinition assembly)
303 // Pre-mark <Module> if there is any methods as they need to be executed
304 // at assembly load time
305 foreach (TypeDefinition type in assembly.MainModule.Types)
307 if (type.Name == "<Module>" && type.HasMethods)
315 protected void MarkField (FieldReference reference)
317 // if (IgnoreScope (reference.DeclaringType.Scope))
320 if (reference.DeclaringType is GenericInstanceType)
321 MarkType (reference.DeclaringType);
323 FieldDefinition field = ResolveFieldDefinition (reference);
326 throw new ResolutionException (reference);
328 if (CheckProcessed (field))
331 MarkType (field.DeclaringType);
332 MarkType (field.FieldType);
333 MarkCustomAttributes (field);
334 MarkMarshalSpec (field);
336 Annotations.Mark (field);
339 protected virtual bool IgnoreScope (IMetadataScope scope)
341 AssemblyDefinition assembly = ResolveAssembly (scope);
342 return Annotations.GetAction (assembly) != AssemblyAction.Link;
345 FieldDefinition ResolveFieldDefinition (FieldReference field)
347 FieldDefinition fd = field as FieldDefinition;
349 fd = field.Resolve ();
354 void MarkScope (IMetadataScope scope)
356 var provider = scope as IMetadataTokenProvider;
357 if (provider == null)
360 Annotations.Mark (provider);
363 protected virtual void MarkSerializable (TypeDefinition type)
365 MarkDefaultConstructor (type);
366 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
369 protected virtual TypeDefinition MarkType (TypeReference reference)
371 if (reference == null)
374 reference = GetOriginalType (reference);
376 if (reference is GenericParameter)
379 // if (IgnoreScope (reference.Scope))
382 TypeDefinition type = ResolveTypeDefinition (reference);
385 throw new ResolutionException (reference);
387 if (CheckProcessed (type))
390 MarkScope (type.Scope);
391 MarkType (type.BaseType);
392 MarkType (type.DeclaringType);
393 MarkCustomAttributes (type);
395 if (IsMulticastDelegate (type)) {
396 MarkMethodCollection (type.Methods);
399 if (IsSerializable (type))
400 MarkSerializable (type);
402 MarkTypeSpecialCustomAttributes (type);
404 MarkGenericParameterProvider (type);
406 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
407 if (type.IsValueType || !type.IsAutoLayout)
408 MarkFields (type, type.IsEnum);
410 if (type.HasInterfaces) {
411 foreach (TypeReference iface in type.Interfaces)
415 if (type.HasMethods) {
416 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
417 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
420 Annotations.Mark (type);
422 ApplyPreserveInfo (type);
427 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
429 if (!type.HasCustomAttributes)
432 foreach (CustomAttribute attribute in type.CustomAttributes) {
433 switch (attribute.Constructor.DeclaringType.FullName) {
434 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
435 MarkXmlSchemaProvider (type, attribute);
441 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
443 if (!method.HasCustomAttributes)
446 foreach (CustomAttribute attribute in method.CustomAttributes) {
447 switch (attribute.Constructor.DeclaringType.FullName) {
448 case "System.Web.Services.Protocols.SoapHeaderAttribute":
449 MarkSoapHeader (method, attribute);
455 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
458 if (!TryGetStringArgument (attribute, out method_name))
461 MarkNamedMethod (type, method_name);
464 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
468 if (attribute.ConstructorArguments.Count < 1)
471 argument = attribute.ConstructorArguments [0].Value as string;
473 return argument != null;
476 protected void MarkNamedMethod (TypeDefinition type, string method_name)
478 if (!type.HasMethods)
481 foreach (MethodDefinition method in type.Methods) {
482 if (method.Name != method_name)
489 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
492 if (!TryGetStringArgument (attribute, out member_name))
495 MarkNamedField (method.DeclaringType, member_name);
496 MarkNamedProperty (method.DeclaringType, member_name);
499 void MarkNamedField (TypeDefinition type, string field_name)
504 foreach (FieldDefinition field in type.Fields) {
505 if (field.Name != field_name)
512 void MarkNamedProperty (TypeDefinition type, string property_name)
514 if (!type.HasProperties)
517 foreach (PropertyDefinition property in type.Properties) {
518 if (property.Name != property_name)
521 MarkMethod (property.GetMethod);
522 MarkMethod (property.SetMethod);
526 void MarkGenericParameterProvider (IGenericParameterProvider provider)
528 if (!provider.HasGenericParameters)
531 foreach (GenericParameter parameter in provider.GenericParameters)
532 MarkGenericParameter (parameter);
535 void MarkGenericParameter (GenericParameter parameter)
537 MarkCustomAttributes (parameter);
538 foreach (TypeReference constraint in parameter.Constraints)
539 MarkType (constraint);
542 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
544 if (!method.IsVirtual)
547 var base_list = Annotations.GetBaseMethods (method);
548 if (base_list == null)
551 foreach (MethodDefinition @base in base_list) {
552 if (IgnoreScope (@base.DeclaringType.Scope))
555 if (IsVirtualAndHasPreservedParent (@base))
562 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
564 static bool IsSpecialSerializationConstructor (MethodDefinition method)
566 if (!IsConstructor (method))
569 var parameters = method.Parameters;
570 if (parameters.Count != 2)
573 return parameters [0].ParameterType.Name == "SerializationInfo" &&
574 parameters [1].ParameterType.Name == "StreamingContext";
577 delegate bool MethodPredicate (MethodDefinition method);
579 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
581 foreach (MethodDefinition method in methods)
582 if (predicate (method))
586 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
588 static bool IsDefaultConstructor (MethodDefinition method)
590 return IsConstructor (method) && !method.HasParameters;
593 static bool IsConstructor (MethodDefinition method)
595 return method.IsConstructor && !method.IsStatic;
598 protected void MarkDefaultConstructor (TypeDefinition type)
600 if ((type == null) || !type.HasMethods)
603 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
606 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
608 static bool IsStaticConstructor (MethodDefinition method)
610 return method.IsConstructor && method.IsStatic;
613 static bool IsSerializable (TypeDefinition td)
615 return (td.Attributes & TypeAttributes.Serializable) != 0;
618 static bool IsMulticastDelegate (TypeDefinition td)
620 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
623 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
625 TypeDefinition td = type as TypeDefinition;
627 td = type.Resolve ();
632 protected TypeReference GetOriginalType (TypeReference type)
634 while (type is TypeSpecification) {
635 GenericInstanceType git = type as GenericInstanceType;
637 MarkGenericArguments (git);
639 var mod = type as IModifierType;
641 MarkModifierType (mod);
643 type = ((TypeSpecification) type).ElementType;
649 void MarkModifierType (IModifierType mod)
651 MarkType (mod.ModifierType);
654 void MarkGenericArguments (IGenericInstance instance)
656 foreach (TypeReference argument in instance.GenericArguments)
659 MarkGenericArgumentConstructors (instance);
662 void MarkGenericArgumentConstructors (IGenericInstance instance)
664 var arguments = instance.GenericArguments;
666 var generic_element = GetGenericProviderFromInstance (instance);
667 if (generic_element == null)
670 var parameters = generic_element.GenericParameters;
672 if (arguments.Count != parameters.Count)
675 for (int i = 0; i < arguments.Count; i++) {
676 var argument = arguments [i];
677 var parameter = parameters [i];
679 if (!parameter.HasDefaultConstructorConstraint)
682 var argument_definition = ResolveTypeDefinition (argument);
683 if (argument_definition == null)
686 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
690 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
692 var method = instance as GenericInstanceMethod;
694 return ResolveMethodDefinition (method.ElementMethod);
696 var type = instance as GenericInstanceType;
698 return ResolveTypeDefinition (type.ElementType);
703 void ApplyPreserveInfo (TypeDefinition type)
705 ApplyPreserveMethods (type);
707 if (!Annotations.IsPreserved (type))
710 switch (Annotations.GetPreserve (type)) {
711 case TypePreserve.All:
712 MarkFields (type, true);
715 case TypePreserve.Fields:
716 MarkFields (type, true);
718 case TypePreserve.Methods:
724 void ApplyPreserveMethods (TypeDefinition type)
726 var list = Annotations.GetPreservedMethods (type);
730 MarkMethodCollection (list);
733 void ApplyPreserveMethods (MethodDefinition method)
735 var list = Annotations.GetPreservedMethods (method);
739 MarkMethodCollection (list);
742 protected void MarkFields (TypeDefinition type, bool includeStatic)
747 foreach (FieldDefinition field in type.Fields) {
748 if (!includeStatic && field.IsStatic)
754 protected virtual void MarkMethods (TypeDefinition type)
757 MarkMethodCollection (type.Methods);
760 void MarkMethodCollection (IEnumerable methods)
762 foreach (MethodDefinition method in methods)
766 protected virtual MethodDefinition MarkMethod (MethodReference reference)
768 reference = GetOriginalMethod (reference);
770 if (reference.DeclaringType is ArrayType)
773 if (reference.DeclaringType is GenericInstanceType)
774 MarkType (reference.DeclaringType);
776 // if (IgnoreScope (reference.DeclaringType.Scope))
779 MethodDefinition method = ResolveMethodDefinition (reference);
782 throw new ResolutionException (reference);
784 if (Annotations.GetAction (method) == MethodAction.Nothing)
785 Annotations.SetAction (method, MethodAction.Parse);
787 EnqueueMethod (method);
791 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
793 AssemblyDefinition assembly = _context.Resolve (scope);
794 MarkAssembly (assembly);
798 protected MethodReference GetOriginalMethod (MethodReference method)
800 while (method is MethodSpecification) {
801 GenericInstanceMethod gim = method as GenericInstanceMethod;
803 MarkGenericArguments (gim);
805 method = ((MethodSpecification) method).ElementMethod;
811 MethodDefinition ResolveMethodDefinition (MethodReference method)
813 MethodDefinition md = method as MethodDefinition;
815 md = method.Resolve ();
820 protected virtual void ProcessMethod (MethodDefinition method)
822 if (CheckProcessed (method))
825 MarkType (method.DeclaringType);
826 MarkCustomAttributes (method);
828 MarkGenericParameterProvider (method);
830 if (IsPropertyMethod (method))
831 MarkProperty (GetProperty (method));
832 else if (IsEventMethod (method))
833 MarkEvent (GetEvent (method));
835 if (method.HasParameters) {
836 foreach (ParameterDefinition pd in method.Parameters) {
837 MarkType (pd.ParameterType);
838 MarkCustomAttributes (pd);
839 MarkMarshalSpec (pd);
843 if (method.HasOverrides) {
844 foreach (MethodReference ov in method.Overrides)
848 MarkMethodSpecialCustomAttributes (method);
850 if (method.IsVirtual)
851 _virtual_methods.Add (method);
853 MarkBaseMethods (method);
855 MarkType (method.ReturnType);
856 MarkCustomAttributes (method.MethodReturnType);
857 MarkMarshalSpec (method.MethodReturnType);
859 if (ShouldParseMethodBody (method))
860 MarkMethodBody (method.Body);
862 Annotations.Mark (method);
864 ApplyPreserveMethods (method);
867 void MarkBaseMethods (MethodDefinition method)
869 IList base_methods = Annotations.GetBaseMethods (method);
870 if (base_methods == null)
873 foreach (MethodDefinition base_method in base_methods) {
874 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
877 MarkMethod (base_method);
878 MarkBaseMethods (base_method);
882 bool ShouldParseMethodBody (MethodDefinition method)
887 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
888 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
889 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
892 static internal bool IsPropertyMethod (MethodDefinition md)
894 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
895 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
898 static bool IsEventMethod (MethodDefinition md)
900 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
901 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
902 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
905 static internal PropertyDefinition GetProperty (MethodDefinition md)
907 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
908 foreach (PropertyDefinition prop in declaringType.Properties)
909 if (prop.GetMethod == md || prop.SetMethod == md)
915 static EventDefinition GetEvent (MethodDefinition md)
917 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
918 foreach (EventDefinition evt in declaringType.Events)
919 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
925 protected void MarkProperty (PropertyDefinition prop)
927 MarkCustomAttributes (prop);
930 protected void MarkEvent (EventDefinition evt)
932 MarkCustomAttributes (evt);
933 MarkMethodIfNotNull (evt.AddMethod);
934 MarkMethodIfNotNull (evt.InvokeMethod);
935 MarkMethodIfNotNull (evt.RemoveMethod);
938 void MarkMethodIfNotNull (MethodReference method)
946 protected virtual void MarkMethodBody (MethodBody body)
948 foreach (VariableDefinition var in body.Variables)
949 MarkType (var.VariableType);
951 foreach (ExceptionHandler eh in body.ExceptionHandlers)
952 if (eh.HandlerType == ExceptionHandlerType.Catch)
953 MarkType (eh.CatchType);
955 foreach (Instruction instruction in body.Instructions)
956 MarkInstruction (instruction);
959 protected virtual void MarkInstruction (Instruction instruction)
961 switch (instruction.OpCode.OperandType) {
962 case OperandType.InlineField:
963 MarkField ((FieldReference) instruction.Operand);
965 case OperandType.InlineMethod:
966 MarkMethod ((MethodReference) instruction.Operand);
968 case OperandType.InlineTok:
969 object token = instruction.Operand;
970 if (token is TypeReference)
971 MarkType ((TypeReference) token);
972 else if (token is MethodReference)
973 MarkMethod ((MethodReference) token);
975 MarkField ((FieldReference) token);
977 case OperandType.InlineType:
978 MarkType ((TypeReference) instruction.Operand);