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 MarkCustomAttributes (assembly);
295 foreach (ModuleDefinition module in assembly.Modules)
296 MarkCustomAttributes (module);
299 protected void MarkField (FieldReference reference)
301 // if (IgnoreScope (reference.DeclaringType.Scope))
304 if (reference.DeclaringType is GenericInstanceType)
305 MarkType (reference.DeclaringType);
307 FieldDefinition field = ResolveFieldDefinition (reference);
310 throw new ResolutionException (reference);
312 if (CheckProcessed (field))
315 MarkType (field.DeclaringType);
316 MarkType (field.FieldType);
317 MarkCustomAttributes (field);
318 MarkMarshalSpec (field);
320 Annotations.Mark (field);
323 protected virtual bool IgnoreScope (IMetadataScope scope)
325 AssemblyDefinition assembly = ResolveAssembly (scope);
326 return Annotations.GetAction (assembly) != AssemblyAction.Link;
329 FieldDefinition ResolveFieldDefinition (FieldReference field)
331 FieldDefinition fd = field as FieldDefinition;
333 fd = field.Resolve ();
338 void MarkScope (IMetadataScope scope)
340 var provider = scope as IMetadataTokenProvider;
341 if (provider == null)
344 Annotations.Mark (provider);
347 protected virtual void MarkSerializable (TypeDefinition type)
349 MarkDefaultConstructor (type);
350 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
353 protected virtual TypeDefinition MarkType (TypeReference reference)
355 if (reference == null)
358 reference = GetOriginalType (reference);
360 if (reference is GenericParameter)
363 // if (IgnoreScope (reference.Scope))
366 TypeDefinition type = ResolveTypeDefinition (reference);
369 throw new ResolutionException (reference);
371 if (CheckProcessed (type))
374 MarkScope (type.Scope);
375 MarkType (type.BaseType);
376 MarkType (type.DeclaringType);
377 MarkCustomAttributes (type);
379 if (IsMulticastDelegate (type)) {
380 MarkMethodCollection (type.Methods);
383 if (IsSerializable (type))
384 MarkSerializable (type);
386 MarkTypeSpecialCustomAttributes (type);
388 MarkGenericParameterProvider (type);
390 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
391 if (type.IsValueType || !type.IsAutoLayout)
392 MarkFields (type, type.IsEnum);
394 if (type.HasInterfaces) {
395 foreach (TypeReference iface in type.Interfaces)
399 if (type.HasMethods) {
400 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
401 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
404 Annotations.Mark (type);
406 ApplyPreserveInfo (type);
411 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
413 if (!type.HasCustomAttributes)
416 foreach (CustomAttribute attribute in type.CustomAttributes) {
417 switch (attribute.Constructor.DeclaringType.FullName) {
418 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
419 MarkXmlSchemaProvider (type, attribute);
425 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
427 if (!method.HasCustomAttributes)
430 foreach (CustomAttribute attribute in method.CustomAttributes) {
431 switch (attribute.Constructor.DeclaringType.FullName) {
432 case "System.Web.Services.Protocols.SoapHeaderAttribute":
433 MarkSoapHeader (method, attribute);
439 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
442 if (!TryGetStringArgument (attribute, out method_name))
445 MarkNamedMethod (type, method_name);
448 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
452 if (attribute.ConstructorArguments.Count < 1)
455 argument = attribute.ConstructorArguments [0].Value as string;
457 return argument != null;
460 protected void MarkNamedMethod (TypeDefinition type, string method_name)
462 if (!type.HasMethods)
465 foreach (MethodDefinition method in type.Methods) {
466 if (method.Name != method_name)
473 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
476 if (!TryGetStringArgument (attribute, out member_name))
479 MarkNamedField (method.DeclaringType, member_name);
480 MarkNamedProperty (method.DeclaringType, member_name);
483 void MarkNamedField (TypeDefinition type, string field_name)
488 foreach (FieldDefinition field in type.Fields) {
489 if (field.Name != field_name)
496 void MarkNamedProperty (TypeDefinition type, string property_name)
498 if (!type.HasProperties)
501 foreach (PropertyDefinition property in type.Properties) {
502 if (property.Name != property_name)
505 MarkMethod (property.GetMethod);
506 MarkMethod (property.SetMethod);
510 void MarkGenericParameterProvider (IGenericParameterProvider provider)
512 if (!provider.HasGenericParameters)
515 foreach (GenericParameter parameter in provider.GenericParameters)
516 MarkGenericParameter (parameter);
519 void MarkGenericParameter (GenericParameter parameter)
521 MarkCustomAttributes (parameter);
522 foreach (TypeReference constraint in parameter.Constraints)
523 MarkType (constraint);
526 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
528 if (!method.IsVirtual)
531 var base_list = Annotations.GetBaseMethods (method);
532 if (base_list == null)
535 foreach (MethodDefinition @base in base_list) {
536 if (IgnoreScope (@base.DeclaringType.Scope))
539 if (IsVirtualAndHasPreservedParent (@base))
546 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
548 static bool IsSpecialSerializationConstructor (MethodDefinition method)
550 if (!IsConstructor (method))
553 var parameters = method.Parameters;
554 if (parameters.Count != 2)
557 return parameters [0].ParameterType.Name == "SerializationInfo" &&
558 parameters [1].ParameterType.Name == "StreamingContext";
561 delegate bool MethodPredicate (MethodDefinition method);
563 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
565 foreach (MethodDefinition method in methods)
566 if (predicate (method))
570 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
572 static bool IsDefaultConstructor (MethodDefinition method)
574 return IsConstructor (method) && !method.HasParameters;
577 static bool IsConstructor (MethodDefinition method)
579 return method.IsConstructor && !method.IsStatic;
582 protected void MarkDefaultConstructor (TypeDefinition type)
584 if ((type == null) || !type.HasMethods)
587 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
590 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
592 static bool IsStaticConstructor (MethodDefinition method)
594 return method.IsConstructor && method.IsStatic;
597 static bool IsSerializable (TypeDefinition td)
599 return (td.Attributes & TypeAttributes.Serializable) != 0;
602 static bool IsMulticastDelegate (TypeDefinition td)
604 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
607 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
609 TypeDefinition td = type as TypeDefinition;
611 td = type.Resolve ();
616 protected TypeReference GetOriginalType (TypeReference type)
618 while (type is TypeSpecification) {
619 GenericInstanceType git = type as GenericInstanceType;
621 MarkGenericArguments (git);
623 var mod = type as IModifierType;
625 MarkModifierType (mod);
627 type = ((TypeSpecification) type).ElementType;
633 void MarkModifierType (IModifierType mod)
635 MarkType (mod.ModifierType);
638 void MarkGenericArguments (IGenericInstance instance)
640 foreach (TypeReference argument in instance.GenericArguments)
643 MarkGenericArgumentConstructors (instance);
646 void MarkGenericArgumentConstructors (IGenericInstance instance)
648 var arguments = instance.GenericArguments;
650 var generic_element = GetGenericProviderFromInstance (instance);
651 if (generic_element == null)
654 var parameters = generic_element.GenericParameters;
656 if (arguments.Count != parameters.Count)
659 for (int i = 0; i < arguments.Count; i++) {
660 var argument = arguments [i];
661 var parameter = parameters [i];
663 if (!parameter.HasDefaultConstructorConstraint)
666 var argument_definition = ResolveTypeDefinition (argument);
667 if (argument_definition == null)
670 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
674 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
676 var method = instance as GenericInstanceMethod;
678 return ResolveMethodDefinition (method.ElementMethod);
680 var type = instance as GenericInstanceType;
682 return ResolveTypeDefinition (type.ElementType);
687 void ApplyPreserveInfo (TypeDefinition type)
689 ApplyPreserveMethods (type);
691 if (!Annotations.IsPreserved (type))
694 switch (Annotations.GetPreserve (type)) {
695 case TypePreserve.All:
696 MarkFields (type, true);
699 case TypePreserve.Fields:
700 MarkFields (type, true);
702 case TypePreserve.Methods:
708 void ApplyPreserveMethods (TypeDefinition type)
710 var list = Annotations.GetPreservedMethods (type);
714 MarkMethodCollection (list);
717 void ApplyPreserveMethods (MethodDefinition method)
719 var list = Annotations.GetPreservedMethods (method);
723 MarkMethodCollection (list);
726 protected void MarkFields (TypeDefinition type, bool includeStatic)
731 foreach (FieldDefinition field in type.Fields) {
732 if (!includeStatic && field.IsStatic)
738 protected virtual void MarkMethods (TypeDefinition type)
741 MarkMethodCollection (type.Methods);
744 void MarkMethodCollection (IEnumerable methods)
746 foreach (MethodDefinition method in methods)
750 protected virtual MethodDefinition MarkMethod (MethodReference reference)
752 reference = GetOriginalMethod (reference);
754 if (reference.DeclaringType is ArrayType)
757 if (reference.DeclaringType is GenericInstanceType)
758 MarkType (reference.DeclaringType);
760 // if (IgnoreScope (reference.DeclaringType.Scope))
763 MethodDefinition method = ResolveMethodDefinition (reference);
766 throw new ResolutionException (reference);
768 if (Annotations.GetAction (method) == MethodAction.Nothing)
769 Annotations.SetAction (method, MethodAction.Parse);
771 EnqueueMethod (method);
775 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
777 AssemblyDefinition assembly = _context.Resolve (scope);
778 MarkAssembly (assembly);
782 protected MethodReference GetOriginalMethod (MethodReference method)
784 while (method is MethodSpecification) {
785 GenericInstanceMethod gim = method as GenericInstanceMethod;
787 MarkGenericArguments (gim);
789 method = ((MethodSpecification) method).ElementMethod;
795 MethodDefinition ResolveMethodDefinition (MethodReference method)
797 MethodDefinition md = method as MethodDefinition;
799 md = method.Resolve ();
804 protected virtual void ProcessMethod (MethodDefinition method)
806 if (CheckProcessed (method))
809 MarkType (method.DeclaringType);
810 MarkCustomAttributes (method);
812 MarkGenericParameterProvider (method);
814 if (IsPropertyMethod (method))
815 MarkProperty (GetProperty (method));
816 else if (IsEventMethod (method))
817 MarkEvent (GetEvent (method));
819 if (method.HasParameters) {
820 foreach (ParameterDefinition pd in method.Parameters) {
821 MarkType (pd.ParameterType);
822 MarkCustomAttributes (pd);
823 MarkMarshalSpec (pd);
827 if (method.HasOverrides) {
828 foreach (MethodReference ov in method.Overrides)
832 MarkMethodSpecialCustomAttributes (method);
834 if (method.IsVirtual)
835 _virtual_methods.Add (method);
837 MarkBaseMethods (method);
839 MarkType (method.ReturnType);
840 MarkCustomAttributes (method.MethodReturnType);
841 MarkMarshalSpec (method.MethodReturnType);
843 if (ShouldParseMethodBody (method))
844 MarkMethodBody (method.Body);
846 Annotations.Mark (method);
848 ApplyPreserveMethods (method);
851 void MarkBaseMethods (MethodDefinition method)
853 IList base_methods = Annotations.GetBaseMethods (method);
854 if (base_methods == null)
857 foreach (MethodDefinition base_method in base_methods) {
858 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
861 MarkMethod (base_method);
862 MarkBaseMethods (base_method);
866 bool ShouldParseMethodBody (MethodDefinition method)
871 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
872 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
873 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
876 static internal bool IsPropertyMethod (MethodDefinition md)
878 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
879 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
882 static bool IsEventMethod (MethodDefinition md)
884 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
885 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
886 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
889 static internal PropertyDefinition GetProperty (MethodDefinition md)
891 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
892 foreach (PropertyDefinition prop in declaringType.Properties)
893 if (prop.GetMethod == md || prop.SetMethod == md)
899 static EventDefinition GetEvent (MethodDefinition md)
901 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
902 foreach (EventDefinition evt in declaringType.Events)
903 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
909 protected void MarkProperty (PropertyDefinition prop)
911 MarkCustomAttributes (prop);
914 protected void MarkEvent (EventDefinition evt)
916 MarkCustomAttributes (evt);
917 MarkMethodIfNotNull (evt.AddMethod);
918 MarkMethodIfNotNull (evt.InvokeMethod);
919 MarkMethodIfNotNull (evt.RemoveMethod);
922 void MarkMethodIfNotNull (MethodReference method)
930 protected virtual void MarkMethodBody (MethodBody body)
932 foreach (VariableDefinition var in body.Variables)
933 MarkType (var.VariableType);
935 foreach (ExceptionHandler eh in body.ExceptionHandlers)
936 if (eh.HandlerType == ExceptionHandlerType.Catch)
937 MarkType (eh.CatchType);
939 foreach (Instruction instruction in body.Instructions)
940 MarkInstruction (instruction);
943 protected virtual void MarkInstruction (Instruction instruction)
945 switch (instruction.OpCode.OperandType) {
946 case OperandType.InlineField:
947 MarkField ((FieldReference) instruction.Operand);
949 case OperandType.InlineMethod:
950 MarkMethod ((MethodReference) instruction.Operand);
952 case OperandType.InlineTok:
953 object token = instruction.Operand;
954 if (token is TypeReference)
955 MarkType ((TypeReference) token);
956 else if (token is MethodReference)
957 MarkMethod ((MethodReference) token);
959 MarkField ((FieldReference) token);
961 case OperandType.InlineType:
962 MarkType ((TypeReference) instruction.Operand);