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;
35 namespace Mono.Linker.Steps {
37 public class MarkStep : IStep {
41 ArrayList _virtual_methods;
45 _methods = new Queue ();
46 _virtual_methods = new ArrayList ();
49 public void Process (LinkContext context)
59 foreach (AssemblyDefinition assembly in _context.GetAssemblies ())
60 InitializeAssembly (assembly);
63 protected virtual void InitializeAssembly (AssemblyDefinition assembly)
65 MarkAssembly (assembly);
66 foreach (TypeDefinition type in assembly.MainModule.Types) {
67 if (!Annotations.IsMarked (type))
70 InitializeType (type);
74 void InitializeType (TypeDefinition type)
79 InitializeFields (type);
81 InitializeMethods (type.Methods);
82 if (type.HasConstructors)
83 InitializeMethods (type.Constructors);
86 void InitializeFields (TypeDefinition type)
88 foreach (FieldDefinition field in type.Fields)
89 if (Annotations.IsMarked (field))
93 void InitializeMethods (ICollection methods)
95 foreach (MethodDefinition method in methods)
96 if (Annotations.IsMarked (method))
97 EnqueueMethod (method);
103 throw new InvalidOperationException ("No entry methods");
105 while (!QueueIsEmpty ()) {
107 ProcessVirtualMethods ();
113 while (!QueueIsEmpty ()) {
114 MethodDefinition method = (MethodDefinition) _methods.Dequeue ();
115 ProcessMethod (method);
121 return _methods.Count == 0;
124 protected virtual void EnqueueMethod (MethodDefinition method)
126 _methods.Enqueue (method);
129 void ProcessVirtualMethods ()
131 foreach (MethodDefinition method in _virtual_methods)
132 ProcessVirtualMethod (method);
135 void ProcessVirtualMethod (MethodDefinition method)
137 IList overrides = Annotations.GetOverrides (method);
138 if (overrides == null)
141 foreach (MethodDefinition @override in overrides)
142 ProcessOverride (@override);
145 void ProcessOverride (MethodDefinition method)
147 if (!Annotations.IsMarked (method.DeclaringType))
150 if (Annotations.IsProcessed (method))
153 if (Annotations.IsMarked (method))
157 ProcessVirtualMethod (method);
160 void MarkMethodBody (MethodBody body)
162 foreach (VariableDefinition var in body.Variables)
163 MarkType (var.VariableType);
165 foreach (ExceptionHandler eh in body.ExceptionHandlers)
166 if (eh.Type == ExceptionHandlerType.Catch)
167 MarkType (eh.CatchType);
169 foreach (Instruction instruction in body.Instructions)
170 MarkInstruction (instruction);
173 void MarkMarshalSpec (IHasMarshalSpec spec)
175 CustomMarshalerSpec marshaler = spec.MarshalSpec as CustomMarshalerSpec;
176 if (marshaler == null)
179 TypeDefinition type = _context.GetType (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);
204 MarkCustomAttributeParameters (ca);
206 TypeReference constructor_type = ca.Constructor.DeclaringType;
207 TypeDefinition type = constructor_type.Resolve ();
209 throw new ResolutionException (constructor_type);
211 MarkCustomAttributeProperties (ca, type);
212 MarkCustomAttributeFields (ca, type);
215 void MarkCustomAttributeProperties (CustomAttribute ca, TypeDefinition attribute)
217 foreach (DictionaryEntry de in ca.Properties) {
218 string propertyname = (string) de.Key;
220 PropertyDefinition property = GetProperty (attribute, propertyname);
221 if (property != null)
222 MarkMethod (property.SetMethod);
224 TypeReference propType = ca.GetPropertyType (propertyname);
225 MarkIfType (propType, de.Value);
229 PropertyDefinition GetProperty (TypeDefinition type, string propertyname)
231 while (type != null) {
232 PropertyDefinition [] properties = type.Properties.GetProperties (propertyname);
233 if (properties != null && properties.Length != 0 && properties [0].SetMethod != null)
234 return properties [0];
236 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
242 void MarkCustomAttributeFields (CustomAttribute ca, TypeDefinition attribute)
244 foreach (DictionaryEntry de in ca.Fields) {
245 string fieldname = (string) de.Key;
247 FieldDefinition field = GetField (attribute, fieldname);
251 TypeReference fieldType = ca.GetFieldType (fieldname);
252 MarkIfType (fieldType, de.Value);
256 FieldDefinition GetField (TypeDefinition type, string fieldname)
258 while (type != null) {
259 FieldDefinition field = type.Fields.GetField (fieldname);
263 type = type.BaseType != null ? ResolveTypeDefinition (type.BaseType) : null;
269 void MarkCustomAttributeParameters (CustomAttribute ca)
271 for (int i = 0; i < ca.Constructor.Parameters.Count; i++) {
272 ParameterDefinition param = ca.Constructor.Parameters [i];
273 MarkIfType (param.ParameterType, ca.ConstructorParameters [i]);
277 void MarkIfType (TypeReference slotType, object value)
279 if (slotType.FullName != Constants.Type)
282 string type_name = (string) value;
285 var type = TypeParser.ParseType (slotType.Module, type_name);
295 protected static bool CheckProcessed (IAnnotationProvider provider)
297 if (Annotations.IsProcessed (provider))
300 Annotations.Processed (provider);
304 void MarkAssembly (AssemblyDefinition assembly)
306 if (CheckProcessed (assembly))
309 MarkCustomAttributes (assembly);
311 foreach (ModuleDefinition module in assembly.Modules)
312 MarkCustomAttributes (module);
315 void MarkField (FieldReference reference)
317 // if (IgnoreScope (reference.DeclaringType.Scope))
320 FieldDefinition field = ResolveFieldDefinition (reference);
323 throw new ResolutionException (reference);
325 if (CheckProcessed (field))
328 MarkType (field.DeclaringType);
329 MarkType (field.FieldType);
330 MarkCustomAttributes (field);
331 MarkMarshalSpec (field);
333 Annotations.Mark (field);
336 protected virtual bool IgnoreScope (IMetadataScope scope)
338 AssemblyDefinition assembly = ResolveAssembly (scope);
339 return Annotations.GetAction (assembly) != AssemblyAction.Link;
342 FieldDefinition ResolveFieldDefinition (FieldReference field)
344 FieldDefinition fd = field as FieldDefinition;
346 fd = field.Resolve ();
351 void MarkScope (IMetadataScope scope)
353 IAnnotationProvider provider = scope as IAnnotationProvider;
354 if (provider == null)
357 Annotations.Mark (provider);
360 protected virtual void MarkType (TypeReference reference)
362 if (reference == null)
365 reference = GetOriginalType (reference);
367 if (reference is GenericParameter)
370 // if (IgnoreScope (reference.Scope))
373 TypeDefinition type = ResolveTypeDefinition (reference);
376 throw new ResolutionException (reference);
378 if (CheckProcessed (type))
381 MarkScope (type.Scope);
382 MarkType (type.BaseType);
383 MarkType (type.DeclaringType);
384 MarkCustomAttributes (type);
386 if (IsMulticastDelegate (type)) {
387 MarkMethodCollection (type.Constructors);
388 MarkMethodCollection (type.Methods);
391 if (IsSerializable (type) && type.HasConstructors) {
392 MarkMethodsIf (type.Constructors, IsDefaultConstructorPredicate);
393 MarkMethodsIf (type.Constructors, IsSpecialSerializationConstructorPredicate);
396 MarkTypeSpecialCustomAttributes (type);
398 MarkGenericParameterProvider (type);
400 if (type.IsValueType)
403 if (type.HasInterfaces) {
404 foreach (TypeReference iface in type.Interfaces)
409 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
411 if (type.HasConstructors)
412 MarkMethodsIf (type.Constructors, IsStaticConstructorPredicate);
414 Annotations.Mark (type);
416 ApplyPreserveInfo (type);
419 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
421 if (!type.HasCustomAttributes)
424 foreach (CustomAttribute attribute in type.CustomAttributes) {
425 switch (attribute.Constructor.DeclaringType.FullName) {
426 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
427 MarkXmlSchemaProvider (type, attribute);
433 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
435 if (!method.HasCustomAttributes)
438 foreach (CustomAttribute attribute in method.CustomAttributes) {
439 switch (attribute.Constructor.DeclaringType.FullName) {
440 case "System.Web.Services.Protocols.SoapHeaderAttribute":
441 MarkSoapHeader (method, attribute);
447 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
450 if (!TryGetStringArgument (attribute, out method_name))
453 MarkNamedMethod (type, method_name);
456 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
460 if (!attribute.Resolved || attribute.ConstructorParameters.Count < 1)
463 argument = attribute.ConstructorParameters [0] as string;
465 return argument != null;
468 void MarkNamedMethod (TypeDefinition type, string method_name)
470 if (!type.HasMethods)
473 foreach (MethodDefinition method in type.Methods) {
474 if (method.Name != method_name)
481 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
484 if (!TryGetStringArgument (attribute, out member_name))
487 MarkNamedField (method.DeclaringType, member_name);
488 MarkNamedProperty (method.DeclaringType, member_name);
491 void MarkNamedField (TypeDefinition type, string field_name)
496 foreach (FieldDefinition field in type.Fields) {
497 if (field.Name != field_name)
504 void MarkNamedProperty (TypeDefinition type, string property_name)
506 if (!type.HasProperties)
509 foreach (PropertyDefinition property in type.Properties) {
510 if (property.Name != property_name)
513 MarkMethod (property.GetMethod);
514 MarkMethod (property.SetMethod);
518 void MarkGenericParameterProvider (IGenericParameterProvider provider)
520 if (!provider.HasGenericParameters)
523 foreach (GenericParameter parameter in provider.GenericParameters)
524 MarkGenericParameter (parameter);
527 void MarkGenericParameter (GenericParameter parameter)
529 MarkCustomAttributes (parameter);
530 foreach (TypeReference constraint in parameter.Constraints)
531 MarkType (constraint);
534 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
536 if (!method.IsVirtual)
539 var base_list = Annotations.GetBaseMethods (method);
540 if (base_list == null)
543 foreach (MethodDefinition @base in base_list) {
544 if (IgnoreScope (@base.DeclaringType.Scope))
547 if (IsVirtualAndHasPreservedParent (@base))
554 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
556 static bool IsSpecialSerializationConstructor (MethodDefinition method)
558 if (!IsConstructor (method))
561 ParameterDefinitionCollection parameters = method.Parameters;
562 if (parameters.Count != 2)
565 return parameters [0].ParameterType.Name == "SerializationInfo" &&
566 parameters [1].ParameterType.Name == "StreamingContext";
569 delegate bool MethodPredicate (MethodDefinition method);
571 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
573 foreach (MethodDefinition method in methods)
574 if (predicate (method))
578 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
580 static bool IsDefaultConstructor (MethodDefinition method)
582 return IsConstructor (method) && method.Parameters.Count == 0;
585 static bool IsConstructor (MethodDefinition method)
587 return method.Name == MethodDefinition.Ctor && method.IsSpecialName &&
588 method.IsRuntimeSpecialName;
591 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
593 static bool IsStaticConstructor (MethodDefinition method)
595 return method.Name == MethodDefinition.Cctor && method.IsSpecialName &&
596 method.IsRuntimeSpecialName;
599 static bool IsSerializable (TypeDefinition td)
601 return (td.Attributes & TypeAttributes.Serializable) != 0;
604 static bool IsMulticastDelegate (TypeDefinition td)
606 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
609 TypeDefinition ResolveTypeDefinition (TypeReference type)
611 TypeDefinition td = type as TypeDefinition;
613 td = type.Resolve ();
618 protected TypeReference GetOriginalType (TypeReference type)
620 while (type is TypeSpecification) {
621 GenericInstanceType git = type as GenericInstanceType;
623 MarkGenericArguments (git);
625 ModType mod = type as ModType;
627 MarkModifierType (mod);
629 type = ((TypeSpecification) type).ElementType;
635 void MarkModifierType (ModType mod)
637 MarkType (mod.ModifierType);
640 void MarkGenericArguments (IGenericInstance instance)
642 foreach (TypeReference argument in instance.GenericArguments)
645 MarkGenericArgumentConstructors (instance);
648 void MarkGenericArgumentConstructors (IGenericInstance instance)
650 var arguments = instance.GenericArguments;
652 var generic_element = GetGenericProviderFromInstance (instance);
653 if (generic_element == null)
656 var parameters = generic_element.GenericParameters;
658 if (arguments.Count != parameters.Count)
661 for (int i = 0; i < arguments.Count; i++) {
662 var argument = arguments [i];
663 var parameter = parameters [i];
665 if (!parameter.HasDefaultConstructorConstraint)
668 var argument_definition = ResolveTypeDefinition (argument);
669 if (argument_definition == null)
672 MarkMethodsIf (argument_definition.Constructors, ctor => !ctor.IsStatic && !ctor.HasParameters);
676 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
678 var method = instance as GenericInstanceMethod;
680 return method.ElementMethod;
682 var type = instance as GenericInstanceType;
684 return type.ElementType;
689 void ApplyPreserveInfo (TypeDefinition type)
691 ApplyPreserveMethods (type);
693 if (!Annotations.IsPreserved (type))
696 switch (Annotations.GetPreserve (type)) {
697 case TypePreserve.All:
701 case TypePreserve.Fields:
704 case TypePreserve.Methods:
710 void ApplyPreserveMethods (TypeDefinition type)
712 var list = Annotations.GetPreservedMethods (type);
716 foreach (MethodDefinition method in list)
720 void MarkFields (TypeDefinition type)
725 foreach (FieldDefinition field in type.Fields)
729 void MarkMethods (TypeDefinition type)
732 MarkMethodCollection (type.Methods);
733 if (type.HasConstructors)
734 MarkMethodCollection (type.Constructors);
737 void MarkMethodCollection (IEnumerable methods)
739 foreach (MethodDefinition method in methods)
743 void MarkMethod (MethodReference reference)
745 reference = GetOriginalMethod (reference);
747 if (reference.DeclaringType is ArrayType)
750 // if (IgnoreScope (reference.DeclaringType.Scope))
753 MethodDefinition method = ResolveMethodDefinition (reference);
756 throw new ResolutionException (reference);
758 if (Annotations.GetAction (method) == MethodAction.Nothing)
759 Annotations.SetAction (method, MethodAction.Parse);
761 EnqueueMethod (method);
764 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
766 AssemblyDefinition assembly = _context.Resolve (scope);
767 MarkAssembly (assembly);
771 MethodReference GetOriginalMethod (MethodReference method)
773 while (method is MethodSpecification) {
774 GenericInstanceMethod gim = method as GenericInstanceMethod;
776 MarkGenericArguments (gim);
778 method = ((MethodSpecification) method).ElementMethod;
784 MethodDefinition ResolveMethodDefinition (MethodReference method)
786 MethodDefinition md = method as MethodDefinition;
788 md = method.Resolve ();
793 void ProcessMethod (MethodDefinition method)
795 if (CheckProcessed (method))
798 MarkType (method.DeclaringType);
799 MarkCustomAttributes (method);
801 MarkGenericParameterProvider (method);
803 if (IsPropertyMethod (method))
804 MarkProperty (GetProperty (method));
805 else if (IsEventMethod (method))
806 MarkEvent (GetEvent (method));
808 if (method.HasParameters) {
809 foreach (ParameterDefinition pd in method.Parameters) {
810 MarkType (pd.ParameterType);
811 MarkCustomAttributes (pd);
812 MarkMarshalSpec (pd);
816 if (method.HasOverrides) {
817 foreach (MethodReference ov in method.Overrides)
821 MarkMethodSpecialCustomAttributes (method);
823 if (method.IsVirtual)
824 _virtual_methods.Add (method);
826 MarkBaseMethods (method);
828 MarkType (method.ReturnType.ReturnType);
829 MarkCustomAttributes (method.ReturnType);
830 MarkMarshalSpec (method.ReturnType);
832 if (ShouldParseMethodBody (method))
833 MarkMethodBody (method.Body);
835 Annotations.Mark (method);
838 void MarkBaseMethods (MethodDefinition method)
840 IList base_methods = Annotations.GetBaseMethods (method);
841 if (base_methods == null)
844 foreach (MethodDefinition base_method in base_methods) {
845 MarkMethod (base_method);
846 MarkBaseMethods (base_method);
850 bool ShouldParseMethodBody (MethodDefinition method)
855 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
856 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
857 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
860 static bool IsPropertyMethod (MethodDefinition md)
862 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
863 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
866 static bool IsEventMethod (MethodDefinition md)
868 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
869 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
870 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
873 static PropertyDefinition GetProperty (MethodDefinition md)
875 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
876 foreach (PropertyDefinition prop in declaringType.Properties)
877 if (prop.GetMethod == md || prop.SetMethod == md)
883 static EventDefinition GetEvent (MethodDefinition md)
885 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
886 foreach (EventDefinition evt in declaringType.Events)
887 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
893 void MarkProperty (PropertyDefinition prop)
895 MarkCustomAttributes (prop);
898 void MarkEvent (EventDefinition evt)
900 MarkCustomAttributes (evt);
901 MarkMethodIfNotNull (evt.AddMethod);
902 MarkMethodIfNotNull (evt.InvokeMethod);
903 MarkMethodIfNotNull (evt.RemoveMethod);
906 void MarkMethodIfNotNull (MethodReference method)
914 void MarkInstruction (Instruction instruction)
916 switch (instruction.OpCode.OperandType) {
917 case OperandType.InlineField:
918 MarkField ((FieldReference) instruction.Operand);
920 case OperandType.InlineMethod:
921 MarkMethod ((MethodReference) instruction.Operand);
923 case OperandType.InlineTok:
924 object token = instruction.Operand;
925 if (token is TypeReference)
926 MarkType ((TypeReference) token);
927 else if (token is MethodReference)
928 MarkMethod ((MethodReference) token);
930 MarkField ((FieldReference) token);
932 case OperandType.InlineType:
933 MarkType ((TypeReference) instruction.Operand);