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 var at = argument.Type;
274 var et = at.GetElementType ();
275 if (et.Namespace != "System" || et.Name != "Type")
279 foreach (var cac in (CustomAttributeArgument[]) argument.Value)
280 MarkWithResolvedScope ((TypeReference) cac.Value);
281 } else if (at.Namespace == "System" && at.Name == "Type") {
282 MarkType (argument.Type);
283 MarkWithResolvedScope ((TypeReference) argument.Value);
287 // custom attributes encoding means it's possible to have a scope that will point into a PCL facade
288 // even if we (just before saving) will resolve all type references (bug #26752)
289 void MarkWithResolvedScope (TypeReference type)
291 // we cannot set the Scope of a TypeSpecification so there's no point in resolving it
292 if ((type == null) || (type is TypeSpecification))
294 var td = type.Resolve ();
296 type.Scope = td.Scope;
300 protected bool CheckProcessed (IMetadataTokenProvider provider)
302 if (Annotations.IsProcessed (provider))
305 Annotations.Processed (provider);
309 void MarkAssembly (AssemblyDefinition assembly)
311 if (CheckProcessed (assembly))
314 ProcessModule (assembly);
316 MarkCustomAttributes (assembly);
318 foreach (ModuleDefinition module in assembly.Modules)
319 MarkCustomAttributes (module);
322 void ProcessModule (AssemblyDefinition assembly)
324 // Pre-mark <Module> if there is any methods as they need to be executed
325 // at assembly load time
326 foreach (TypeDefinition type in assembly.MainModule.Types)
328 if (type.Name == "<Module>" && type.HasMethods)
336 protected void MarkField (FieldReference reference)
338 // if (IgnoreScope (reference.DeclaringType.Scope))
341 if (reference.DeclaringType is GenericInstanceType)
342 MarkType (reference.DeclaringType);
344 FieldDefinition field = ResolveFieldDefinition (reference);
347 throw new ResolutionException (reference);
349 if (CheckProcessed (field))
352 MarkType (field.DeclaringType);
353 MarkType (field.FieldType);
354 MarkCustomAttributes (field);
355 MarkMarshalSpec (field);
357 Annotations.Mark (field);
360 protected virtual bool IgnoreScope (IMetadataScope scope)
362 AssemblyDefinition assembly = ResolveAssembly (scope);
363 return Annotations.GetAction (assembly) != AssemblyAction.Link;
366 FieldDefinition ResolveFieldDefinition (FieldReference field)
368 FieldDefinition fd = field as FieldDefinition;
370 fd = field.Resolve ();
375 void MarkScope (IMetadataScope scope)
377 var provider = scope as IMetadataTokenProvider;
378 if (provider == null)
381 Annotations.Mark (provider);
384 protected virtual void MarkSerializable (TypeDefinition type)
386 MarkDefaultConstructor (type);
387 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
390 protected virtual TypeDefinition MarkType (TypeReference reference)
392 if (reference == null)
395 reference = GetOriginalType (reference);
397 if (reference is GenericParameter)
400 // if (IgnoreScope (reference.Scope))
403 TypeDefinition type = ResolveTypeDefinition (reference);
406 throw new ResolutionException (reference);
408 if (CheckProcessed (type))
411 MarkScope (type.Scope);
412 MarkType (type.BaseType);
413 MarkType (type.DeclaringType);
414 MarkCustomAttributes (type);
416 if (IsMulticastDelegate (type)) {
417 MarkMethodCollection (type.Methods);
420 if (IsSerializable (type))
421 MarkSerializable (type);
423 MarkTypeSpecialCustomAttributes (type);
425 MarkGenericParameterProvider (type);
427 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
428 if (type.IsValueType || !type.IsAutoLayout)
429 MarkFields (type, type.IsEnum);
431 if (type.HasInterfaces) {
432 foreach (TypeReference iface in type.Interfaces)
436 if (type.HasMethods) {
437 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
438 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
441 Annotations.Mark (type);
443 ApplyPreserveInfo (type);
448 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
450 if (!type.HasCustomAttributes)
453 foreach (CustomAttribute attribute in type.CustomAttributes) {
454 switch (attribute.Constructor.DeclaringType.FullName) {
455 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
456 MarkXmlSchemaProvider (type, attribute);
462 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
464 if (!method.HasCustomAttributes)
467 foreach (CustomAttribute attribute in method.CustomAttributes) {
468 switch (attribute.Constructor.DeclaringType.FullName) {
469 case "System.Web.Services.Protocols.SoapHeaderAttribute":
470 MarkSoapHeader (method, attribute);
476 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
479 if (!TryGetStringArgument (attribute, out method_name))
482 MarkNamedMethod (type, method_name);
485 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
489 if (attribute.ConstructorArguments.Count < 1)
492 argument = attribute.ConstructorArguments [0].Value as string;
494 return argument != null;
497 protected void MarkNamedMethod (TypeDefinition type, string method_name)
499 if (!type.HasMethods)
502 foreach (MethodDefinition method in type.Methods) {
503 if (method.Name != method_name)
510 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
513 if (!TryGetStringArgument (attribute, out member_name))
516 MarkNamedField (method.DeclaringType, member_name);
517 MarkNamedProperty (method.DeclaringType, member_name);
520 void MarkNamedField (TypeDefinition type, string field_name)
525 foreach (FieldDefinition field in type.Fields) {
526 if (field.Name != field_name)
533 void MarkNamedProperty (TypeDefinition type, string property_name)
535 if (!type.HasProperties)
538 foreach (PropertyDefinition property in type.Properties) {
539 if (property.Name != property_name)
542 MarkMethod (property.GetMethod);
543 MarkMethod (property.SetMethod);
547 void MarkGenericParameterProvider (IGenericParameterProvider provider)
549 if (!provider.HasGenericParameters)
552 foreach (GenericParameter parameter in provider.GenericParameters)
553 MarkGenericParameter (parameter);
556 void MarkGenericParameter (GenericParameter parameter)
558 MarkCustomAttributes (parameter);
559 foreach (TypeReference constraint in parameter.Constraints)
560 MarkType (constraint);
563 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
565 if (!method.IsVirtual)
568 var base_list = Annotations.GetBaseMethods (method);
569 if (base_list == null)
572 foreach (MethodDefinition @base in base_list) {
573 if (IgnoreScope (@base.DeclaringType.Scope))
576 if (IsVirtualAndHasPreservedParent (@base))
583 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
585 static bool IsSpecialSerializationConstructor (MethodDefinition method)
587 if (!IsConstructor (method))
590 var parameters = method.Parameters;
591 if (parameters.Count != 2)
594 return parameters [0].ParameterType.Name == "SerializationInfo" &&
595 parameters [1].ParameterType.Name == "StreamingContext";
598 delegate bool MethodPredicate (MethodDefinition method);
600 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
602 foreach (MethodDefinition method in methods)
603 if (predicate (method))
607 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
609 static bool IsDefaultConstructor (MethodDefinition method)
611 return IsConstructor (method) && !method.HasParameters;
614 static bool IsConstructor (MethodDefinition method)
616 return method.IsConstructor && !method.IsStatic;
619 protected void MarkDefaultConstructor (TypeDefinition type)
621 if ((type == null) || !type.HasMethods)
624 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
627 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
629 static bool IsStaticConstructor (MethodDefinition method)
631 return method.IsConstructor && method.IsStatic;
634 static bool IsSerializable (TypeDefinition td)
636 return (td.Attributes & TypeAttributes.Serializable) != 0;
639 static bool IsMulticastDelegate (TypeDefinition td)
641 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
644 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
646 TypeDefinition td = type as TypeDefinition;
648 td = type.Resolve ();
653 protected TypeReference GetOriginalType (TypeReference type)
655 while (type is TypeSpecification) {
656 GenericInstanceType git = type as GenericInstanceType;
658 MarkGenericArguments (git);
660 var mod = type as IModifierType;
662 MarkModifierType (mod);
664 type = ((TypeSpecification) type).ElementType;
670 void MarkModifierType (IModifierType mod)
672 MarkType (mod.ModifierType);
675 void MarkGenericArguments (IGenericInstance instance)
677 foreach (TypeReference argument in instance.GenericArguments)
680 MarkGenericArgumentConstructors (instance);
683 void MarkGenericArgumentConstructors (IGenericInstance instance)
685 var arguments = instance.GenericArguments;
687 var generic_element = GetGenericProviderFromInstance (instance);
688 if (generic_element == null)
691 var parameters = generic_element.GenericParameters;
693 if (arguments.Count != parameters.Count)
696 for (int i = 0; i < arguments.Count; i++) {
697 var argument = arguments [i];
698 var parameter = parameters [i];
700 if (!parameter.HasDefaultConstructorConstraint)
703 var argument_definition = ResolveTypeDefinition (argument);
704 if (argument_definition == null)
707 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
711 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
713 var method = instance as GenericInstanceMethod;
715 return ResolveMethodDefinition (method.ElementMethod);
717 var type = instance as GenericInstanceType;
719 return ResolveTypeDefinition (type.ElementType);
724 void ApplyPreserveInfo (TypeDefinition type)
726 ApplyPreserveMethods (type);
728 if (!Annotations.IsPreserved (type))
731 switch (Annotations.GetPreserve (type)) {
732 case TypePreserve.All:
733 MarkFields (type, true);
736 case TypePreserve.Fields:
737 MarkFields (type, true);
739 case TypePreserve.Methods:
745 void ApplyPreserveMethods (TypeDefinition type)
747 var list = Annotations.GetPreservedMethods (type);
751 MarkMethodCollection (list);
754 void ApplyPreserveMethods (MethodDefinition method)
756 var list = Annotations.GetPreservedMethods (method);
760 MarkMethodCollection (list);
763 protected void MarkFields (TypeDefinition type, bool includeStatic)
768 foreach (FieldDefinition field in type.Fields) {
769 if (!includeStatic && field.IsStatic)
775 protected virtual void MarkMethods (TypeDefinition type)
778 MarkMethodCollection (type.Methods);
781 void MarkMethodCollection (IEnumerable methods)
783 foreach (MethodDefinition method in methods)
787 protected virtual MethodDefinition MarkMethod (MethodReference reference)
789 reference = GetOriginalMethod (reference);
791 if (reference.DeclaringType is ArrayType)
794 if (reference.DeclaringType is GenericInstanceType)
795 MarkType (reference.DeclaringType);
797 // if (IgnoreScope (reference.DeclaringType.Scope))
800 MethodDefinition method = ResolveMethodDefinition (reference);
803 throw new ResolutionException (reference);
805 if (Annotations.GetAction (method) == MethodAction.Nothing)
806 Annotations.SetAction (method, MethodAction.Parse);
808 EnqueueMethod (method);
812 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
814 AssemblyDefinition assembly = _context.Resolve (scope);
815 MarkAssembly (assembly);
819 protected MethodReference GetOriginalMethod (MethodReference method)
821 while (method is MethodSpecification) {
822 GenericInstanceMethod gim = method as GenericInstanceMethod;
824 MarkGenericArguments (gim);
826 method = ((MethodSpecification) method).ElementMethod;
832 MethodDefinition ResolveMethodDefinition (MethodReference method)
834 MethodDefinition md = method as MethodDefinition;
836 md = method.Resolve ();
841 protected virtual void ProcessMethod (MethodDefinition method)
843 if (CheckProcessed (method))
846 MarkType (method.DeclaringType);
847 MarkCustomAttributes (method);
849 MarkGenericParameterProvider (method);
851 if (IsPropertyMethod (method))
852 MarkProperty (GetProperty (method));
853 else if (IsEventMethod (method))
854 MarkEvent (GetEvent (method));
856 if (method.HasParameters) {
857 foreach (ParameterDefinition pd in method.Parameters) {
858 MarkType (pd.ParameterType);
859 MarkCustomAttributes (pd);
860 MarkMarshalSpec (pd);
864 if (method.HasOverrides) {
865 foreach (MethodReference ov in method.Overrides)
869 MarkMethodSpecialCustomAttributes (method);
871 if (method.IsVirtual)
872 _virtual_methods.Add (method);
874 MarkBaseMethods (method);
876 MarkType (method.ReturnType);
877 MarkCustomAttributes (method.MethodReturnType);
878 MarkMarshalSpec (method.MethodReturnType);
880 if (ShouldParseMethodBody (method))
881 MarkMethodBody (method.Body);
883 Annotations.Mark (method);
885 ApplyPreserveMethods (method);
888 void MarkBaseMethods (MethodDefinition method)
890 IList base_methods = Annotations.GetBaseMethods (method);
891 if (base_methods == null)
894 foreach (MethodDefinition base_method in base_methods) {
895 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
898 MarkMethod (base_method);
899 MarkBaseMethods (base_method);
903 bool ShouldParseMethodBody (MethodDefinition method)
908 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
909 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
910 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
913 static internal bool IsPropertyMethod (MethodDefinition md)
915 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
916 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
919 static bool IsEventMethod (MethodDefinition md)
921 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
922 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
923 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
926 static internal PropertyDefinition GetProperty (MethodDefinition md)
928 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
929 foreach (PropertyDefinition prop in declaringType.Properties)
930 if (prop.GetMethod == md || prop.SetMethod == md)
936 static EventDefinition GetEvent (MethodDefinition md)
938 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
939 foreach (EventDefinition evt in declaringType.Events)
940 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
946 protected void MarkProperty (PropertyDefinition prop)
948 MarkCustomAttributes (prop);
951 protected void MarkEvent (EventDefinition evt)
953 MarkCustomAttributes (evt);
954 MarkMethodIfNotNull (evt.AddMethod);
955 MarkMethodIfNotNull (evt.InvokeMethod);
956 MarkMethodIfNotNull (evt.RemoveMethod);
959 void MarkMethodIfNotNull (MethodReference method)
967 protected virtual void MarkMethodBody (MethodBody body)
969 foreach (VariableDefinition var in body.Variables)
970 MarkType (var.VariableType);
972 foreach (ExceptionHandler eh in body.ExceptionHandlers)
973 if (eh.HandlerType == ExceptionHandlerType.Catch)
974 MarkType (eh.CatchType);
976 foreach (Instruction instruction in body.Instructions)
977 MarkInstruction (instruction);
980 protected virtual void MarkInstruction (Instruction instruction)
982 switch (instruction.OpCode.OperandType) {
983 case OperandType.InlineField:
984 MarkField ((FieldReference) instruction.Operand);
986 case OperandType.InlineMethod:
987 MarkMethod ((MethodReference) instruction.Operand);
989 case OperandType.InlineTok:
990 object token = instruction.Operand;
991 if (token is TypeReference)
992 MarkType ((TypeReference) token);
993 else if (token is MethodReference)
994 MarkMethod ((MethodReference) token);
996 MarkField ((FieldReference) token);
998 case OperandType.InlineType:
999 MarkType ((TypeReference) instruction.Operand);