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
);