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 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 if (!type.HasMethods)
352 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
353 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
356 protected virtual TypeDefinition MarkType (TypeReference reference)
358 if (reference == null)
361 reference = GetOriginalType (reference);
363 if (reference is GenericParameter)
366 // if (IgnoreScope (reference.Scope))
369 TypeDefinition type = ResolveTypeDefinition (reference);
372 throw new ResolutionException (reference);
374 if (CheckProcessed (type))
377 MarkScope (type.Scope);
378 MarkType (type.BaseType);
379 MarkType (type.DeclaringType);
380 MarkCustomAttributes (type);
382 if (IsMulticastDelegate (type)) {
383 MarkMethodCollection (type.Methods);
386 if (IsSerializable (type))
387 MarkSerializable (type);
389 MarkTypeSpecialCustomAttributes (type);
391 MarkGenericParameterProvider (type);
393 // keep fields for value-types and for classes with LayoutKind.Sequential or Explicit
394 if (type.IsValueType || !type.IsAutoLayout)
395 MarkFields (type, type.IsEnum);
397 if (type.HasInterfaces) {
398 foreach (TypeReference iface in type.Interfaces)
402 if (type.HasMethods) {
403 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
404 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
407 Annotations.Mark (type);
409 ApplyPreserveInfo (type);
414 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
416 if (!type.HasCustomAttributes)
419 foreach (CustomAttribute attribute in type.CustomAttributes) {
420 switch (attribute.Constructor.DeclaringType.FullName) {
421 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
422 MarkXmlSchemaProvider (type, attribute);
428 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
430 if (!method.HasCustomAttributes)
433 foreach (CustomAttribute attribute in method.CustomAttributes) {
434 switch (attribute.Constructor.DeclaringType.FullName) {
435 case "System.Web.Services.Protocols.SoapHeaderAttribute":
436 MarkSoapHeader (method, attribute);
442 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
445 if (!TryGetStringArgument (attribute, out method_name))
448 MarkNamedMethod (type, method_name);
451 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
455 if (attribute.ConstructorArguments.Count < 1)
458 argument = attribute.ConstructorArguments [0].Value as string;
460 return argument != null;
463 protected void MarkNamedMethod (TypeDefinition type, string method_name)
465 if (!type.HasMethods)
468 foreach (MethodDefinition method in type.Methods) {
469 if (method.Name != method_name)
476 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
479 if (!TryGetStringArgument (attribute, out member_name))
482 MarkNamedField (method.DeclaringType, member_name);
483 MarkNamedProperty (method.DeclaringType, member_name);
486 void MarkNamedField (TypeDefinition type, string field_name)
491 foreach (FieldDefinition field in type.Fields) {
492 if (field.Name != field_name)
499 void MarkNamedProperty (TypeDefinition type, string property_name)
501 if (!type.HasProperties)
504 foreach (PropertyDefinition property in type.Properties) {
505 if (property.Name != property_name)
508 MarkMethod (property.GetMethod);
509 MarkMethod (property.SetMethod);
513 void MarkGenericParameterProvider (IGenericParameterProvider provider)
515 if (!provider.HasGenericParameters)
518 foreach (GenericParameter parameter in provider.GenericParameters)
519 MarkGenericParameter (parameter);
522 void MarkGenericParameter (GenericParameter parameter)
524 MarkCustomAttributes (parameter);
525 foreach (TypeReference constraint in parameter.Constraints)
526 MarkType (constraint);
529 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
531 if (!method.IsVirtual)
534 var base_list = Annotations.GetBaseMethods (method);
535 if (base_list == null)
538 foreach (MethodDefinition @base in base_list) {
539 if (IgnoreScope (@base.DeclaringType.Scope))
542 if (IsVirtualAndHasPreservedParent (@base))
549 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
551 static bool IsSpecialSerializationConstructor (MethodDefinition method)
553 if (!IsConstructor (method))
556 var parameters = method.Parameters;
557 if (parameters.Count != 2)
560 return parameters [0].ParameterType.Name == "SerializationInfo" &&
561 parameters [1].ParameterType.Name == "StreamingContext";
564 delegate bool MethodPredicate (MethodDefinition method);
566 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
568 foreach (MethodDefinition method in methods)
569 if (predicate (method))
573 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
575 static bool IsDefaultConstructor (MethodDefinition method)
577 return IsConstructor (method) && !method.HasParameters;
580 static bool IsConstructor (MethodDefinition method)
582 return method.IsConstructor && !method.IsStatic;
585 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
587 static bool IsStaticConstructor (MethodDefinition method)
589 return method.IsConstructor && method.IsStatic;
592 static bool IsSerializable (TypeDefinition td)
594 return (td.Attributes & TypeAttributes.Serializable) != 0;
597 static bool IsMulticastDelegate (TypeDefinition td)
599 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
602 protected TypeDefinition ResolveTypeDefinition (TypeReference type)
604 TypeDefinition td = type as TypeDefinition;
606 td = type.Resolve ();
611 protected TypeReference GetOriginalType (TypeReference type)
613 while (type is TypeSpecification) {
614 GenericInstanceType git = type as GenericInstanceType;
616 MarkGenericArguments (git);
618 var mod = type as IModifierType;
620 MarkModifierType (mod);
622 type = ((TypeSpecification) type).ElementType;
628 void MarkModifierType (IModifierType mod)
630 MarkType (mod.ModifierType);
633 void MarkGenericArguments (IGenericInstance instance)
635 foreach (TypeReference argument in instance.GenericArguments)
638 MarkGenericArgumentConstructors (instance);
641 void MarkGenericArgumentConstructors (IGenericInstance instance)
643 var arguments = instance.GenericArguments;
645 var generic_element = GetGenericProviderFromInstance (instance);
646 if (generic_element == null)
649 var parameters = generic_element.GenericParameters;
651 if (arguments.Count != parameters.Count)
654 for (int i = 0; i < arguments.Count; i++) {
655 var argument = arguments [i];
656 var parameter = parameters [i];
658 if (!parameter.HasDefaultConstructorConstraint)
661 var argument_definition = ResolveTypeDefinition (argument);
662 if (argument_definition == null)
665 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
669 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
671 var method = instance as GenericInstanceMethod;
673 return ResolveMethodDefinition (method.ElementMethod);
675 var type = instance as GenericInstanceType;
677 return ResolveTypeDefinition (type.ElementType);
682 void ApplyPreserveInfo (TypeDefinition type)
684 ApplyPreserveMethods (type);
686 if (!Annotations.IsPreserved (type))
689 switch (Annotations.GetPreserve (type)) {
690 case TypePreserve.All:
691 MarkFields (type, true);
694 case TypePreserve.Fields:
695 MarkFields (type, true);
697 case TypePreserve.Methods:
703 void ApplyPreserveMethods (TypeDefinition type)
705 var list = Annotations.GetPreservedMethods (type);
709 MarkMethodCollection (list);
712 void ApplyPreserveMethods (MethodDefinition method)
714 var list = Annotations.GetPreservedMethods (method);
718 MarkMethodCollection (list);
721 protected void MarkFields (TypeDefinition type, bool includeStatic)
726 foreach (FieldDefinition field in type.Fields) {
727 if (!includeStatic && field.IsStatic)
733 protected virtual void MarkMethods (TypeDefinition type)
736 MarkMethodCollection (type.Methods);
739 void MarkMethodCollection (IEnumerable methods)
741 foreach (MethodDefinition method in methods)
745 protected virtual MethodDefinition MarkMethod (MethodReference reference)
747 reference = GetOriginalMethod (reference);
749 if (reference.DeclaringType is ArrayType)
752 if (reference.DeclaringType is GenericInstanceType)
753 MarkType (reference.DeclaringType);
755 // if (IgnoreScope (reference.DeclaringType.Scope))
758 MethodDefinition method = ResolveMethodDefinition (reference);
761 throw new ResolutionException (reference);
763 if (Annotations.GetAction (method) == MethodAction.Nothing)
764 Annotations.SetAction (method, MethodAction.Parse);
766 EnqueueMethod (method);
770 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
772 AssemblyDefinition assembly = _context.Resolve (scope);
773 MarkAssembly (assembly);
777 protected MethodReference GetOriginalMethod (MethodReference method)
779 while (method is MethodSpecification) {
780 GenericInstanceMethod gim = method as GenericInstanceMethod;
782 MarkGenericArguments (gim);
784 method = ((MethodSpecification) method).ElementMethod;
790 MethodDefinition ResolveMethodDefinition (MethodReference method)
792 MethodDefinition md = method as MethodDefinition;
794 md = method.Resolve ();
799 protected virtual void ProcessMethod (MethodDefinition method)
801 if (CheckProcessed (method))
804 MarkType (method.DeclaringType);
805 MarkCustomAttributes (method);
807 MarkGenericParameterProvider (method);
809 if (IsPropertyMethod (method))
810 MarkProperty (GetProperty (method));
811 else if (IsEventMethod (method))
812 MarkEvent (GetEvent (method));
814 if (method.HasParameters) {
815 foreach (ParameterDefinition pd in method.Parameters) {
816 MarkType (pd.ParameterType);
817 MarkCustomAttributes (pd);
818 MarkMarshalSpec (pd);
822 if (method.HasOverrides) {
823 foreach (MethodReference ov in method.Overrides)
827 MarkMethodSpecialCustomAttributes (method);
829 if (method.IsVirtual)
830 _virtual_methods.Add (method);
832 MarkBaseMethods (method);
834 MarkType (method.ReturnType);
835 MarkCustomAttributes (method.MethodReturnType);
836 MarkMarshalSpec (method.MethodReturnType);
838 if (ShouldParseMethodBody (method))
839 MarkMethodBody (method.Body);
841 Annotations.Mark (method);
843 ApplyPreserveMethods (method);
846 void MarkBaseMethods (MethodDefinition method)
848 IList base_methods = Annotations.GetBaseMethods (method);
849 if (base_methods == null)
852 foreach (MethodDefinition base_method in base_methods) {
853 if (base_method.DeclaringType.IsInterface && !method.DeclaringType.IsInterface)
856 MarkMethod (base_method);
857 MarkBaseMethods (base_method);
861 bool ShouldParseMethodBody (MethodDefinition method)
866 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
867 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
868 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
871 static internal bool IsPropertyMethod (MethodDefinition md)
873 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
874 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
877 static bool IsEventMethod (MethodDefinition md)
879 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
880 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
881 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
884 static internal PropertyDefinition GetProperty (MethodDefinition md)
886 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
887 foreach (PropertyDefinition prop in declaringType.Properties)
888 if (prop.GetMethod == md || prop.SetMethod == md)
894 static EventDefinition GetEvent (MethodDefinition md)
896 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
897 foreach (EventDefinition evt in declaringType.Events)
898 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
904 protected void MarkProperty (PropertyDefinition prop)
906 MarkCustomAttributes (prop);
909 protected void MarkEvent (EventDefinition evt)
911 MarkCustomAttributes (evt);
912 MarkMethodIfNotNull (evt.AddMethod);
913 MarkMethodIfNotNull (evt.InvokeMethod);
914 MarkMethodIfNotNull (evt.RemoveMethod);
917 void MarkMethodIfNotNull (MethodReference method)
925 protected virtual void MarkMethodBody (MethodBody body)
927 foreach (VariableDefinition var in body.Variables)
928 MarkType (var.VariableType);
930 foreach (ExceptionHandler eh in body.ExceptionHandlers)
931 if (eh.HandlerType == ExceptionHandlerType.Catch)
932 MarkType (eh.CatchType);
934 foreach (Instruction instruction in body.Instructions)
935 MarkInstruction (instruction);
938 protected virtual void MarkInstruction (Instruction instruction)
940 switch (instruction.OpCode.OperandType) {
941 case OperandType.InlineField:
942 MarkField ((FieldReference) instruction.Operand);
944 case OperandType.InlineMethod:
945 MarkMethod ((MethodReference) instruction.Operand);
947 case OperandType.InlineTok:
948 object token = instruction.Operand;
949 if (token is TypeReference)
950 MarkType ((TypeReference) token);
951 else if (token is MethodReference)
952 MarkMethod ((MethodReference) token);
954 MarkField ((FieldReference) token);
956 case OperandType.InlineType:
957 MarkType ((TypeReference) instruction.Operand);