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 {
43 ArrayList _virtual_methods;
45 public AnnotationStore Annotations {
46 get { return _context.Annotations; }
51 _methods = new Queue ();
52 _virtual_methods = new ArrayList ();
55 public 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 FieldDefinition field = ResolveFieldDefinition (reference);
295 throw new ResolutionException (reference);
297 if (CheckProcessed (field))
300 MarkType (field.DeclaringType);
301 MarkType (field.FieldType);
302 MarkCustomAttributes (field);
303 MarkMarshalSpec (field);
305 Annotations.Mark (field);
308 protected virtual bool IgnoreScope (IMetadataScope scope)
310 AssemblyDefinition assembly = ResolveAssembly (scope);
311 return Annotations.GetAction (assembly) != AssemblyAction.Link;
314 FieldDefinition ResolveFieldDefinition (FieldReference field)
316 FieldDefinition fd = field as FieldDefinition;
318 fd = field.Resolve ();
323 void MarkScope (IMetadataScope scope)
325 var provider = scope as IMetadataTokenProvider;
326 if (provider == null)
329 Annotations.Mark (provider);
332 protected virtual void MarkType (TypeReference reference)
334 if (reference == null)
337 reference = GetOriginalType (reference);
339 if (reference is GenericParameter)
342 // if (IgnoreScope (reference.Scope))
345 TypeDefinition type = ResolveTypeDefinition (reference);
348 throw new ResolutionException (reference);
350 if (CheckProcessed (type))
353 MarkScope (type.Scope);
354 MarkType (type.BaseType);
355 MarkType (type.DeclaringType);
356 MarkCustomAttributes (type);
358 if (IsMulticastDelegate (type)) {
359 MarkMethodCollection (type.Methods);
362 if (IsSerializable (type) && type.HasMethods) {
363 MarkMethodsIf (type.Methods, IsDefaultConstructorPredicate);
364 MarkMethodsIf (type.Methods, IsSpecialSerializationConstructorPredicate);
367 MarkTypeSpecialCustomAttributes (type);
369 MarkGenericParameterProvider (type);
371 if (type.IsValueType)
374 if (type.HasInterfaces) {
375 foreach (TypeReference iface in type.Interfaces)
379 if (type.HasMethods) {
380 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
381 MarkMethodsIf (type.Methods, IsStaticConstructorPredicate);
384 Annotations.Mark (type);
386 ApplyPreserveInfo (type);
389 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
391 if (!type.HasCustomAttributes)
394 foreach (CustomAttribute attribute in type.CustomAttributes) {
395 switch (attribute.Constructor.DeclaringType.FullName) {
396 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
397 MarkXmlSchemaProvider (type, attribute);
403 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
405 if (!method.HasCustomAttributes)
408 foreach (CustomAttribute attribute in method.CustomAttributes) {
409 switch (attribute.Constructor.DeclaringType.FullName) {
410 case "System.Web.Services.Protocols.SoapHeaderAttribute":
411 MarkSoapHeader (method, attribute);
417 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
420 if (!TryGetStringArgument (attribute, out method_name))
423 MarkNamedMethod (type, method_name);
426 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
430 if (attribute.ConstructorArguments.Count < 1)
433 argument = attribute.ConstructorArguments [0].Value as string;
435 return argument != null;
438 void MarkNamedMethod (TypeDefinition type, string method_name)
440 if (!type.HasMethods)
443 foreach (MethodDefinition method in type.Methods) {
444 if (method.Name != method_name)
451 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
454 if (!TryGetStringArgument (attribute, out member_name))
457 MarkNamedField (method.DeclaringType, member_name);
458 MarkNamedProperty (method.DeclaringType, member_name);
461 void MarkNamedField (TypeDefinition type, string field_name)
466 foreach (FieldDefinition field in type.Fields) {
467 if (field.Name != field_name)
474 void MarkNamedProperty (TypeDefinition type, string property_name)
476 if (!type.HasProperties)
479 foreach (PropertyDefinition property in type.Properties) {
480 if (property.Name != property_name)
483 MarkMethod (property.GetMethod);
484 MarkMethod (property.SetMethod);
488 void MarkGenericParameterProvider (IGenericParameterProvider provider)
490 if (!provider.HasGenericParameters)
493 foreach (GenericParameter parameter in provider.GenericParameters)
494 MarkGenericParameter (parameter);
497 void MarkGenericParameter (GenericParameter parameter)
499 MarkCustomAttributes (parameter);
500 foreach (TypeReference constraint in parameter.Constraints)
501 MarkType (constraint);
504 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
506 if (!method.IsVirtual)
509 var base_list = Annotations.GetBaseMethods (method);
510 if (base_list == null)
513 foreach (MethodDefinition @base in base_list) {
514 if (IgnoreScope (@base.DeclaringType.Scope))
517 if (IsVirtualAndHasPreservedParent (@base))
524 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
526 static bool IsSpecialSerializationConstructor (MethodDefinition method)
528 if (!IsConstructor (method))
531 var parameters = method.Parameters;
532 if (parameters.Count != 2)
535 return parameters [0].ParameterType.Name == "SerializationInfo" &&
536 parameters [1].ParameterType.Name == "StreamingContext";
539 delegate bool MethodPredicate (MethodDefinition method);
541 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
543 foreach (MethodDefinition method in methods)
544 if (predicate (method))
548 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
550 static bool IsDefaultConstructor (MethodDefinition method)
552 return IsConstructor (method) && method.Parameters.Count == 0;
555 static bool IsConstructor (MethodDefinition method)
557 return method.IsConstructor && !method.IsStatic;
560 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
562 static bool IsStaticConstructor (MethodDefinition method)
564 return method.IsConstructor && method.IsStatic;
567 static bool IsSerializable (TypeDefinition td)
569 return (td.Attributes & TypeAttributes.Serializable) != 0;
572 static bool IsMulticastDelegate (TypeDefinition td)
574 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
577 TypeDefinition ResolveTypeDefinition (TypeReference type)
579 TypeDefinition td = type as TypeDefinition;
581 td = type.Resolve ();
586 protected TypeReference GetOriginalType (TypeReference type)
588 while (type is TypeSpecification) {
589 GenericInstanceType git = type as GenericInstanceType;
591 MarkGenericArguments (git);
593 var mod = type as IModifierType;
595 MarkModifierType (mod);
597 type = ((TypeSpecification) type).ElementType;
603 void MarkModifierType (IModifierType mod)
605 MarkType (mod.ModifierType);
608 void MarkGenericArguments (IGenericInstance instance)
610 foreach (TypeReference argument in instance.GenericArguments)
613 MarkGenericArgumentConstructors (instance);
616 void MarkGenericArgumentConstructors (IGenericInstance instance)
618 var arguments = instance.GenericArguments;
620 var generic_element = GetGenericProviderFromInstance (instance);
621 if (generic_element == null)
624 var parameters = generic_element.GenericParameters;
626 if (arguments.Count != parameters.Count)
629 for (int i = 0; i < arguments.Count; i++) {
630 var argument = arguments [i];
631 var parameter = parameters [i];
633 if (!parameter.HasDefaultConstructorConstraint)
636 var argument_definition = ResolveTypeDefinition (argument);
637 if (argument_definition == null)
640 MarkMethodsIf (argument_definition.Methods, ctor => !ctor.IsStatic && !ctor.HasParameters);
644 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
646 var method = instance as GenericInstanceMethod;
648 return method.ElementMethod;
650 var type = instance as GenericInstanceType;
652 return type.ElementType;
657 void ApplyPreserveInfo (TypeDefinition type)
659 ApplyPreserveMethods (type);
661 if (!Annotations.IsPreserved (type))
664 switch (Annotations.GetPreserve (type)) {
665 case TypePreserve.All:
669 case TypePreserve.Fields:
672 case TypePreserve.Methods:
678 void ApplyPreserveMethods (TypeDefinition type)
680 var list = Annotations.GetPreservedMethods (type);
684 foreach (MethodDefinition method in list)
688 void MarkFields (TypeDefinition type)
693 foreach (FieldDefinition field in type.Fields)
697 void MarkMethods (TypeDefinition type)
700 MarkMethodCollection (type.Methods);
703 void MarkMethodCollection (IEnumerable methods)
705 foreach (MethodDefinition method in methods)
709 void MarkMethod (MethodReference reference)
711 reference = GetOriginalMethod (reference);
713 if (reference.DeclaringType is ArrayType)
716 // if (IgnoreScope (reference.DeclaringType.Scope))
719 MethodDefinition method = ResolveMethodDefinition (reference);
722 throw new ResolutionException (reference);
724 if (Annotations.GetAction (method) == MethodAction.Nothing)
725 Annotations.SetAction (method, MethodAction.Parse);
727 EnqueueMethod (method);
730 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
732 AssemblyDefinition assembly = _context.Resolve (scope);
733 MarkAssembly (assembly);
737 MethodReference GetOriginalMethod (MethodReference method)
739 while (method is MethodSpecification) {
740 GenericInstanceMethod gim = method as GenericInstanceMethod;
742 MarkGenericArguments (gim);
744 method = ((MethodSpecification) method).ElementMethod;
750 MethodDefinition ResolveMethodDefinition (MethodReference method)
752 MethodDefinition md = method as MethodDefinition;
754 md = method.Resolve ();
759 void ProcessMethod (MethodDefinition method)
761 if (CheckProcessed (method))
764 MarkType (method.DeclaringType);
765 MarkCustomAttributes (method);
767 MarkGenericParameterProvider (method);
769 if (IsPropertyMethod (method))
770 MarkProperty (GetProperty (method));
771 else if (IsEventMethod (method))
772 MarkEvent (GetEvent (method));
774 if (method.HasParameters) {
775 foreach (ParameterDefinition pd in method.Parameters) {
776 MarkType (pd.ParameterType);
777 MarkCustomAttributes (pd);
778 MarkMarshalSpec (pd);
782 if (method.HasOverrides) {
783 foreach (MethodReference ov in method.Overrides)
787 MarkMethodSpecialCustomAttributes (method);
789 if (method.IsVirtual)
790 _virtual_methods.Add (method);
792 MarkBaseMethods (method);
794 MarkType (method.ReturnType);
795 MarkCustomAttributes (method.MethodReturnType);
796 MarkMarshalSpec (method.MethodReturnType);
798 if (ShouldParseMethodBody (method))
799 MarkMethodBody (method.Body);
801 Annotations.Mark (method);
804 void MarkBaseMethods (MethodDefinition method)
806 IList base_methods = Annotations.GetBaseMethods (method);
807 if (base_methods == null)
810 foreach (MethodDefinition base_method in base_methods) {
811 MarkMethod (base_method);
812 MarkBaseMethods (base_method);
816 bool ShouldParseMethodBody (MethodDefinition method)
821 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
822 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
823 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
826 static bool IsPropertyMethod (MethodDefinition md)
828 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
829 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
832 static bool IsEventMethod (MethodDefinition md)
834 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
835 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
836 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
839 static PropertyDefinition GetProperty (MethodDefinition md)
841 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
842 foreach (PropertyDefinition prop in declaringType.Properties)
843 if (prop.GetMethod == md || prop.SetMethod == md)
849 static EventDefinition GetEvent (MethodDefinition md)
851 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
852 foreach (EventDefinition evt in declaringType.Events)
853 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
859 void MarkProperty (PropertyDefinition prop)
861 MarkCustomAttributes (prop);
864 void MarkEvent (EventDefinition evt)
866 MarkCustomAttributes (evt);
867 MarkMethodIfNotNull (evt.AddMethod);
868 MarkMethodIfNotNull (evt.InvokeMethod);
869 MarkMethodIfNotNull (evt.RemoveMethod);
872 void MarkMethodIfNotNull (MethodReference method)
880 void MarkMethodBody (MethodBody body)
882 foreach (VariableDefinition var in body.Variables)
883 MarkType (var.VariableType);
885 foreach (ExceptionHandler eh in body.ExceptionHandlers)
886 if (eh.HandlerType == ExceptionHandlerType.Catch)
887 MarkType (eh.CatchType);
889 foreach (Instruction instruction in body.Instructions)
890 MarkInstruction (instruction);
893 void MarkInstruction (Instruction instruction)
895 switch (instruction.OpCode.OperandType) {
896 case OperandType.InlineField:
897 MarkField ((FieldReference) instruction.Operand);
899 case OperandType.InlineMethod:
900 MarkMethod ((MethodReference) instruction.Operand);
902 case OperandType.InlineTok:
903 object token = instruction.Operand;
904 if (token is TypeReference)
905 MarkType ((TypeReference) token);
906 else if (token is MethodReference)
907 MarkMethod ((MethodReference) token);
909 MarkField ((FieldReference) token);
911 case OperandType.InlineType:
912 MarkType ((TypeReference) instruction.Operand);