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 InitializeType (nested);
94 void InitializeFields (TypeDefinition type)
96 foreach (FieldDefinition field in type.Fields)
97 if (Annotations.IsMarked (field))
101 void InitializeMethods (ICollection methods)
103 foreach (MethodDefinition method in methods)
104 if (Annotations.IsMarked (method))
105 EnqueueMethod (method);
111 throw new InvalidOperationException ("No entry methods");
113 while (!QueueIsEmpty ()) {
115 ProcessVirtualMethods ();
121 while (!QueueIsEmpty ()) {
122 MethodDefinition method = (MethodDefinition) _methods.Dequeue ();
123 ProcessMethod (method);
129 return _methods.Count == 0;
132 protected virtual void EnqueueMethod (MethodDefinition method)
134 _methods.Enqueue (method);
137 void ProcessVirtualMethods ()
139 foreach (MethodDefinition method in _virtual_methods)
140 ProcessVirtualMethod (method);
143 void ProcessVirtualMethod (MethodDefinition method)
145 IList overrides = Annotations.GetOverrides (method);
146 if (overrides == null)
149 foreach (MethodDefinition @override in overrides)
150 ProcessOverride (@override);
153 void ProcessOverride (MethodDefinition method)
155 if (!Annotations.IsMarked (method.DeclaringType))
158 if (Annotations.IsProcessed (method))
161 if (Annotations.IsMarked (method))
165 ProcessVirtualMethod (method);
168 void MarkMarshalSpec (IMarshalInfoProvider spec)
170 if (!spec.HasMarshalInfo)
173 var marshaler = spec.MarshalInfo as CustomMarshalInfo;
174 if (marshaler == null)
177 MarkType (marshaler.ManagedType);
180 void MarkCustomAttributes (ICustomAttributeProvider provider)
182 if (!provider.HasCustomAttributes)
185 foreach (CustomAttribute ca in provider.CustomAttributes)
186 MarkCustomAttribute (ca);
189 void MarkCustomAttribute (CustomAttribute ca)
191 MarkMethod (ca.Constructor);
193 MarkCustomAttributeArguments (ca);
195 TypeReference constructor_type = ca.Constructor.DeclaringType;
196 TypeDefinition type = constructor_type.Resolve ();
198 throw new ResolutionException (constructor_type);
200 MarkCustomAttributeProperties (ca, type);
201 MarkCustomAttributeFields (ca, type);
204 void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute)
206 foreach (var named_argument in ca.Properties) {
207 PropertyDefinition property = GetProperty (attribute, named_argument.Name);
208 if (property != null)
209 MarkMethod (property.SetMethod);
211 MarkIfType (named_argument.Argument);
215 PropertyDefinition GetProperty (TypeDefinition type, string propertyname)
217 while (type != null) {
218 PropertyDefinition property = type.Properties.FirstOrDefault (p => p.Name == propertyname);
219 if (property != null)
222 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
228 void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute)
230 foreach (var named_argument in ca.Fields) {
231 FieldDefinition field = GetField (attribute, named_argument.Name);
235 MarkIfType (named_argument.Argument);
239 FieldDefinition GetField (TypeDefinition type, string fieldname)
241 while (type != null) {
242 FieldDefinition field = type.Fields.FirstOrDefault (f => f.Name == fieldname);
246 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
252 void MarkCustomAttributeArguments (CustomAttribute ca)
254 foreach (var argument in ca.ConstructorArguments)
255 MarkIfType (argument);
258 void MarkIfType (CustomAttributeArgument argument)
260 if (argument.Type.FullName != "System.Type")
263 MarkType (argument.Type);
264 MarkType ((TypeReference) argument.Value);
267 protected bool CheckProcessed (IMetadataTokenProvider provider)
269 if (Annotations.IsProcessed (provider))
272 Annotations.Processed (provider);
276 void MarkAssembly (AssemblyDefinition assembly)
278 if (CheckProcessed (assembly))
281 MarkCustomAttributes (assembly);
283 foreach (ModuleDefinition module in assembly.Modules)
284 MarkCustomAttributes (module);
287 void MarkField (FieldReference reference)
289 // if (IgnoreScope (reference.DeclaringType.Scope))
292 if (reference.DeclaringType is GenericInstanceType)
293 MarkType (reference.DeclaringType);
295 FieldDefinition field = ResolveFieldDefinition (reference);
298 throw new ResolutionException (reference);
300 if (CheckProcessed (field))
303 MarkType (field.DeclaringType);
304 MarkType (field.FieldType);
305 MarkCustomAttributes (field);
306 MarkMarshalSpec (field);
308 Annotations.Mark (field);
311 protected virtual bool IgnoreScope (IMetadataScope scope)
313 AssemblyDefinition assembly = ResolveAssembly (scope);
314 return Annotations.GetAction (assembly) != AssemblyAction.Link;
317 FieldDefinition ResolveFieldDefinition (FieldReference field)
319 FieldDefinition fd = field as FieldDefinition;
321 fd = field.Resolve ();
326 void MarkScope (IMetadataScope scope)
328 var provider = scope as IMetadataTokenProvider;
329 if (provider == null)
332 Annotations.Mark (provider);
335 protected virtual TypeDefinition MarkType (TypeReference reference)
337 if (reference == null)
340 reference = GetOriginalType (reference);
342 if (reference is GenericParameter)
345 // if (IgnoreScope (reference.Scope))
348 TypeDefinition type = ResolveTypeDefinition (reference);
351 throw new ResolutionException (reference);
353 if (CheckProcessed (type))
356 MarkScope (type.Scope);
357 MarkType (type.BaseType);
358 MarkType (type.DeclaringType);
359 MarkCustomAttributes (type);
361 if (IsMulticastDelegate (type)) {
362 MarkMethodCollection (type.Methods);
365 if (IsSerializable (type) && type.HasMethods) {
366 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
367 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
370 MarkTypeSpecialCustomAttributes (type);
372 MarkGenericParameterProvider (type);
374 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
375 if (type.IsValueType || !type.IsAutoLayout)
376 MarkFields (type, type.IsEnum);
378 if (type.HasInterfaces) {
379 foreach (TypeReference iface in type.Interfaces)
383 if (type.HasMethods) {
384 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
385 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
388 Annotations.Mark (type);
390 ApplyPreserveInfo (type);
395 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
397 if (!type.HasCustomAttributes)
400 foreach (CustomAttribute attribute in type.CustomAttributes) {
401 switch (attribute.Constructor.DeclaringType.FullName) {
402 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
403 MarkXmlSchemaProvider (type, attribute);
409 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
411 if (!method.HasCustomAttributes)
414 foreach (CustomAttribute attribute in method.CustomAttributes) {
415 switch (attribute.Constructor.DeclaringType.FullName) {
416 case "System.Web.Services.Protocols.SoapHeaderAttribute":
417 MarkSoapHeader (method, attribute);
423 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
426 if (!TryGetStringArgument (attribute, out method_name))
429 MarkNamedMethod (type, method_name);
432 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
436 if (attribute.ConstructorArguments.Count < 1)
439 argument = attribute.ConstructorArguments [0].Value as string;
441 return argument != null;
444 protected void MarkNamedMethod (TypeDefinition type, string method_name)
446 if (!type.HasMethods)
449 foreach (MethodDefinition method in type.Methods) {
450 if (method.Name != method_name)
457 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
460 if (!TryGetStringArgument (attribute, out member_name))
463 MarkNamedField (method.DeclaringType, member_name);
464 MarkNamedProperty (method.DeclaringType, member_name);
467 void MarkNamedField (TypeDefinition type, string field_name)
472 foreach (FieldDefinition field in type.Fields) {
473 if (field.Name != field_name)
480 void MarkNamedProperty (TypeDefinition type, string property_name)
482 if (!type.HasProperties)
485 foreach (PropertyDefinition property in type.Properties) {
486 if (property.Name != property_name)
489 MarkMethod (property.GetMethod);
490 MarkMethod (property.SetMethod);
494 void MarkGenericParameterProvider (IGenericParameterProvider provider)
496 if (!provider.HasGenericParameters)
499 foreach (GenericParameter parameter in provider.GenericParameters)
500 MarkGenericParameter (parameter);
503 void MarkGenericParameter (GenericParameter parameter)
505 MarkCustomAttributes (parameter);
506 foreach (TypeReference constraint in parameter.Constraints)
507 MarkType (constraint);
510 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
512 if (!method.IsVirtual)
515 var base_list = Annotations.GetBaseMethods (method);
516 if (base_list == null)
519 foreach (MethodDefinition @base in base_list) {
520 if (IgnoreScope (@base.DeclaringType.Scope))
523 if (IsVirtualAndHasPreservedParent (@base))
530 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
532 static bool IsSpecialSerializationConstructor (MethodDefinition method)
534 if (!IsConstructor (method))
537 var parameters = method.Parameters;
538 if (parameters.Count != 2)
541 return parameters [0].ParameterType.Name == "SerializationInfo" &&
542 parameters [1].ParameterType.Name == "StreamingContext";
545 delegate bool MethodPredicate (MethodDefinition method);
547 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
549 foreach (MethodDefinition method in methods)
550 if (predicate (method))
554 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
556 static bool IsDefaultConstructor (MethodDefinition method)
558 return IsConstructor (method) && method.Parameters.Count == 0;
561 static bool IsConstructor (MethodDefinition method)
563 return method.IsConstructor && !method.IsStatic;
566 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
568 static bool IsStaticConstructor (MethodDefinition method)
570 return method.IsConstructor && method.IsStatic;
573 static bool IsSerializable (TypeDefinition td)
575 return (td.Attributes & TypeAttributes.Serializable) != 0;
578 static bool IsMulticastDelegate (TypeDefinition td)
580 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
583 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
585 TypeDefinition td = type as TypeDefinition;
587 td = type.Resolve ();
592 protected TypeReference GetOriginalType (TypeReference type)
594 while (type is TypeSpecification) {
595 GenericInstanceType git = type as GenericInstanceType;
597 MarkGenericArguments (git);
599 var mod = type as IModifierType;
601 MarkModifierType (mod);
603 type = ((TypeSpecification) type).ElementType;
609 void MarkModifierType (IModifierType mod)
611 MarkType (mod.ModifierType);
614 void MarkGenericArguments (IGenericInstance instance)
616 foreach (TypeReference argument in instance.GenericArguments)
619 MarkGenericArgumentConstructors (instance);
622 void MarkGenericArgumentConstructors (IGenericInstance instance)
624 var arguments = instance.GenericArguments;
626 var generic_element = GetGenericProviderFromInstance (instance);
627 if (generic_element == null)
630 var parameters = generic_element.GenericParameters;
632 if (arguments.Count != parameters.Count)
635 for (int i = 0; i < arguments.Count; i++) {
636 var argument = arguments [i];
637 var parameter = parameters [i];
639 if (!parameter.HasDefaultConstructorConstraint)
642 var argument_definition = ResolveTypeDefinition (argument);
643 if (argument_definition == null)
646 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
650 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
652 var method = instance as GenericInstanceMethod;
654 return ResolveMethodDefinition (method.ElementMethod);
656 var type = instance as GenericInstanceType;
658 return ResolveTypeDefinition (type.ElementType);
663 void ApplyPreserveInfo (TypeDefinition type)
665 ApplyPreserveMethods (type);
667 if (!Annotations.IsPreserved (type))
670 switch (Annotations.GetPreserve (type)) {
671 case TypePreserve.All:
672 MarkFields (type, true);
675 case TypePreserve.Fields:
676 MarkFields (type, true);
678 case TypePreserve.Methods:
684 void ApplyPreserveMethods (TypeDefinition type)
686 var list = Annotations.GetPreservedMethods (type);
690 MarkMethodCollection (list);
693 void ApplyPreserveMethods (MethodDefinition method)
695 var list = Annotations.GetPreservedMethods (method);
699 MarkMethodCollection (list);
702 protected void MarkFields (TypeDefinition type, bool includeStatic)
707 foreach (FieldDefinition field in type.Fields) {
708 if (!includeStatic && field.IsStatic)
714 protected virtual void MarkMethods (TypeDefinition type)
717 MarkMethodCollection (type.Methods);
720 void MarkMethodCollection (IEnumerable methods)
722 foreach (MethodDefinition method in methods)
726 protected void MarkMethod (MethodReference reference)
728 reference = GetOriginalMethod (reference);
730 if (reference.DeclaringType is ArrayType)
733 if (reference.DeclaringType is GenericInstanceType)
734 MarkType (reference.DeclaringType);
736 // if (IgnoreScope (reference.DeclaringType.Scope))
739 MethodDefinition method = ResolveMethodDefinition (reference);
742 throw new ResolutionException (reference);
744 if (Annotations.GetAction (method) == MethodAction.Nothing)
745 Annotations.SetAction (method, MethodAction.Parse);
747 EnqueueMethod (method);
750 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
752 AssemblyDefinition assembly = _context.Resolve (scope);
753 MarkAssembly (assembly);
757 protected MethodReference GetOriginalMethod (MethodReference method)
759 while (method is MethodSpecification) {
760 GenericInstanceMethod gim = method as GenericInstanceMethod;
762 MarkGenericArguments (gim);
764 method = ((MethodSpecification) method).ElementMethod;
770 MethodDefinition ResolveMethodDefinition (MethodReference method)
772 MethodDefinition md = method as MethodDefinition;
774 md = method.Resolve ();
779 protected virtual void ProcessMethod (MethodDefinition method)
781 if (CheckProcessed (method))
784 MarkType (method.DeclaringType);
785 MarkCustomAttributes (method);
787 MarkGenericParameterProvider (method);
789 if (IsPropertyMethod (method))
790 MarkProperty (GetProperty (method));
791 else if (IsEventMethod (method))
792 MarkEvent (GetEvent (method));
794 if (method.HasParameters) {
795 foreach (ParameterDefinition pd in method.Parameters) {
796 MarkType (pd.ParameterType);
797 MarkCustomAttributes (pd);
798 MarkMarshalSpec (pd);
802 if (method.HasOverrides) {
803 foreach (MethodReference ov in method.Overrides)
807 MarkMethodSpecialCustomAttributes (method);
809 if (method.IsVirtual)
810 _virtual_methods.Add (method);
812 MarkBaseMethods (method);
814 MarkType (method.ReturnType);
815 MarkCustomAttributes (method.MethodReturnType);
816 MarkMarshalSpec (method.MethodReturnType);
818 if (ShouldParseMethodBody (method))
819 MarkMethodBody (method.Body);
821 Annotations.Mark (method);
823 ApplyPreserveMethods (method);
826 void MarkBaseMethods (MethodDefinition method)
828 IList base_methods = Annotations.GetBaseMethods (method);
829 if (base_methods == null)
832 foreach (MethodDefinition base_method in base_methods) {
833 MarkMethod (base_method);
834 MarkBaseMethods (base_method);
838 bool ShouldParseMethodBody (MethodDefinition method)
843 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
844 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
845 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
848 static bool IsPropertyMethod (MethodDefinition md)
850 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
851 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
854 static bool IsEventMethod (MethodDefinition md)
856 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
857 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
858 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
861 static PropertyDefinition GetProperty (MethodDefinition md)
863 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
864 foreach (PropertyDefinition prop in declaringType.Properties)
865 if (prop.GetMethod == md || prop.SetMethod == md)
871 static EventDefinition GetEvent (MethodDefinition md)
873 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
874 foreach (EventDefinition evt in declaringType.Events)
875 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
881 void MarkProperty (PropertyDefinition prop)
883 MarkCustomAttributes (prop);
886 void MarkEvent (EventDefinition evt)
888 MarkCustomAttributes (evt);
889 MarkMethodIfNotNull (evt.AddMethod);
890 MarkMethodIfNotNull (evt.InvokeMethod);
891 MarkMethodIfNotNull (evt.RemoveMethod);
894 void MarkMethodIfNotNull (MethodReference method)
902 protected virtual void MarkMethodBody (MethodBody body)
904 foreach (VariableDefinition var in body.Variables)
905 MarkType (var.VariableType);
907 foreach (ExceptionHandler eh in body.ExceptionHandlers)
908 if (eh.HandlerType == ExceptionHandlerType.Catch)
909 MarkType (eh.CatchType);
911 foreach (Instruction instruction in body.Instructions)
912 MarkInstruction (instruction);
915 protected virtual void MarkInstruction (Instruction instruction)
917 switch (instruction.OpCode.OperandType) {
918 case OperandType.InlineField:
919 MarkField ((FieldReference) instruction.Operand);
921 case OperandType.InlineMethod:
922 MarkMethod ((MethodReference) instruction.Operand);
924 case OperandType.InlineTok:
925 object token = instruction.Operand;
926 if (token is TypeReference)
927 MarkType ((TypeReference) token);
928 else if (token is MethodReference)
929 MarkMethod ((MethodReference) token);
931 MarkField ((FieldReference) token);
933 case OperandType.InlineType:
934 MarkType ((TypeReference) instruction.Operand);