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 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 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 TypeDefinition MarkType (TypeReference reference)
349 if (reference == null)
352 reference = GetOriginalType (reference);
354 if (reference is GenericParameter)
357 // if (IgnoreScope (reference.Scope))
360 TypeDefinition type = ResolveTypeDefinition (reference);
363 throw new ResolutionException (reference);
365 if (CheckProcessed (type))
368 MarkScope (type.Scope);
369 MarkType (type.BaseType);
370 MarkType (type.DeclaringType);
371 MarkCustomAttributes (type);
373 if (IsMulticastDelegate (type)) {
374 MarkMethodCollection (type.Methods);
377 if (IsSerializable (type) && type.HasMethods) {
378 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
379 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
382 MarkTypeSpecialCustomAttributes (type);
384 MarkGenericParameterProvider (type);
386 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
387 if (type.IsValueType || !type.IsAutoLayout)
388 MarkFields (type, type.IsEnum);
390 if (type.HasInterfaces) {
391 foreach (TypeReference iface in type.Interfaces)
395 if (type.HasMethods) {
396 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
397 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
400 Annotations.Mark (type);
402 ApplyPreserveInfo (type);
407 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
409 if (!type.HasCustomAttributes)
412 foreach (CustomAttribute attribute in type.CustomAttributes) {
413 switch (attribute.Constructor.DeclaringType.FullName) {
414 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
415 MarkXmlSchemaProvider (type, attribute);
421 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
423 if (!method.HasCustomAttributes)
426 foreach (CustomAttribute attribute in method.CustomAttributes) {
427 switch (attribute.Constructor.DeclaringType.FullName) {
428 case "System.Web.Services.Protocols.SoapHeaderAttribute":
429 MarkSoapHeader (method, attribute);
435 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
438 if (!TryGetStringArgument (attribute, out method_name))
441 MarkNamedMethod (type, method_name);
444 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
448 if (attribute.ConstructorArguments.Count < 1)
451 argument = attribute.ConstructorArguments [0].Value as string;
453 return argument != null;
456 protected void MarkNamedMethod (TypeDefinition type, string method_name)
458 if (!type.HasMethods)
461 foreach (MethodDefinition method in type.Methods) {
462 if (method.Name != method_name)
469 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
472 if (!TryGetStringArgument (attribute, out member_name))
475 MarkNamedField (method.DeclaringType, member_name);
476 MarkNamedProperty (method.DeclaringType, member_name);
479 void MarkNamedField (TypeDefinition type, string field_name)
484 foreach (FieldDefinition field in type.Fields) {
485 if (field.Name != field_name)
492 void MarkNamedProperty (TypeDefinition type, string property_name)
494 if (!type.HasProperties)
497 foreach (PropertyDefinition property in type.Properties) {
498 if (property.Name != property_name)
501 MarkMethod (property.GetMethod);
502 MarkMethod (property.SetMethod);
506 void MarkGenericParameterProvider (IGenericParameterProvider provider)
508 if (!provider.HasGenericParameters)
511 foreach (GenericParameter parameter in provider.GenericParameters)
512 MarkGenericParameter (parameter);
515 void MarkGenericParameter (GenericParameter parameter)
517 MarkCustomAttributes (parameter);
518 foreach (TypeReference constraint in parameter.Constraints)
519 MarkType (constraint);
522 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
524 if (!method.IsVirtual)
527 var base_list = Annotations.GetBaseMethods (method);
528 if (base_list == null)
531 foreach (MethodDefinition @base in base_list) {
532 if (IgnoreScope (@base.DeclaringType.Scope))
535 if (IsVirtualAndHasPreservedParent (@base))
542 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
544 static bool IsSpecialSerializationConstructor (MethodDefinition method)
546 if (!IsConstructor (method))
549 var parameters = method.Parameters;
550 if (parameters.Count != 2)
553 return parameters [0].ParameterType.Name == "SerializationInfo" &&
554 parameters [1].ParameterType.Name == "StreamingContext";
557 delegate bool MethodPredicate (MethodDefinition method);
559 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
561 foreach (MethodDefinition method in methods)
562 if (predicate (method))
566 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
568 static bool IsDefaultConstructor (MethodDefinition method)
570 return IsConstructor (method) && method.Parameters.Count == 0;
573 static bool IsConstructor (MethodDefinition method)
575 return method.IsConstructor && !method.IsStatic;
578 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
580 static bool IsStaticConstructor (MethodDefinition method)
582 return method.IsConstructor && method.IsStatic;
585 static bool IsSerializable (TypeDefinition td)
587 return (td.Attributes & TypeAttributes.Serializable) != 0;
590 static bool IsMulticastDelegate (TypeDefinition td)
592 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
595 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
597 TypeDefinition td = type as TypeDefinition;
599 td = type.Resolve ();
604 protected TypeReference GetOriginalType (TypeReference type)
606 while (type is TypeSpecification) {
607 GenericInstanceType git = type as GenericInstanceType;
609 MarkGenericArguments (git);
611 var mod = type as IModifierType;
613 MarkModifierType (mod);
615 type = ((TypeSpecification) type).ElementType;
621 void MarkModifierType (IModifierType mod)
623 MarkType (mod.ModifierType);
626 void MarkGenericArguments (IGenericInstance instance)
628 foreach (TypeReference argument in instance.GenericArguments)
631 MarkGenericArgumentConstructors (instance);
634 void MarkGenericArgumentConstructors (IGenericInstance instance)
636 var arguments = instance.GenericArguments;
638 var generic_element = GetGenericProviderFromInstance (instance);
639 if (generic_element == null)
642 var parameters = generic_element.GenericParameters;
644 if (arguments.Count != parameters.Count)
647 for (int i = 0; i < arguments.Count; i++) {
648 var argument = arguments [i];
649 var parameter = parameters [i];
651 if (!parameter.HasDefaultConstructorConstraint)
654 var argument_definition = ResolveTypeDefinition (argument);
655 if (argument_definition == null)
658 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
662 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
664 var method = instance as GenericInstanceMethod;
666 return ResolveMethodDefinition (method.ElementMethod);
668 var type = instance as GenericInstanceType;
670 return ResolveTypeDefinition (type.ElementType);
675 void ApplyPreserveInfo (TypeDefinition type)
677 ApplyPreserveMethods (type);
679 if (!Annotations.IsPreserved (type))
682 switch (Annotations.GetPreserve (type)) {
683 case TypePreserve.All:
684 MarkFields (type, true);
687 case TypePreserve.Fields:
688 MarkFields (type, true);
690 case TypePreserve.Methods:
696 void ApplyPreserveMethods (TypeDefinition type)
698 var list = Annotations.GetPreservedMethods (type);
702 MarkMethodCollection (list);
705 void ApplyPreserveMethods (MethodDefinition method)
707 var list = Annotations.GetPreservedMethods (method);
711 MarkMethodCollection (list);
714 protected void MarkFields (TypeDefinition type, bool includeStatic)
719 foreach (FieldDefinition field in type.Fields) {
720 if (!includeStatic && field.IsStatic)
726 protected virtual void MarkMethods (TypeDefinition type)
729 MarkMethodCollection (type.Methods);
732 void MarkMethodCollection (IEnumerable methods)
734 foreach (MethodDefinition method in methods)
738 protected virtual MethodDefinition MarkMethod (MethodReference reference)
740 reference = GetOriginalMethod (reference);
742 if (reference.DeclaringType is ArrayType)
745 if (reference.DeclaringType is GenericInstanceType)
746 MarkType (reference.DeclaringType);
748 // if (IgnoreScope (reference.DeclaringType.Scope))
751 MethodDefinition method = ResolveMethodDefinition (reference);
754 throw new ResolutionException (reference);
756 if (Annotations.GetAction (method) == MethodAction.Nothing)
757 Annotations.SetAction (method, MethodAction.Parse);
759 EnqueueMethod (method);
763 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
765 AssemblyDefinition assembly = _context.Resolve (scope);
766 MarkAssembly (assembly);
770 protected MethodReference GetOriginalMethod (MethodReference method)
772 while (method is MethodSpecification) {
773 GenericInstanceMethod gim = method as GenericInstanceMethod;
775 MarkGenericArguments (gim);
777 method = ((MethodSpecification) method).ElementMethod;
783 MethodDefinition ResolveMethodDefinition (MethodReference method)
785 MethodDefinition md = method as MethodDefinition;
787 md = method.Resolve ();
792 protected virtual void ProcessMethod (MethodDefinition method)
794 if (CheckProcessed (method))
797 MarkType (method.DeclaringType);
798 MarkCustomAttributes (method);
800 MarkGenericParameterProvider (method);
802 if (IsPropertyMethod (method))
803 MarkProperty (GetProperty (method));
804 else if (IsEventMethod (method))
805 MarkEvent (GetEvent (method));
807 if (method.HasParameters) {
808 foreach (ParameterDefinition pd in method.Parameters) {
809 MarkType (pd.ParameterType);
810 MarkCustomAttributes (pd);
811 MarkMarshalSpec (pd);
815 if (method.HasOverrides) {
816 foreach (MethodReference ov in method.Overrides)
820 MarkMethodSpecialCustomAttributes (method);
822 if (method.IsVirtual)
823 _virtual_methods.Add (method);
825 MarkBaseMethods (method);
827 MarkType (method.ReturnType);
828 MarkCustomAttributes (method.MethodReturnType);
829 MarkMarshalSpec (method.MethodReturnType);
831 if (ShouldParseMethodBody (method))
832 MarkMethodBody (method.Body);
834 Annotations.Mark (method);
836 ApplyPreserveMethods (method);
839 void MarkBaseMethods (MethodDefinition method)
841 IList base_methods = Annotations.GetBaseMethods (method);
842 if (base_methods == null)
845 foreach (MethodDefinition base_method in base_methods) {
846 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
849 MarkMethod (base_method);
850 MarkBaseMethods (base_method);
854 bool ShouldParseMethodBody (MethodDefinition method)
859 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
860 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
861 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
864 static bool IsPropertyMethod (MethodDefinition md)
866 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
867 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
870 static bool IsEventMethod (MethodDefinition md)
872 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
873 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
874 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
877 static PropertyDefinition GetProperty (MethodDefinition md)
879 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
880 foreach (PropertyDefinition prop in declaringType.Properties)
881 if (prop.GetMethod == md || prop.SetMethod == md)
887 static EventDefinition GetEvent (MethodDefinition md)
889 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
890 foreach (EventDefinition evt in declaringType.Events)
891 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
897 void MarkProperty (PropertyDefinition prop)
899 MarkCustomAttributes (prop);
902 void MarkEvent (EventDefinition evt)
904 MarkCustomAttributes (evt);
905 MarkMethodIfNotNull (evt.AddMethod);
906 MarkMethodIfNotNull (evt.InvokeMethod);
907 MarkMethodIfNotNull (evt.RemoveMethod);
910 void MarkMethodIfNotNull (MethodReference method)
918 protected virtual void MarkMethodBody (MethodBody body)
920 foreach (VariableDefinition var in body.Variables)
921 MarkType (var.VariableType);
923 foreach (ExceptionHandler eh in body.ExceptionHandlers)
924 if (eh.HandlerType == ExceptionHandlerType.Catch)
925 MarkType (eh.CatchType);
927 foreach (Instruction instruction in body.Instructions)
928 MarkInstruction (instruction);
931 protected virtual void MarkInstruction (Instruction instruction)
933 switch (instruction.OpCode.OperandType) {
934 case OperandType.InlineField:
935 MarkField ((FieldReference) instruction.Operand);
937 case OperandType.InlineMethod:
938 MarkMethod ((MethodReference) instruction.Operand);
940 case OperandType.InlineTok:
941 object token = instruction.Operand;
942 if (token is TypeReference)
943 MarkType ((TypeReference) token);
944 else if (token is MethodReference)
945 MarkMethod ((MethodReference) token);
947 MarkField ((FieldReference) token);
949 case OperandType.InlineType:
950 MarkType ((TypeReference) instruction.Operand);