3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // System.Reflection.Emit/ModuleBuilder.cs
29 // Paolo Molaro (lupus@ximian.com)
31 // (C) 2001 Ximian, Inc. http://www.ximian.com
35 using System
.Reflection
;
36 using System
.Collections
;
37 using System
.Runtime
.CompilerServices
;
38 using System
.Runtime
.InteropServices
;
39 using System
.Diagnostics
.SymbolStore
;
41 using System
.Resources
;
42 using System
.Globalization
;
44 namespace System
.Reflection
.Emit
{
45 public class ModuleBuilder
: Module
{
46 #region Sync with reflection.h
47 private IntPtr dynamic_image
;
48 private int num_types
;
49 private TypeBuilder
[] types
;
50 private CustomAttributeBuilder
[] cattrs
;
52 private int table_idx
;
53 internal AssemblyBuilder assemblyb
;
54 private MethodBuilder
[] global_methods
;
55 private FieldBuilder
[] global_fields
;
57 private MonoResource
[] resources
;
59 private TypeBuilder global_type
;
60 private Type global_type_created
;
62 Hashtable us_string_cache
= new Hashtable ();
63 private int[] table_indexes
;
65 ModuleBuilderTokenGenerator token_gen
;
66 ArrayList resource_writers
= null;
68 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
69 private static extern void basic_init (ModuleBuilder ab
);
71 internal ModuleBuilder (AssemblyBuilder assb
, string name
, string fullyqname
, bool emitSymbolInfo
, bool transient
) {
72 this.name
= this.scopename
= name
;
73 this.fqname
= fullyqname
;
74 this.assembly
= this.assemblyb
= assb
;
75 this.transient
= transient
;
76 // to keep mcs fast we do not want CryptoConfig wo be involved to create the RNG
77 guid
= Guid
.FastNewGuidArray ();
78 // guid = Guid.NewGuid().ToByteArray ();
79 table_idx
= get_next_table_index (this, 0x00, true);
80 name_cache
= new Hashtable ();
87 public override string FullyQualifiedName {get { return fqname;}}
89 public bool IsTransient () {
93 public void CreateGlobalFunctions ()
95 if (global_type_created
!= null)
96 throw new InvalidOperationException ("global methods already created");
97 if (global_type
!= null)
98 global_type_created
= global_type
.CreateType ();
101 public FieldBuilder
DefineInitializedData( string name
, byte[] data
, FieldAttributes attributes
) {
103 throw new ArgumentNullException ("data");
105 FieldBuilder fb
= DefineUninitializedData (name
, data
.Length
,
106 attributes
| FieldAttributes
.HasFieldRVA
);
107 fb
.SetRVAData (data
);
112 public FieldBuilder
DefineUninitializedData( string name
, int size
, FieldAttributes attributes
) {
114 throw new ArgumentNullException ("name");
115 if (global_type_created
!= null)
116 throw new InvalidOperationException ("global fields already created");
117 if (global_type
== null)
118 global_type
= new TypeBuilder (this, 0);
120 string typeName
= "$ArrayType$" + size
;
121 Type datablobtype
= GetType (typeName
, false, false);
122 if (datablobtype
== null) {
123 TypeBuilder tb
= DefineType (typeName
,
124 TypeAttributes
.Public
|TypeAttributes
.ExplicitLayout
|TypeAttributes
.Sealed
,
125 assemblyb
.corlib_value_type
, null, PackingSize
.Size1
, size
);
129 FieldBuilder fb
= global_type
.DefineField (name
, datablobtype
, attributes
|FieldAttributes
.Static
);
131 if (global_fields
!= null) {
132 FieldBuilder
[] new_fields
= new FieldBuilder
[global_fields
.Length
+1];
133 System
.Array
.Copy (global_fields
, new_fields
, global_fields
.Length
);
134 new_fields
[global_fields
.Length
] = fb
;
135 global_fields
= new_fields
;
137 global_fields
= new FieldBuilder
[1];
138 global_fields
[0] = fb
;
143 private void addGlobalMethod (MethodBuilder mb
) {
144 if (global_methods
!= null) {
145 MethodBuilder
[] new_methods
= new MethodBuilder
[global_methods
.Length
+1];
146 System
.Array
.Copy (global_methods
, new_methods
, global_methods
.Length
);
147 new_methods
[global_methods
.Length
] = mb
;
148 global_methods
= new_methods
;
150 global_methods
= new MethodBuilder
[1];
151 global_methods
[0] = mb
;
155 public MethodBuilder
DefineGlobalMethod (string name
, MethodAttributes attributes
, Type returnType
, Type
[] parameterTypes
)
157 return DefineGlobalMethod (name
, attributes
, CallingConventions
.Standard
, returnType
, parameterTypes
);
160 public MethodBuilder
DefineGlobalMethod (string name
, MethodAttributes attributes
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
) {
161 return DefineGlobalMethod (name
, attributes
, callingConvention
, returnType
, null, null, parameterTypes
, null, null);
164 #if NET_2_0 || BOOTSTRAP_NET_2_0
169 MethodBuilder
DefineGlobalMethod (string name
, MethodAttributes attributes
, CallingConventions callingConvention
, Type returnType
, Type
[] requiredReturnTypeCustomModifiers
, Type
[] optionalReturnTypeCustomModifiers
, Type
[] parameterTypes
, Type
[][] requiredParameterTypeCustomModifiers
, Type
[][] optionalParameterTypeCustomModifiers
)
172 throw new ArgumentNullException ("name");
173 if ((attributes
& MethodAttributes
.Static
) == 0)
174 throw new ArgumentException ("global methods must be static");
175 if (global_type_created
!= null)
176 throw new InvalidOperationException ("global methods already created");
177 if (global_type
== null)
178 global_type
= new TypeBuilder (this, 0);
179 MethodBuilder mb
= global_type
.DefineMethod (name
, attributes
, callingConvention
, returnType
, requiredReturnTypeCustomModifiers
, optionalReturnTypeCustomModifiers
, parameterTypes
, requiredParameterTypeCustomModifiers
, optionalParameterTypeCustomModifiers
);
181 addGlobalMethod (mb
);
185 public MethodBuilder
DefinePInvokeMethod (string name
, string dllName
, MethodAttributes attributes
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
, CallingConvention nativeCallConv
, CharSet nativeCharSet
) {
186 return DefinePInvokeMethod (name
, dllName
, name
, attributes
, callingConvention
, returnType
, parameterTypes
, nativeCallConv
, nativeCharSet
);
189 public MethodBuilder
DefinePInvokeMethod (string name
, string dllName
, string entryName
, MethodAttributes attributes
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
, CallingConvention nativeCallConv
, CharSet nativeCharSet
) {
191 throw new ArgumentNullException ("name");
192 if ((attributes
& MethodAttributes
.Static
) == 0)
193 throw new ArgumentException ("global methods must be static");
194 if (global_type_created
!= null)
195 throw new InvalidOperationException ("global methods already created");
196 if (global_type
== null)
197 global_type
= new TypeBuilder (this, 0);
198 MethodBuilder mb
= global_type
.DefinePInvokeMethod (name
, dllName
, entryName
, attributes
, callingConvention
, returnType
, parameterTypes
, nativeCallConv
, nativeCharSet
);
200 addGlobalMethod (mb
);
204 public TypeBuilder
DefineType (string name
) {
205 return DefineType (name
, 0);
208 public TypeBuilder
DefineType (string name
, TypeAttributes attr
) {
209 return DefineType (name
, attr
, typeof(object), null);
212 public TypeBuilder
DefineType (string name
, TypeAttributes attr
, Type parent
) {
213 return DefineType (name
, attr
, parent
, null);
216 private TypeBuilder
DefineType (string name
, TypeAttributes attr
, Type parent
, Type
[] interfaces
, PackingSize packsize
, int typesize
) {
217 if (name_cache
.Contains (name
))
218 throw new ArgumentException ("Duplicate type name within an assembly.");
220 TypeBuilder res
= new TypeBuilder (this, name
, attr
, parent
, interfaces
, packsize
, typesize
, null);
222 if (types
.Length
== num_types
) {
223 TypeBuilder
[] new_types
= new TypeBuilder
[types
.Length
* 2];
224 System
.Array
.Copy (types
, new_types
, num_types
);
228 types
= new TypeBuilder
[1];
230 types
[num_types
] = res
;
232 name_cache
.Add (name
, res
);
236 internal void RegisterTypeName (TypeBuilder tb
, string name
) {
237 name_cache
.Add (name
, tb
);
240 public TypeBuilder
DefineType (string name
, TypeAttributes attr
, Type parent
, Type
[] interfaces
) {
241 return DefineType (name
, attr
, parent
, interfaces
, PackingSize
.Unspecified
, TypeBuilder
.UnspecifiedTypeSize
);
244 public TypeBuilder
DefineType (string name
, TypeAttributes attr
, Type parent
, int typesize
) {
245 return DefineType (name
, attr
, parent
, null, PackingSize
.Unspecified
, TypeBuilder
.UnspecifiedTypeSize
);
248 public TypeBuilder
DefineType (string name
, TypeAttributes attr
, Type parent
, PackingSize packsize
) {
249 return DefineType (name
, attr
, parent
, null, packsize
, TypeBuilder
.UnspecifiedTypeSize
);
252 public TypeBuilder
DefineType (string name
, TypeAttributes attr
, Type parent
, PackingSize packsize
, int typesize
) {
253 return DefineType (name
, attr
, parent
, null, packsize
, typesize
);
256 public MethodInfo
GetArrayMethod( Type arrayClass
, string methodName
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
) {
257 return new MonoArrayMethod (arrayClass
, methodName
, callingConvention
, returnType
, parameterTypes
);
260 public EnumBuilder
DefineEnum( string name
, TypeAttributes visibility
, Type underlyingType
) {
261 EnumBuilder eb
= new EnumBuilder (this, name
, visibility
, underlyingType
);
265 public override Type
GetType( string className
) {
266 return GetType (className
, false, false);
269 public override Type
GetType( string className
, bool ignoreCase
) {
270 return GetType (className
, false, ignoreCase
);
273 private TypeBuilder
search_in_array (TypeBuilder
[] arr
, int validElementsInArray
, string className
) {
275 for (i
= 0; i
< validElementsInArray
; ++i
) {
276 if (String
.Compare (className
, arr
[i
].FullName
, true, CultureInfo
.InvariantCulture
) == 0) {
283 private TypeBuilder
search_nested_in_array (TypeBuilder
[] arr
, int validElementsInArray
, string className
) {
285 for (i
= 0; i
< validElementsInArray
; ++i
) {
286 if (String
.Compare (className
, arr
[i
].Name
, true, CultureInfo
.InvariantCulture
) == 0)
292 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
293 private static extern Type
create_modified_type (TypeBuilder tb
, string modifiers
);
295 static readonly char [] type_modifiers
= {'&', '[', '*'}
;
297 private TypeBuilder
GetMaybeNested (TypeBuilder t
, string className
) {
301 subt
= className
.IndexOf ('+');
303 if (t
.subtypes
!= null)
304 return search_nested_in_array (t
.subtypes
, t
.subtypes
.Length
, className
);
307 if (t
.subtypes
!= null) {
308 pname
= className
.Substring (0, subt
);
309 rname
= className
.Substring (subt
+ 1);
310 TypeBuilder result
= search_nested_in_array (t
.subtypes
, t
.subtypes
.Length
, pname
);
312 return GetMaybeNested (result
, rname
);
317 public override Type
GetType (string className
, bool throwOnError
, bool ignoreCase
) {
319 string orig
= className
;
321 TypeBuilder result
= null;
323 if (types
== null && throwOnError
)
324 throw new TypeLoadException (className
);
326 subt
= className
.IndexOfAny (type_modifiers
);
328 modifiers
= className
.Substring (subt
);
329 className
= className
.Substring (0, subt
);
334 result
= name_cache
[className
] as TypeBuilder
;
336 subt
= className
.IndexOf ('+');
339 result
= search_in_array (types
, num_types
, className
);
342 pname
= className
.Substring (0, subt
);
343 rname
= className
.Substring (subt
+ 1);
344 result
= search_in_array (types
, num_types
, pname
);
346 result
= GetMaybeNested (result
, rname
);
349 if ((result
== null) && throwOnError
)
350 throw new TypeLoadException (orig
);
351 if (result
!= null && (modifiers
!= null))
352 return create_modified_type (result
, modifiers
);
356 internal int get_next_table_index (object obj
, int table
, bool inc
) {
357 if (table_indexes
== null) {
358 table_indexes
= new int [64];
359 for (int i
=0; i
< 64; ++i
)
360 table_indexes
[i
] = 1;
361 /* allow room for .<Module> in TypeDef table */
362 table_indexes
[0x02] = 2;
364 // Console.WriteLine ("getindex for table "+table.ToString()+" got "+table_indexes [table].ToString());
366 return table_indexes
[table
]++;
367 return table_indexes
[table
];
370 public void SetCustomAttribute( CustomAttributeBuilder customBuilder
) {
371 if (cattrs
!= null) {
372 CustomAttributeBuilder
[] new_array
= new CustomAttributeBuilder
[cattrs
.Length
+ 1];
373 cattrs
.CopyTo (new_array
, 0);
374 new_array
[cattrs
.Length
] = customBuilder
;
377 cattrs
= new CustomAttributeBuilder
[1];
378 cattrs
[0] = customBuilder
;
381 public void SetCustomAttribute( ConstructorInfo con
, byte[] binaryAttribute
) {
382 SetCustomAttribute (new CustomAttributeBuilder (con
, binaryAttribute
));
385 public ISymbolWriter
GetSymWriter () {
389 public ISymbolDocumentWriter
DefineDocument (string url
, Guid language
, Guid languageVendor
, Guid documentType
) {
393 public override Type
[] GetTypes ()
396 return new TypeBuilder
[0];
399 TypeBuilder
[] copy
= new TypeBuilder
[n
];
400 Array
.Copy (types
, copy
, n
);
405 public IResourceWriter
DefineResource (string name
, string description
, ResourceAttributes attribute
)
408 throw new ArgumentNullException ("name");
409 if (name
== String
.Empty
)
410 throw new ArgumentException ("name cannot be empty");
412 throw new InvalidOperationException ("The module is transient");
413 if (!assemblyb
.IsSave
)
414 throw new InvalidOperationException ("The assembly is transient");
415 ResourceWriter writer
= new ResourceWriter (new MemoryStream ());
416 if (resource_writers
== null)
417 resource_writers
= new ArrayList ();
418 resource_writers
.Add (writer
);
420 // The data is filled out later
421 if (resources
!= null) {
422 MonoResource
[] new_r
= new MonoResource
[resources
.Length
+ 1];
423 System
.Array
.Copy(resources
, new_r
, resources
.Length
);
426 resources
= new MonoResource
[1];
428 int p
= resources
.Length
- 1;
429 resources
[p
].name
= name
;
430 resources
[p
].attrs
= attribute
;
435 public IResourceWriter
DefineResource (string name
, string description
)
437 return DefineResource (name
, description
, ResourceAttributes
.Public
);
441 public void DefineUnmanagedResource (byte[] resource
)
443 if (resource
== null)
444 throw new ArgumentNullException ("resource");
446 throw new NotImplementedException ();
450 public void DefineUnmanagedResource (string resourceFileName
)
452 if (resourceFileName
== null)
453 throw new ArgumentNullException ("resourceFileName");
454 if (resourceFileName
== String
.Empty
)
455 throw new ArgumentException ("resourceFileName");
456 if (!File
.Exists (resourceFileName
) || Directory
.Exists (resourceFileName
))
457 throw new FileNotFoundException ("File '" + resourceFileName
+ "' does not exists or is a directory.");
459 throw new NotImplementedException ();
463 public void SetSymCustomAttribute (string name
, byte[] data
)
465 throw new NotImplementedException ();
469 public void SetUserEntryPoint (MethodInfo entryPoint
)
471 if (entryPoint
== null)
472 throw new ArgumentNullException ("entryPoint");
473 if (entryPoint
.DeclaringType
.Module
!= this)
474 throw new InvalidOperationException ("entryPoint is not contained in this module");
475 throw new NotImplementedException ();
478 public MethodToken
GetMethodToken (MethodInfo method
)
481 throw new ArgumentNullException ("method");
482 if (method
.DeclaringType
.Module
!= this)
483 throw new InvalidOperationException ("The method is not in this module");
484 return new MethodToken (GetToken (method
));
487 public MethodToken
GetArrayMethodToken (Type arrayClass
, string methodName
, CallingConventions callingConvention
, Type returnType
, Type
[] parameterTypes
)
489 return GetMethodToken (GetArrayMethod (arrayClass
, methodName
, callingConvention
, returnType
, parameterTypes
));
493 public MethodToken
GetConstructorToken (ConstructorInfo con
)
496 throw new ArgumentNullException ("con");
497 return new MethodToken (GetToken (con
));
500 public FieldToken
GetFieldToken (FieldInfo field
)
503 throw new ArgumentNullException ("field");
504 if (field
.DeclaringType
.Module
!= this)
505 throw new InvalidOperationException ("The method is not in this module");
506 return new FieldToken (GetToken (field
));
510 public SignatureToken
GetSignatureToken (byte[] sigBytes
, int sigLength
)
512 throw new NotImplementedException ();
515 public SignatureToken
GetSignatureToken (SignatureHelper sigHelper
)
517 if (sigHelper
== null)
518 throw new ArgumentNullException ("sigHelper");
519 return new SignatureToken (GetToken (sigHelper
));
522 public StringToken
GetStringConstant (string str
)
525 throw new ArgumentNullException ("str");
526 return new StringToken (GetToken (str
));
529 public TypeToken
GetTypeToken (Type type
)
532 throw new ArgumentNullException ("type");
534 throw new ArgumentException ("type can't be a byref type", "type");
535 if (!IsTransient () && (type
.Module
is ModuleBuilder
) && ((ModuleBuilder
)type
.Module
).IsTransient ())
536 throw new InvalidOperationException ("a non-transient module can't reference a transient module");
537 return new TypeToken (GetToken (type
));
540 public TypeToken
GetTypeToken (string type
)
542 return GetTypeToken (GetType (name
));
545 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
546 private static extern int getUSIndex (ModuleBuilder mb
, string str
);
548 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
549 private static extern int getToken (ModuleBuilder mb
, object obj
);
551 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
552 private static extern int getMethodToken (ModuleBuilder mb
, MethodInfo method
,
553 Type
[] opt_param_types
);
555 internal int GetToken (string str
) {
556 if (us_string_cache
.Contains (str
))
557 return (int)us_string_cache
[str
];
558 int result
= getUSIndex (this, str
);
559 us_string_cache
[str
] = result
;
563 internal int GetToken (MemberInfo member
) {
564 return getToken (this, member
);
567 internal int GetToken (MethodInfo method
, Type
[] opt_param_types
) {
568 return getMethodToken (this, method
, opt_param_types
);
571 internal int GetToken (SignatureHelper helper
) {
572 return getToken (this, helper
);
575 internal TokenGenerator
GetTokenGenerator () {
576 if (token_gen
== null)
577 token_gen
= new ModuleBuilderTokenGenerator (this);
581 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
582 private static extern void build_metadata (ModuleBuilder mb
);
584 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
585 private static extern int getDataChunk (ModuleBuilder mb
, byte[] buf
, int offset
);
587 internal void Save ()
589 if (transient
&& !is_main
)
591 if ((global_type
!= null) && (global_type_created
== null))
592 global_type_created
= global_type
.CreateType ();
594 if (resource_writers
!= null) {
595 for (int i
= 0; i
< resource_writers
.Count
; ++i
) {
596 ResourceWriter writer
= (ResourceWriter
)resource_writers
[i
];
598 MemoryStream stream
= (MemoryStream
)writer
.Stream
;
599 resources
[i
].data
= new byte [stream
.Length
];
600 stream
.Seek (0, SeekOrigin
.Begin
);
601 stream
.Read (resources
[i
].data
, 0, (int)stream
.Length
);
605 build_metadata (this);
607 string fileName
= fqname
;
608 if (assemblyb
.AssemblyDir
!= null)
609 fileName
= System
.IO
.Path
.Combine (assemblyb
.AssemblyDir
, fileName
);
611 byte[] buf
= new byte [65536];
615 file
= new FileStream (fileName
, FileMode
.Create
, FileAccess
.Write
);
618 while ((count
= getDataChunk (this, buf
, offset
)) != 0) {
619 file
.Write (buf
, 0, count
);
625 // The constant 0x80000000 is internal to Mono, it means `make executable'
627 File
.SetAttributes (fileName
, (FileAttributes
) (unchecked ((int) 0x80000000)));
630 internal string FileName
{
636 internal bool IsMain
{
642 internal void CreateGlobalType () {
643 if (global_type
== null)
644 global_type
= new TypeBuilder (this, 0);
647 internal static Guid
Mono_GetGuid (ModuleBuilder mb
)
649 return new Guid (mb
.guid
);
653 internal class ModuleBuilderTokenGenerator
: TokenGenerator
{
655 private ModuleBuilder mb
;
657 public ModuleBuilderTokenGenerator (ModuleBuilder mb
) {
661 public int GetToken (string str
) {
662 return mb
.GetToken (str
);
665 public int GetToken (MemberInfo member
) {
666 return mb
.GetToken (member
);
669 public int GetToken (MethodInfo method
, Type
[] opt_param_types
) {
670 return mb
.GetToken (method
, opt_param_types
);
673 public int GetToken (SignatureHelper helper
) {
674 return mb
.GetToken (helper
);