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
{
44 _queue
= new Queue ();
47 public void Process (LinkContext context
)
57 foreach (AssemblyDefinition assembly
in _context
.GetAssemblies ())
58 InitializeAssembly (assembly
);
61 void InitializeAssembly (AssemblyDefinition assembly
)
63 MarkAssembly (assembly
);
64 foreach (TypeDefinition type
in assembly
.MainModule
.Types
) {
65 if (!Annotations
.IsMarked (type
))
68 InitializeType (type
);
72 void InitializeType (TypeDefinition type
)
77 InitializeFields (type
);
79 InitializeMethods (type
.Methods
);
80 if (type
.HasConstructors
)
81 InitializeMethods (type
.Constructors
);
84 void InitializeFields (TypeDefinition type
)
86 foreach (FieldDefinition field
in type
.Fields
)
87 if (Annotations
.IsMarked (field
))
91 void InitializeMethods (ICollection methods
)
93 foreach (MethodDefinition method
in methods
)
94 if (Annotations
.IsMarked (method
))
95 _queue
.Enqueue (method
);
101 throw new InvalidOperationException ("No entry methods");
103 while (!QueueIsEmpty ()) {
104 MethodDefinition method
= (MethodDefinition
) _queue
.Dequeue ();
105 ProcessMethod (method
);
111 return _queue
.Count
== 0;
114 void MarkMethodBody (MethodBody body
)
116 foreach (VariableDefinition
var in body
.Variables
)
117 MarkType (var.VariableType
);
119 foreach (ExceptionHandler eh
in body
.ExceptionHandlers
)
120 if (eh
.Type
== ExceptionHandlerType
.Catch
)
121 MarkType (eh
.CatchType
);
123 foreach (Instruction instruction
in body
.Instructions
)
124 MarkInstruction (instruction
);
127 void MarkMarshalSpec (IHasMarshalSpec spec
)
129 CustomMarshalerSpec marshaler
= spec
.MarshalSpec
as CustomMarshalerSpec
;
130 if (marshaler
== null)
133 TypeDefinition type
= _context
.GetType (marshaler
.ManagedType
);
137 void MarkCustomAttributes (ICustomAttributeProvider provider
)
139 if (!provider
.HasCustomAttributes
)
142 foreach (CustomAttribute ca
in provider
.CustomAttributes
)
143 MarkCustomAttribute (ca
);
146 void MarkCustomAttribute (CustomAttribute ca
)
148 MarkMethod (ca
.Constructor
);
158 MarkCustomAttributeParameters (ca
);
160 TypeDefinition type
= ca
.Constructor
.DeclaringType
.Resolve ();
162 MarkCustomAttributeProperties (ca
, type
);
163 MarkCustomAttributeFields (ca
, type
);
166 void MarkCustomAttributeProperties (CustomAttribute ca
, TypeDefinition attribute
)
168 foreach (DictionaryEntry de
in ca
.Properties
) {
169 string propertyname
= (string) de
.Key
;
171 PropertyDefinition
[] properties
= attribute
.Properties
.GetProperties (propertyname
);
173 if (properties
!= null && properties
.Length
!= 0 && properties
[0].SetMethod
!= null)
174 MarkMethod (properties
[0].SetMethod
);
176 TypeReference propType
= ca
.GetPropertyType (propertyname
);
177 MarkIfType (propType
, de
.Value
);
181 void MarkCustomAttributeFields (CustomAttribute ca
, TypeDefinition attribute
)
183 foreach (DictionaryEntry de
in ca
.Fields
) {
184 string fieldname
= (string) de
.Key
;
186 FieldDefinition field
= attribute
.Fields
.GetField (fieldname
);
190 TypeReference fieldType
= ca
.GetFieldType (fieldname
);
191 MarkIfType (fieldType
, de
.Value
);
195 void MarkCustomAttributeParameters (CustomAttribute ca
)
197 for (int i
= 0; i
< ca
.Constructor
.Parameters
.Count
; i
++) {
198 ParameterDefinition param
= ca
.Constructor
.Parameters
[i
];
199 MarkIfType (param
.ParameterType
, ca
.ConstructorParameters
[i
]);
203 void MarkIfType (TypeReference slotType
, object value)
205 if (slotType
.FullName
!= Constants
.Type
)
208 TypeDefinition type
= _context
.GetType ((string) value);
213 static bool CheckProcessed (IAnnotationProvider provider
)
215 if (Annotations
.IsProcessed (provider
))
218 Annotations
.Processed (provider
);
222 void MarkAssembly (AssemblyDefinition assembly
)
224 if (CheckProcessed (assembly
))
227 MarkCustomAttributes (assembly
);
229 foreach (ModuleDefinition module
in assembly
.Modules
)
230 MarkCustomAttributes (module
);
233 void MarkField (FieldReference reference
)
235 if (IgnoreScope (reference
.DeclaringType
.Scope
))
238 FieldDefinition field
= ResolveFieldDefinition (reference
);
241 throw new ResolutionException (reference
);
243 if (CheckProcessed (field
))
246 MarkType (field
.DeclaringType
);
247 MarkType (field
.FieldType
);
248 MarkCustomAttributes (field
);
249 MarkMarshalSpec (field
);
251 Annotations
.Mark (field
);
254 bool IgnoreScope (IMetadataScope scope
)
256 AssemblyDefinition assembly
= ResolveAssembly (scope
);
257 return Annotations
.GetAction (assembly
) != AssemblyAction
.Link
;
260 FieldDefinition
ResolveFieldDefinition (FieldReference field
)
262 FieldDefinition fd
= field
as FieldDefinition
;
264 fd
= field
.Resolve ();
269 void MarkType (TypeReference reference
)
271 if (reference
== null)
274 reference
= GetOriginalType (reference
);
276 if (reference
is GenericParameter
)
279 if (IgnoreScope (reference
.Scope
))
282 TypeDefinition type
= ResolveTypeDefinition (reference
);
285 throw new ResolutionException (reference
);
287 if (CheckProcessed (type
))
290 MarkType (type
.BaseType
);
291 MarkType (type
.DeclaringType
);
292 MarkCustomAttributes(type
);
294 if (IsMulticastDelegate (type
))
295 MarkMethodCollection (type
.Constructors
);
297 if (IsSerializable (type
) && type
.HasConstructors
) {
298 MarkMethodsIf (type
.Constructors
, IsDefaultConstructorPredicate
);
299 MarkMethodsIf (type
.Constructors
, IsSpecialSerializationConstructorPredicate
);
302 MarkGenericParameterProvider (type
);
304 if (type
.IsValueType
)
307 if (type
.HasInterfaces
) {
308 foreach (TypeReference iface
in type
.Interfaces
)
312 if (type
.HasConstructors
)
313 MarkMethodsIf (type
.Constructors
, IsStaticConstructorPredicate
);
316 MarkMethodsIf (type
.Methods
, IsVirtualPredicate
);
318 Annotations
.Mark (type
);
320 ApplyPreserveInfo (type
);
323 void MarkGenericParameterProvider (IGenericParameterProvider provider
)
325 if (!provider
.HasGenericParameters
)
328 foreach (GenericParameter parameter
in provider
.GenericParameters
)
329 MarkGenericParameter (parameter
);
332 void MarkGenericParameter (GenericParameter parameter
)
334 MarkCustomAttributes (parameter
);
335 foreach (TypeReference constraint
in parameter
.Constraints
)
336 MarkType (constraint
);
339 static MethodPredicate IsSpecialSerializationConstructorPredicate
= new MethodPredicate (IsSpecialSerializationConstructor
);
341 static bool IsSpecialSerializationConstructor (MethodDefinition method
)
343 if (!IsConstructor (method
))
346 ParameterDefinitionCollection parameters
= method
.Parameters
;
347 if (parameters
.Count
!= 2)
350 return parameters
[0].ParameterType
.Name
== "SerializationInfo" &&
351 parameters
[1].ParameterType
.Name
== "StreamingContext";
354 delegate bool MethodPredicate (MethodDefinition method
);
356 void MarkMethodsIf (ICollection methods
, MethodPredicate predicate
)
358 foreach (MethodDefinition method
in methods
)
359 if (predicate (method
))
363 static MethodPredicate IsDefaultConstructorPredicate
= new MethodPredicate (IsDefaultConstructor
);
365 static bool IsDefaultConstructor (MethodDefinition method
)
367 return IsConstructor (method
) && method
.Parameters
.Count
== 0;
370 static bool IsConstructor (MethodDefinition method
)
372 return method
.Name
== MethodDefinition
.Ctor
&& method
.IsSpecialName
&&
373 method
.IsRuntimeSpecialName
;
376 static MethodPredicate IsVirtualPredicate
= new MethodPredicate (IsVirtual
);
378 static bool IsVirtual (MethodDefinition method
)
380 return method
.IsVirtual
;
383 static MethodPredicate IsStaticConstructorPredicate
= new MethodPredicate (IsStaticConstructor
);
385 static bool IsStaticConstructor (MethodDefinition method
)
387 return method
.Name
== MethodDefinition
.Cctor
&& method
.IsSpecialName
&&
388 method
.IsRuntimeSpecialName
;
391 static bool IsSerializable (TypeDefinition td
)
393 return (td
.Attributes
& TypeAttributes
.Serializable
) != 0;
396 static bool IsMulticastDelegate (TypeDefinition td
)
398 return td
.BaseType
!= null && td
.BaseType
.FullName
== "System.MulticastDelegate";
401 TypeDefinition
ResolveTypeDefinition (TypeReference type
)
403 TypeDefinition td
= type
as TypeDefinition
;
405 td
= type
.Resolve ();
410 TypeReference
GetOriginalType (TypeReference type
)
412 while (type
is TypeSpecification
) {
413 GenericInstanceType git
= type
as GenericInstanceType
;
415 MarkGenericArguments (git
);
417 ModType mod
= type
as ModType
;
419 MarkModifierType (mod
);
421 type
= ((TypeSpecification
) type
).ElementType
;
427 void MarkModifierType (ModType mod
)
429 MarkType (mod
.ModifierType
);
432 void MarkGenericArguments (IGenericInstance instance
)
434 foreach (TypeReference argument
in instance
.GenericArguments
)
438 void ApplyPreserveInfo (TypeDefinition type
)
440 if (!Annotations
.IsPreserved (type
))
443 switch (Annotations
.GetPreserve (type
)) {
444 case TypePreserve
.All
:
448 case TypePreserve
.Fields
:
451 case TypePreserve
.Methods
:
457 void MarkFields (TypeDefinition type
)
462 foreach (FieldDefinition field
in type
.Fields
)
466 void MarkMethods (TypeDefinition type
)
469 MarkMethodCollection (type
.Methods
);
470 if (type
.HasConstructors
)
471 MarkMethodCollection (type
.Constructors
);
474 void MarkMethodCollection (IEnumerable methods
)
476 foreach (MethodDefinition method
in methods
)
480 void MarkMethod (MethodReference reference
)
482 reference
= GetOriginalMethod (reference
);
484 if (reference
.DeclaringType
is ArrayType
)
487 if (IgnoreScope (reference
.DeclaringType
.Scope
))
490 MethodDefinition method
= ResolveMethodDefinition (reference
);
493 throw new ResolutionException (reference
);
495 Annotations
.SetAction (method
, MethodAction
.Parse
);
497 _queue
.Enqueue (method
);
500 AssemblyDefinition
ResolveAssembly (IMetadataScope scope
)
502 AssemblyDefinition assembly
= _context
.Resolve (scope
);
503 MarkAssembly (assembly
);
507 MethodReference
GetOriginalMethod (MethodReference method
)
509 while (method
is MethodSpecification
) {
510 GenericInstanceMethod gim
= method
as GenericInstanceMethod
;
512 MarkGenericArguments (gim
);
514 method
= ((MethodSpecification
) method
).ElementMethod
;
520 MethodDefinition
ResolveMethodDefinition (MethodReference method
)
522 MethodDefinition md
= method
as MethodDefinition
;
524 md
= method
.Resolve ();
529 void ProcessMethod (MethodDefinition method
)
531 if (CheckProcessed (method
))
534 MarkType (method
.DeclaringType
);
535 MarkCustomAttributes (method
);
537 MarkGenericParameterProvider (method
);
539 if (IsPropertyMethod (method
))
540 MarkProperty (GetProperty (method
));
541 else if (IsEventMethod (method
))
542 MarkEvent (GetEvent (method
));
544 if (method
.HasParameters
) {
545 foreach (ParameterDefinition pd
in method
.Parameters
) {
546 MarkType (pd
.ParameterType
);
547 MarkCustomAttributes (pd
);
548 MarkMarshalSpec (pd
);
552 if (method
.HasOverrides
) {
553 foreach (MethodReference ov
in method
.Overrides
)
557 MarkType (method
.ReturnType
.ReturnType
);
558 MarkCustomAttributes (method
.ReturnType
);
559 MarkMarshalSpec (method
.ReturnType
);
561 if (ShouldParseMethodBody (method
))
562 MarkMethodBody (method
.Body
);
564 Annotations
.Mark (method
);
567 bool ShouldParseMethodBody (MethodDefinition method
)
572 AssemblyDefinition assembly
= ResolveAssembly (method
.DeclaringType
.Scope
);
573 return (Annotations
.GetAction (method
) == MethodAction
.ForceParse
||
574 (Annotations
.GetAction (assembly
) == AssemblyAction
.Link
&& Annotations
.GetAction (method
) == MethodAction
.Parse
));
577 static bool IsPropertyMethod (MethodDefinition md
)
579 return (md
.SemanticsAttributes
& MethodSemanticsAttributes
.Getter
) != 0 ||
580 (md
.SemanticsAttributes
& MethodSemanticsAttributes
.Setter
) != 0;
583 static bool IsEventMethod (MethodDefinition md
)
585 return (md
.SemanticsAttributes
& MethodSemanticsAttributes
.AddOn
) != 0 ||
586 (md
.SemanticsAttributes
& MethodSemanticsAttributes
.Fire
) != 0 ||
587 (md
.SemanticsAttributes
& MethodSemanticsAttributes
.RemoveOn
) != 0;
590 static PropertyDefinition
GetProperty (MethodDefinition md
)
592 TypeDefinition declaringType
= (TypeDefinition
) md
.DeclaringType
;
593 foreach (PropertyDefinition prop
in declaringType
.Properties
)
594 if (prop
.GetMethod
== md
|| prop
.SetMethod
== md
)
600 static EventDefinition
GetEvent (MethodDefinition md
)
602 TypeDefinition declaringType
= (TypeDefinition
) md
.DeclaringType
;
603 foreach (EventDefinition evt
in declaringType
.Events
)
604 if (evt
.AddMethod
== md
|| evt
.InvokeMethod
== md
|| evt
.RemoveMethod
== md
)
610 void MarkProperty (PropertyDefinition prop
)
612 MarkCustomAttributes (prop
);
615 void MarkEvent (EventDefinition evt
)
617 MarkCustomAttributes (evt
);
618 MarkMethodIfNotNull (evt
.AddMethod
);
619 MarkMethodIfNotNull (evt
.InvokeMethod
);
620 MarkMethodIfNotNull (evt
.RemoveMethod
);
623 void MarkMethodIfNotNull (MethodReference method
)
631 void MarkInstruction (Instruction instruction
)
633 switch (instruction
.OpCode
.OperandType
) {
634 case OperandType
.InlineField
:
635 MarkField ((FieldReference
) instruction
.Operand
);
637 case OperandType
.InlineMethod
:
638 MarkMethod ((MethodReference
) instruction
.Operand
);
640 case OperandType
.InlineTok
:
641 object token
= instruction
.Operand
;
642 if (token
is TypeReference
)
643 MarkType ((TypeReference
) token
);
644 else if (token
is MethodReference
)
645 MarkMethod ((MethodReference
) token
);
647 MarkField ((FieldReference
) token
);
649 case OperandType
.InlineType
:
650 MarkType ((TypeReference
) instruction
.Operand
);