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)
293 var td = type.Resolve ();
295 type.Scope = td.Scope;
299 protected bool CheckProcessed (IMetadataTokenProvider provider)
301 if (Annotations.IsProcessed (provider))
304 Annotations.Processed (provider);
308 void MarkAssembly (AssemblyDefinition assembly)
310 if (CheckProcessed (assembly))
313 ProcessModule (assembly);
315 MarkCustomAttributes (assembly);
317 foreach (ModuleDefinition module in assembly.Modules)
318 MarkCustomAttributes (module);
321 void ProcessModule (AssemblyDefinition assembly)
323 // Pre-mark <Module> if there is any methods as they need to be executed
324 // at assembly load time
325 foreach (TypeDefinition type in assembly.MainModule.Types)
327 if (type.Name == "<Module>" && type.HasMethods)
335 protected void MarkField (FieldReference reference)
337 // if (IgnoreScope (reference.DeclaringType.Scope))
340 if (reference.DeclaringType is GenericInstanceType)
341 MarkType (reference.DeclaringType);
343 FieldDefinition field = ResolveFieldDefinition (reference);
346 throw new ResolutionException (reference);
348 if (CheckProcessed (field))
351 MarkType (field.DeclaringType);
352 MarkType (field.FieldType);
353 MarkCustomAttributes (field);
354 MarkMarshalSpec (field);
356 Annotations.Mark (field);
359 protected virtual bool IgnoreScope (IMetadataScope scope)
361 AssemblyDefinition assembly = ResolveAssembly (scope);
362 return Annotations.GetAction (assembly) != AssemblyAction.Link;
365 FieldDefinition ResolveFieldDefinition (FieldReference field)
367 FieldDefinition fd = field as FieldDefinition;
369 fd = field.Resolve ();
374 void MarkScope (IMetadataScope scope)
376 var provider = scope as IMetadataTokenProvider;
377 if (provider == null)
380 Annotations.Mark (provider);
383 protected virtual void MarkSerializable (TypeDefinition type)
385 MarkDefaultConstructor (type);
386 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
389 protected virtual TypeDefinition MarkType (TypeReference reference)
391 if (reference == null)
394 reference = GetOriginalType (reference);
396 if (reference is GenericParameter)
399 // if (IgnoreScope (reference.Scope))
402 TypeDefinition type = ResolveTypeDefinition (reference);
405 throw new ResolutionException (reference);
407 if (CheckProcessed (type))
410 MarkScope (type.Scope);
411 MarkType (type.BaseType);
412 MarkType (type.DeclaringType);
413 MarkCustomAttributes (type);
415 if (IsMulticastDelegate (type)) {
416 MarkMethodCollection (type.Methods);
419 if (IsSerializable (type))
420 MarkSerializable (type);
422 MarkTypeSpecialCustomAttributes (type);
424 MarkGenericParameterProvider (type);
426 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
427 if (type.IsValueType || !type.IsAutoLayout)
428 MarkFields (type, type.IsEnum);
430 if (type.HasInterfaces) {
431 foreach (TypeReference iface in type.Interfaces)
435 if (type.HasMethods) {
436 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
437 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
440 Annotations.Mark (type);
442 ApplyPreserveInfo (type);
447 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
449 if (!type.HasCustomAttributes)
452 foreach (CustomAttribute attribute in type.CustomAttributes) {
453 switch (attribute.Constructor.DeclaringType.FullName) {
454 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
455 MarkXmlSchemaProvider (type, attribute);
461 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
463 if (!method.HasCustomAttributes)
466 foreach (CustomAttribute attribute in method.CustomAttributes) {
467 switch (attribute.Constructor.DeclaringType.FullName) {
468 case "System.Web.Services.Protocols.SoapHeaderAttribute":
469 MarkSoapHeader (method, attribute);
475 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
478 if (!TryGetStringArgument (attribute, out method_name))
481 MarkNamedMethod (type, method_name);
484 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
488 if (attribute.ConstructorArguments.Count < 1)
491 argument = attribute.ConstructorArguments [0].Value as string;
493 return argument != null;
496 protected void MarkNamedMethod (TypeDefinition type, string method_name)
498 if (!type.HasMethods)
501 foreach (MethodDefinition method in type.Methods) {
502 if (method.Name != method_name)
509 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
512 if (!TryGetStringArgument (attribute, out member_name))
515 MarkNamedField (method.DeclaringType, member_name);
516 MarkNamedProperty (method.DeclaringType, member_name);
519 void MarkNamedField (TypeDefinition type, string field_name)
524 foreach (FieldDefinition field in type.Fields) {
525 if (field.Name != field_name)
532 void MarkNamedProperty (TypeDefinition type, string property_name)
534 if (!type.HasProperties)
537 foreach (PropertyDefinition property in type.Properties) {
538 if (property.Name != property_name)
541 MarkMethod (property.GetMethod);
542 MarkMethod (property.SetMethod);
546 void MarkGenericParameterProvider (IGenericParameterProvider provider)
548 if (!provider.HasGenericParameters)
551 foreach (GenericParameter parameter in provider.GenericParameters)
552 MarkGenericParameter (parameter);
555 void MarkGenericParameter (GenericParameter parameter)
557 MarkCustomAttributes (parameter);
558 foreach (TypeReference constraint in parameter.Constraints)
559 MarkType (constraint);
562 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
564 if (!method.IsVirtual)
567 var base_list = Annotations.GetBaseMethods (method);
568 if (base_list == null)
571 foreach (MethodDefinition @base in base_list) {
572 if (IgnoreScope (@base.DeclaringType.Scope))
575 if (IsVirtualAndHasPreservedParent (@base))
582 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
584 static bool IsSpecialSerializationConstructor (MethodDefinition method)
586 if (!IsConstructor (method))
589 var parameters = method.Parameters;
590 if (parameters.Count != 2)
593 return parameters [0].ParameterType.Name == "SerializationInfo" &&
594 parameters [1].ParameterType.Name == "StreamingContext";
597 delegate bool MethodPredicate (MethodDefinition method);
599 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
601 foreach (MethodDefinition method in methods)
602 if (predicate (method))
606 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
608 static bool IsDefaultConstructor (MethodDefinition method)
610 return IsConstructor (method) && !method.HasParameters;
613 static bool IsConstructor (MethodDefinition method)
615 return method.IsConstructor && !method.IsStatic;
618 protected void MarkDefaultConstructor (TypeDefinition type)
620 if ((type == null) || !type.HasMethods)
623 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
626 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
628 static bool IsStaticConstructor (MethodDefinition method)
630 return method.IsConstructor && method.IsStatic;
633 static bool IsSerializable (TypeDefinition td)
635 return (td.Attributes & TypeAttributes.Serializable) != 0;
638 static bool IsMulticastDelegate (TypeDefinition td)
640 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
643 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
645 TypeDefinition td = type as TypeDefinition;
647 td = type.Resolve ();
652 protected TypeReference GetOriginalType (TypeReference type)
654 while (type is TypeSpecification) {
655 GenericInstanceType git = type as GenericInstanceType;
657 MarkGenericArguments (git);
659 var mod = type as IModifierType;
661 MarkModifierType (mod);
663 type = ((TypeSpecification) type).ElementType;
669 void MarkModifierType (IModifierType mod)
671 MarkType (mod.ModifierType);
674 void MarkGenericArguments (IGenericInstance instance)
676 foreach (TypeReference argument in instance.GenericArguments)
679 MarkGenericArgumentConstructors (instance);
682 void MarkGenericArgumentConstructors (IGenericInstance instance)
684 var arguments = instance.GenericArguments;
686 var generic_element = GetGenericProviderFromInstance (instance);
687 if (generic_element == null)
690 var parameters = generic_element.GenericParameters;
692 if (arguments.Count != parameters.Count)
695 for (int i = 0; i < arguments.Count; i++) {
696 var argument = arguments [i];
697 var parameter = parameters [i];
699 if (!parameter.HasDefaultConstructorConstraint)
702 var argument_definition = ResolveTypeDefinition (argument);
703 if (argument_definition == null)
706 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
710 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
712 var method = instance as GenericInstanceMethod;
714 return ResolveMethodDefinition (method.ElementMethod);
716 var type = instance as GenericInstanceType;
718 return ResolveTypeDefinition (type.ElementType);
723 void ApplyPreserveInfo (TypeDefinition type)
725 ApplyPreserveMethods (type);
727 if (!Annotations.IsPreserved (type))
730 switch (Annotations.GetPreserve (type)) {
731 case TypePreserve.All:
732 MarkFields (type, true);
735 case TypePreserve.Fields:
736 MarkFields (type, true);
738 case TypePreserve.Methods:
744 void ApplyPreserveMethods (TypeDefinition type)
746 var list = Annotations.GetPreservedMethods (type);
750 MarkMethodCollection (list);
753 void ApplyPreserveMethods (MethodDefinition method)
755 var list = Annotations.GetPreservedMethods (method);
759 MarkMethodCollection (list);
762 protected void MarkFields (TypeDefinition type, bool includeStatic)
767 foreach (FieldDefinition field in type.Fields) {
768 if (!includeStatic && field.IsStatic)
774 protected virtual void MarkMethods (TypeDefinition type)
777 MarkMethodCollection (type.Methods);
780 void MarkMethodCollection (IEnumerable methods)
782 foreach (MethodDefinition method in methods)
786 protected virtual MethodDefinition MarkMethod (MethodReference reference)
788 reference = GetOriginalMethod (reference);
790 if (reference.DeclaringType is ArrayType)
793 if (reference.DeclaringType is GenericInstanceType)
794 MarkType (reference.DeclaringType);
796 // if (IgnoreScope (reference.DeclaringType.Scope))
799 MethodDefinition method = ResolveMethodDefinition (reference);
802 throw new ResolutionException (reference);
804 if (Annotations.GetAction (method) == MethodAction.Nothing)
805 Annotations.SetAction (method, MethodAction.Parse);
807 EnqueueMethod (method);
811 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
813 AssemblyDefinition assembly = _context.Resolve (scope);
814 MarkAssembly (assembly);
818 protected MethodReference GetOriginalMethod (MethodReference method)
820 while (method is MethodSpecification) {
821 GenericInstanceMethod gim = method as GenericInstanceMethod;
823 MarkGenericArguments (gim);
825 method = ((MethodSpecification) method).ElementMethod;
831 MethodDefinition ResolveMethodDefinition (MethodReference method)
833 MethodDefinition md = method as MethodDefinition;
835 md = method.Resolve ();
840 protected virtual void ProcessMethod (MethodDefinition method)
842 if (CheckProcessed (method))
845 MarkType (method.DeclaringType);
846 MarkCustomAttributes (method);
848 MarkGenericParameterProvider (method);
850 if (IsPropertyMethod (method))
851 MarkProperty (GetProperty (method));
852 else if (IsEventMethod (method))
853 MarkEvent (GetEvent (method));
855 if (method.HasParameters) {
856 foreach (ParameterDefinition pd in method.Parameters) {
857 MarkType (pd.ParameterType);
858 MarkCustomAttributes (pd);
859 MarkMarshalSpec (pd);
863 if (method.HasOverrides) {
864 foreach (MethodReference ov in method.Overrides)
868 MarkMethodSpecialCustomAttributes (method);
870 if (method.IsVirtual)
871 _virtual_methods.Add (method);
873 MarkBaseMethods (method);
875 MarkType (method.ReturnType);
876 MarkCustomAttributes (method.MethodReturnType);
877 MarkMarshalSpec (method.MethodReturnType);
879 if (ShouldParseMethodBody (method))
880 MarkMethodBody (method.Body);
882 Annotations.Mark (method);
884 ApplyPreserveMethods (method);
887 void MarkBaseMethods (MethodDefinition method)
889 IList base_methods = Annotations.GetBaseMethods (method);
890 if (base_methods == null)
893 foreach (MethodDefinition base_method in base_methods) {
894 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
897 MarkMethod (base_method);
898 MarkBaseMethods (base_method);
902 bool ShouldParseMethodBody (MethodDefinition method)
907 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
908 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
909 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
912 static internal bool IsPropertyMethod (MethodDefinition md)
914 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
915 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
918 static bool IsEventMethod (MethodDefinition md)
920 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
921 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
922 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
925 static internal PropertyDefinition GetProperty (MethodDefinition md)
927 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
928 foreach (PropertyDefinition prop in declaringType.Properties)
929 if (prop.GetMethod == md || prop.SetMethod == md)
935 static EventDefinition GetEvent (MethodDefinition md)
937 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
938 foreach (EventDefinition evt in declaringType.Events)
939 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
945 protected void MarkProperty (PropertyDefinition prop)
947 MarkCustomAttributes (prop);
950 protected void MarkEvent (EventDefinition evt)
952 MarkCustomAttributes (evt);
953 MarkMethodIfNotNull (evt.AddMethod);
954 MarkMethodIfNotNull (evt.InvokeMethod);
955 MarkMethodIfNotNull (evt.RemoveMethod);
958 void MarkMethodIfNotNull (MethodReference method)
966 protected virtual void MarkMethodBody (MethodBody body)
968 foreach (VariableDefinition var in body.Variables)
969 MarkType (var.VariableType);
971 foreach (ExceptionHandler eh in body.ExceptionHandlers)
972 if (eh.HandlerType == ExceptionHandlerType.Catch)
973 MarkType (eh.CatchType);
975 foreach (Instruction instruction in body.Instructions)
976 MarkInstruction (instruction);
979 protected virtual void MarkInstruction (Instruction instruction)
981 switch (instruction.OpCode.OperandType) {
982 case OperandType.InlineField:
983 MarkField ((FieldReference) instruction.Operand);
985 case OperandType.InlineMethod:
986 MarkMethod ((MethodReference) instruction.Operand);
988 case OperandType.InlineTok:
989 object token = instruction.Operand;
990 if (token is TypeReference)
991 MarkType ((TypeReference) token);
992 else if (token is MethodReference)
993 MarkMethod ((MethodReference) token);
995 MarkField ((FieldReference) token);
997 case OperandType.InlineType:
998 MarkType ((TypeReference) instruction.Operand);