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 TypeDefinition type = _context.GetType ((string) value);
287 protected static bool CheckProcessed (IAnnotationProvider provider)
289 if (Annotations.IsProcessed (provider))
292 Annotations.Processed (provider);
296 void MarkAssembly (AssemblyDefinition assembly)
298 if (CheckProcessed (assembly))
301 MarkCustomAttributes (assembly);
303 foreach (ModuleDefinition module in assembly.Modules)
304 MarkCustomAttributes (module);
307 void MarkField (FieldReference reference)
309 // if (IgnoreScope (reference.DeclaringType.Scope))
312 FieldDefinition field = ResolveFieldDefinition (reference);
315 throw new ResolutionException (reference);
317 if (CheckProcessed (field))
320 MarkType (field.DeclaringType);
321 MarkType (field.FieldType);
322 MarkCustomAttributes (field);
323 MarkMarshalSpec (field);
325 Annotations.Mark (field);
328 protected virtual bool IgnoreScope (IMetadataScope scope)
330 AssemblyDefinition assembly = ResolveAssembly (scope);
331 return Annotations.GetAction (assembly) != AssemblyAction.Link;
334 FieldDefinition ResolveFieldDefinition (FieldReference field)
336 FieldDefinition fd = field as FieldDefinition;
338 fd = field.Resolve ();
343 void MarkScope (IMetadataScope scope)
345 IAnnotationProvider provider = scope as IAnnotationProvider;
346 if (provider == null)
349 Annotations.Mark (provider);
352 protected virtual void MarkType (TypeReference reference)
354 if (reference == null)
357 reference = GetOriginalType (reference);
359 if (reference is GenericParameter)
362 // if (IgnoreScope (reference.Scope))
365 TypeDefinition type = ResolveTypeDefinition (reference);
368 throw new ResolutionException (reference);
370 if (CheckProcessed (type))
373 MarkScope (type.Scope);
374 MarkType (type.BaseType);
375 MarkType (type.DeclaringType);
376 MarkCustomAttributes (type);
378 if (IsMulticastDelegate (type)) {
379 MarkMethodCollection (type.Constructors);
380 MarkMethodCollection (type.Methods);
383 if (IsSerializable (type) && type.HasConstructors) {
384 MarkMethodsIf (type.Constructors, IsDefaultConstructorPredicate);
385 MarkMethodsIf (type.Constructors, IsSpecialSerializationConstructorPredicate);
388 MarkTypeSpecialCustomAttributes (type);
390 MarkGenericParameterProvider (type);
392 if (type.IsValueType)
395 if (type.HasInterfaces) {
396 foreach (TypeReference iface in type.Interfaces)
401 MarkMethodsIf (type.Methods, IsVirtualAndHasPreservedParent);
403 if (type.HasConstructors)
404 MarkMethodsIf (type.Constructors, IsStaticConstructorPredicate);
406 Annotations.Mark (type);
408 ApplyPreserveInfo (type);
411 void MarkTypeSpecialCustomAttributes (TypeDefinition type)
413 if (!type.HasCustomAttributes)
416 foreach (CustomAttribute attribute in type.CustomAttributes) {
417 switch (attribute.Constructor.DeclaringType.FullName) {
418 case "System.Xml.Serialization.XmlSchemaProviderAttribute":
419 MarkXmlSchemaProvider (type, attribute);
425 void MarkMethodSpecialCustomAttributes (MethodDefinition method)
427 if (!method.HasCustomAttributes)
430 foreach (CustomAttribute attribute in method.CustomAttributes) {
431 switch (attribute.Constructor.DeclaringType.FullName) {
432 case "System.Web.Services.Protocols.SoapHeaderAttribute":
433 MarkSoapHeader (method, attribute);
439 void MarkXmlSchemaProvider (TypeDefinition type, CustomAttribute attribute)
442 if (!TryGetStringArgument (attribute, out method_name))
445 MarkNamedMethod (type, method_name);
448 static bool TryGetStringArgument (CustomAttribute attribute, out string argument)
452 if (!attribute.Resolved || attribute.ConstructorParameters.Count < 1)
455 argument = attribute.ConstructorParameters [0] as string;
457 return argument != null;
460 void MarkNamedMethod (TypeDefinition type, string method_name)
462 if (!type.HasMethods)
465 foreach (MethodDefinition method in type.Methods) {
466 if (method.Name != method_name)
473 void MarkSoapHeader (MethodDefinition method, CustomAttribute attribute)
476 if (!TryGetStringArgument (attribute, out member_name))
479 MarkNamedField (method.DeclaringType, member_name);
480 MarkNamedProperty (method.DeclaringType, member_name);
483 void MarkNamedField (TypeDefinition type, string field_name)
488 foreach (FieldDefinition field in type.Fields) {
489 if (field.Name != field_name)
496 void MarkNamedProperty (TypeDefinition type, string property_name)
498 if (!type.HasProperties)
501 foreach (PropertyDefinition property in type.Properties) {
502 if (property.Name != property_name)
505 MarkMethod (property.GetMethod);
506 MarkMethod (property.SetMethod);
510 void MarkGenericParameterProvider (IGenericParameterProvider provider)
512 if (!provider.HasGenericParameters)
515 foreach (GenericParameter parameter in provider.GenericParameters)
516 MarkGenericParameter (parameter);
519 void MarkGenericParameter (GenericParameter parameter)
521 MarkCustomAttributes (parameter);
522 foreach (TypeReference constraint in parameter.Constraints)
523 MarkType (constraint);
526 bool IsVirtualAndHasPreservedParent (MethodDefinition method)
528 if (!method.IsVirtual)
531 var base_list = Annotations.GetBaseMethods (method);
532 if (base_list == null)
535 foreach (MethodDefinition @base in base_list) {
536 if (IgnoreScope (@base.DeclaringType.Scope))
539 if (IsVirtualAndHasPreservedParent (@base))
546 static MethodPredicate IsSpecialSerializationConstructorPredicate = new MethodPredicate (IsSpecialSerializationConstructor);
548 static bool IsSpecialSerializationConstructor (MethodDefinition method)
550 if (!IsConstructor (method))
553 ParameterDefinitionCollection parameters = method.Parameters;
554 if (parameters.Count != 2)
557 return parameters [0].ParameterType.Name == "SerializationInfo" &&
558 parameters [1].ParameterType.Name == "StreamingContext";
561 delegate bool MethodPredicate (MethodDefinition method);
563 void MarkMethodsIf (ICollection methods, MethodPredicate predicate)
565 foreach (MethodDefinition method in methods)
566 if (predicate (method))
570 static MethodPredicate IsDefaultConstructorPredicate = new MethodPredicate (IsDefaultConstructor);
572 static bool IsDefaultConstructor (MethodDefinition method)
574 return IsConstructor (method) && method.Parameters.Count == 0;
577 static bool IsConstructor (MethodDefinition method)
579 return method.Name == MethodDefinition.Ctor && method.IsSpecialName &&
580 method.IsRuntimeSpecialName;
583 static MethodPredicate IsStaticConstructorPredicate = new MethodPredicate (IsStaticConstructor);
585 static bool IsStaticConstructor (MethodDefinition method)
587 return method.Name == MethodDefinition.Cctor && method.IsSpecialName &&
588 method.IsRuntimeSpecialName;
591 static bool IsSerializable (TypeDefinition td)
593 return (td.Attributes & TypeAttributes.Serializable) != 0;
596 static bool IsMulticastDelegate (TypeDefinition td)
598 return td.BaseType != null && td.BaseType.FullName == "System.MulticastDelegate";
601 TypeDefinition ResolveTypeDefinition (TypeReference type)
603 TypeDefinition td = type as TypeDefinition;
605 td = type.Resolve ();
610 protected TypeReference GetOriginalType (TypeReference type)
612 while (type is TypeSpecification) {
613 GenericInstanceType git = type as GenericInstanceType;
615 MarkGenericArguments (git);
617 ModType mod = type as ModType;
619 MarkModifierType (mod);
621 type = ((TypeSpecification) type).ElementType;
627 void MarkModifierType (ModType mod)
629 MarkType (mod.ModifierType);
632 void MarkGenericArguments (IGenericInstance instance)
634 foreach (TypeReference argument in instance.GenericArguments)
637 MarkGenericArgumentConstructors (instance);
640 void MarkGenericArgumentConstructors (IGenericInstance instance)
642 var arguments = instance.GenericArguments;
644 var generic_element = GetGenericProviderFromInstance (instance);
645 if (generic_element == null)
648 var parameters = generic_element.GenericParameters;
650 if (arguments.Count != parameters.Count)
653 for (int i = 0; i < arguments.Count; i++) {
654 var argument = arguments [i];
655 var parameter = parameters [i];
657 if (!parameter.HasDefaultConstructorConstraint)
660 var argument_definition = ResolveTypeDefinition (argument);
661 if (argument_definition == null)
664 MarkMethodsIf (argument_definition.Constructors, ctor => !ctor.IsStatic && !ctor.HasParameters);
668 IGenericParameterProvider GetGenericProviderFromInstance (IGenericInstance instance)
670 var method = instance as GenericInstanceMethod;
672 return method.ElementMethod;
674 var type = instance as GenericInstanceType;
676 return type.ElementType;
681 void ApplyPreserveInfo (TypeDefinition type)
683 ApplyPreserveMethods (type);
685 if (!Annotations.IsPreserved (type))
688 switch (Annotations.GetPreserve (type)) {
689 case TypePreserve.All:
693 case TypePreserve.Fields:
696 case TypePreserve.Methods:
702 void ApplyPreserveMethods (TypeDefinition type)
704 var list = Annotations.GetPreservedMethods (type);
708 foreach (MethodDefinition method in list)
712 void MarkFields (TypeDefinition type)
717 foreach (FieldDefinition field in type.Fields)
721 void MarkMethods (TypeDefinition type)
724 MarkMethodCollection (type.Methods);
725 if (type.HasConstructors)
726 MarkMethodCollection (type.Constructors);
729 void MarkMethodCollection (IEnumerable methods)
731 foreach (MethodDefinition method in methods)
735 void MarkMethod (MethodReference reference)
737 reference = GetOriginalMethod (reference);
739 if (reference.DeclaringType is ArrayType)
742 // if (IgnoreScope (reference.DeclaringType.Scope))
745 MethodDefinition method = ResolveMethodDefinition (reference);
748 throw new ResolutionException (reference);
750 if (Annotations.GetAction (method) == MethodAction.Nothing)
751 Annotations.SetAction (method, MethodAction.Parse);
753 EnqueueMethod (method);
756 AssemblyDefinition ResolveAssembly (IMetadataScope scope)
758 AssemblyDefinition assembly = _context.Resolve (scope);
759 MarkAssembly (assembly);
763 MethodReference GetOriginalMethod (MethodReference method)
765 while (method is MethodSpecification) {
766 GenericInstanceMethod gim = method as GenericInstanceMethod;
768 MarkGenericArguments (gim);
770 method = ((MethodSpecification) method).ElementMethod;
776 MethodDefinition ResolveMethodDefinition (MethodReference method)
778 MethodDefinition md = method as MethodDefinition;
780 md = method.Resolve ();
785 void ProcessMethod (MethodDefinition method)
787 if (CheckProcessed (method))
790 MarkType (method.DeclaringType);
791 MarkCustomAttributes (method);
793 MarkGenericParameterProvider (method);
795 if (IsPropertyMethod (method))
796 MarkProperty (GetProperty (method));
797 else if (IsEventMethod (method))
798 MarkEvent (GetEvent (method));
800 if (method.HasParameters) {
801 foreach (ParameterDefinition pd in method.Parameters) {
802 MarkType (pd.ParameterType);
803 MarkCustomAttributes (pd);
804 MarkMarshalSpec (pd);
808 if (method.HasOverrides) {
809 foreach (MethodReference ov in method.Overrides)
813 MarkMethodSpecialCustomAttributes (method);
815 if (method.IsVirtual)
816 _virtual_methods.Add (method);
818 MarkBaseMethods (method);
820 MarkType (method.ReturnType.ReturnType);
821 MarkCustomAttributes (method.ReturnType);
822 MarkMarshalSpec (method.ReturnType);
824 if (ShouldParseMethodBody (method))
825 MarkMethodBody (method.Body);
827 Annotations.Mark (method);
830 void MarkBaseMethods (MethodDefinition method)
832 IList base_methods = Annotations.GetBaseMethods (method);
833 if (base_methods == null)
836 foreach (MethodDefinition base_method in base_methods) {
837 MarkMethod (base_method);
838 MarkBaseMethods (base_method);
842 bool ShouldParseMethodBody (MethodDefinition method)
847 AssemblyDefinition assembly = ResolveAssembly (method.DeclaringType.Scope);
848 return (Annotations.GetAction (method) == MethodAction.ForceParse ||
849 (Annotations.GetAction (assembly) == AssemblyAction.Link && Annotations.GetAction (method) == MethodAction.Parse));
852 static bool IsPropertyMethod (MethodDefinition md)
854 return (md.SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0 ||
855 (md.SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0;
858 static bool IsEventMethod (MethodDefinition md)
860 return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 ||
861 (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 ||
862 (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
865 static PropertyDefinition GetProperty (MethodDefinition md)
867 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
868 foreach (PropertyDefinition prop in declaringType.Properties)
869 if (prop.GetMethod == md || prop.SetMethod == md)
875 static EventDefinition GetEvent (MethodDefinition md)
877 TypeDefinition declaringType = (TypeDefinition) md.DeclaringType;
878 foreach (EventDefinition evt in declaringType.Events)
879 if (evt.AddMethod == md || evt.InvokeMethod == md || evt.RemoveMethod == md)
885 void MarkProperty (PropertyDefinition prop)
887 MarkCustomAttributes (prop);
890 void MarkEvent (EventDefinition evt)
892 MarkCustomAttributes (evt);
893 MarkMethodIfNotNull (evt.AddMethod);
894 MarkMethodIfNotNull (evt.InvokeMethod);
895 MarkMethodIfNotNull (evt.RemoveMethod);
898 void MarkMethodIfNotNull (MethodReference method)
906 void MarkInstruction (Instruction instruction)
908 switch (instruction.OpCode.OperandType) {
909 case OperandType.InlineField:
910 MarkField ((FieldReference) instruction.Operand);
912 case OperandType.InlineMethod:
913 MarkMethod ((MethodReference) instruction.Operand);
915 case OperandType.InlineTok:
916 object token = instruction.Operand;
917 if (token is TypeReference)
918 MarkType ((TypeReference) token);
919 else if (token is MethodReference)
920 MarkMethod ((MethodReference) token);
922 MarkField ((FieldReference) token);
924 case OperandType.InlineType:
925 MarkType ((TypeReference) instruction.Operand);