Merge pull request #3749 from BrzVlad/fix-mips-fix
[mono.git] / mcs / class / corlib / System.Reflection.Emit / AssemblyBuilder.cs
1 //
2 // System.Reflection.Emit/AssemblyBuilder.cs
3 //
4 // Author:
5 //   Paolo Molaro (lupus@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 #if !FULL_AOT_RUNTIME
34 using System;
35 using System.Reflection;
36 using System.Resources;
37 using System.IO;
38 using System.Security.Policy;
39 using System.Runtime.Serialization;
40 using System.Globalization;
41 using System.Runtime.CompilerServices;
42 using System.Collections;
43 using System.Collections.Generic;
44 using System.Runtime.InteropServices;
45 using System.Security;
46 using System.Security.Cryptography;
47 using System.Security.Permissions;
48
49 using Mono.Security;
50 using Mono.Security.Cryptography;
51
52 namespace System.Reflection.Emit
53 {
54         internal enum NativeResourceType
55         {
56                 None,
57                 Unmanaged,
58                 Assembly,
59                 Explicit
60         }
61
62         internal struct RefEmitPermissionSet {
63                 public SecurityAction action;
64                 public string pset;
65
66                 public RefEmitPermissionSet (SecurityAction action, string pset) {
67                         this.action = action;
68                         this.pset = pset;
69                 }
70         }
71
72         internal struct MonoResource {
73 #pragma warning disable 649
74                 public byte[] data;
75                 public string name;
76                 public string filename;
77                 public ResourceAttributes attrs;
78                 public int offset;
79                 public Stream stream;
80 #pragma warning restore 649
81         }
82
83         internal struct MonoWin32Resource {
84                 public int res_type;
85                 public int res_id;
86                 public int lang_id;
87                 public byte[] data;
88
89                 public MonoWin32Resource (int res_type, int res_id, int lang_id, byte[] data) {
90                         this.res_type = res_type;
91                         this.res_id = res_id;
92                         this.lang_id = lang_id;
93                         this.data = data;
94                 }
95         }
96
97         internal class GenericInstanceKey {
98                 Type gtd;
99                 internal Type[] args;
100                 int hash_code;
101
102                 internal GenericInstanceKey (Type gtd, Type[] args)
103                 {
104                         this.gtd = gtd;
105                         this.args = args;
106
107                         hash_code = gtd.GetHashCode ();
108                         for (int i = 0; i < args.Length; ++i)
109                                 hash_code ^= args [i].GetHashCode ();
110                 }
111
112                 static bool IsBoundedVector (Type type) {
113                         ArrayType at = type as ArrayType;
114                         if (at != null)
115                                 return at.GetEffectiveRank () == 1;
116                         return type.ToString ().EndsWith ("[*]", StringComparison.Ordinal); /*Super uggly hack, SR doesn't allow one to query for it */
117                 }
118
119                 static bool TypeEquals (Type a, Type b) {
120                         if (a == b)
121                                 return true;
122
123                         if (a.HasElementType) {
124                                 if (!b.HasElementType)
125                                         return false;
126                                 if (!TypeEquals (a.GetElementType (), b.GetElementType ()))
127                                         return false;
128                                 if (a.IsArray) {
129                                         if (!b.IsArray)
130                                                 return false;
131                                         int rank = a.GetArrayRank ();
132                                         if (rank != b.GetArrayRank ())
133                                                 return false;
134                                         if (rank == 1 && IsBoundedVector (a) != IsBoundedVector (b))
135                                                 return false;
136                                 } else if (a.IsByRef) {
137                                         if (!b.IsByRef)
138                                                 return false;
139                                 } else if (a.IsPointer) {
140                                         if (!b.IsPointer)
141                                                 return false;
142                                 }
143                                 return true;
144                         }
145
146                         if (a.IsGenericType) {
147                                 if (!b.IsGenericType)
148                                         return false;
149                                 if (a.IsGenericParameter)
150                                         return a == b;
151                                 if (a.IsGenericParameter) //previous test should have caught it
152                                         return false;
153
154                                 if (a.IsGenericTypeDefinition) {
155                                         if (!b.IsGenericTypeDefinition)
156                                                 return false;
157                                 } else {
158                                         if (b.IsGenericTypeDefinition)
159                                                 return false;
160                                         if (!TypeEquals (a.GetGenericTypeDefinition (), b.GetGenericTypeDefinition ()))
161                                                 return false;
162
163                                         Type[] argsA = a.GetGenericArguments ();
164                                         Type[] argsB = b.GetGenericArguments ();
165                                         for (int i = 0; i < argsA.Length; ++i) {
166                                                 if (!TypeEquals (argsA [i], argsB [i]))
167                                                         return false;
168                                         }
169                                 }
170                         }
171
172                         /*
173                         Now only non-generic, non compound types are left. To properly deal with user
174                         types we would have to call UnderlyingSystemType, but we let them have their
175                         own instantiation as this is MS behavior and mcs (pre C# 4.0, at least) doesn't
176                         depend on proper UT canonicalization.
177                         */
178                         return a == b;
179                 }
180
181                 public override bool Equals (object obj)
182                 {
183                         GenericInstanceKey other = obj as GenericInstanceKey;
184                         if (other == null)
185                                 return false;
186                         if (gtd != other.gtd)
187                                 return false;
188                         for (int i = 0; i < args.Length; ++i) {
189                                 Type a = args [i];
190                                 Type b = other.args [i];
191                                 /*
192                                 We must cannonicalize as much as we can. Using equals means that some resulting types
193                                 won't have the exact same types as the argument ones. 
194                                 For example, flyweight types used array, pointer and byref will should this behavior.
195                                 MCS seens to be resilient to this problem so hopefully this won't show up.   
196                                 */
197                                 if (a != b && !a.Equals (b))
198                                         return false;
199                         }
200                         return true;
201                 }
202
203                 public override int GetHashCode ()
204                 {
205                         return hash_code;
206                 }
207         }
208
209
210         [ComVisible (true)]
211         [ComDefaultInterface (typeof (_AssemblyBuilder))]
212         [ClassInterface (ClassInterfaceType.None)]
213         [StructLayout (LayoutKind.Sequential)]
214         public sealed class AssemblyBuilder : Assembly, _AssemblyBuilder {
215 #pragma warning disable 169, 414, 649
216                 #region Sync with object-internals.h
217                 private UIntPtr dynamic_assembly; /* GC-tracked */
218                 private MethodInfo entry_point;
219                 private ModuleBuilder[] modules;
220                 private string name;
221                 private string dir;
222                 private CustomAttributeBuilder[] cattrs;
223                 private MonoResource[] resources;
224                 byte[] public_key;
225                 string version;
226                 string culture;
227                 uint algid;
228                 uint flags;
229                 PEFileKinds pekind = PEFileKinds.Dll;
230                 bool delay_sign;
231                 uint access;
232                 Module[] loaded_modules;
233                 MonoWin32Resource[] win32_resources;
234                 private RefEmitPermissionSet[] permissions_minimum;
235                 private RefEmitPermissionSet[] permissions_optional;
236                 private RefEmitPermissionSet[] permissions_refused;
237                 PortableExecutableKinds peKind;
238                 ImageFileMachine machine;
239                 bool corlib_internal;
240                 Type[] type_forwarders;
241                 byte[] pktoken;
242                 #endregion
243 #pragma warning restore 169, 414, 649
244                 
245                 internal Type corlib_object_type = typeof (System.Object);
246                 internal Type corlib_value_type = typeof (System.ValueType);
247                 internal Type corlib_enum_type = typeof (System.Enum);
248                 internal Type corlib_void_type = typeof (void);
249                 ArrayList resource_writers = null;
250                 Win32VersionResource version_res;
251                 bool created;
252                 bool is_module_only;
253                 private Mono.Security.StrongName sn;
254                 NativeResourceType native_resource;
255                 string versioninfo_culture;
256
257                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
258                 private static extern void basic_init (AssemblyBuilder ab);
259
260                 /* Keep this in sync with codegen.cs in mcs */
261                 private const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
262
263                 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access, bool corlib_internal)
264                 {
265                         /* This is obsolete now, as mcs doesn't use SRE any more */
266                         if ((access & COMPILER_ACCESS) != 0)
267                                 throw new NotImplementedException ("COMPILER_ACCESS is no longer supperted, use a newer mcs.");
268
269                         if (!Enum.IsDefined (typeof (AssemblyBuilderAccess), access))
270                                 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
271                                         "Argument value {0} is not valid.", (int) access),
272                                         "access");
273
274                         name = n.Name;
275                         this.access = (uint)access;
276                         flags = (uint) n.Flags;
277
278                         // don't call GetCurrentDirectory for Run-only builders (CAS may not like that)
279                         if (IsSave && (directory == null || directory.Length == 0)) {
280                                 dir = Directory.GetCurrentDirectory ();
281                         } else {
282                                 dir = directory;
283                         }
284
285                         /* Set defaults from n */
286                         if (n.CultureInfo != null) {
287                                 culture = n.CultureInfo.Name;
288                                 versioninfo_culture = n.CultureInfo.Name;
289                         }
290                         Version v = n.Version;
291                         if (v != null) {
292                                 version = v.ToString ();
293                         }
294
295                         if (n.KeyPair != null) {
296                                 // full keypair is available (for signing)
297                                 sn = n.KeyPair.StrongName ();
298                         } else {
299                                 // public key is available (for delay-signing)
300                                 byte[] pk = n.GetPublicKey ();
301                                 if ((pk != null) && (pk.Length > 0)) {
302                                         sn = new Mono.Security.StrongName (pk);
303                                 }
304                         }
305
306                         if (sn != null)
307                                 flags |= (uint) AssemblyNameFlags.PublicKey;
308
309                         this.corlib_internal = corlib_internal;
310                         if (sn != null) {
311                                 this.pktoken = new byte[sn.PublicKeyToken.Length * 2];
312                                 int pkti = 0;
313                                 foreach (byte pkb in sn.PublicKeyToken) {
314                                         string part = pkb.ToString("x2");
315                                         this.pktoken[pkti++] = (byte)part[0];
316                                         this.pktoken[pkti++] = (byte)part[1];
317                                 }
318                         }
319
320                         basic_init (this);
321                 }
322
323                 public override string CodeBase {
324                         get {
325                                 throw not_supported ();
326                         }
327                 }
328                 
329                 public override MethodInfo EntryPoint {
330                         get {
331                                 return entry_point;
332                         }
333                 }
334
335                 public override string Location {
336                         get {
337                                 throw not_supported ();
338                         }
339                 }
340
341                 /* This is to keep signature compatibility with MS.NET */
342                 public override string ImageRuntimeVersion {
343                         get {
344                                 return base.ImageRuntimeVersion;
345                         }
346                 }
347
348                 [MonoTODO]
349                 public override bool ReflectionOnly {
350                         get { return base.ReflectionOnly; }
351                 }
352
353                 public void AddResourceFile (string name, string fileName)
354                 {
355                         AddResourceFile (name, fileName, ResourceAttributes.Public);
356                 }
357
358                 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
359                 {
360                         AddResourceFile (name, fileName, attribute, true);
361                 }
362
363                 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
364                 {
365                         check_name_and_filename (name, fileName, fileNeedsToExists);
366
367                         // Resource files are created/searched under the assembly storage
368                         // directory
369                         if (dir != null)
370                                 fileName = Path.Combine (dir, fileName);
371
372                         if (resources != null) {
373                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
374                                 System.Array.Copy(resources, new_r, resources.Length);
375                                 resources = new_r;
376                         } else {
377                                 resources = new MonoResource [1];
378                         }
379                         int p = resources.Length - 1;
380                         resources [p].name = name;
381                         resources [p].filename = fileName;
382                         resources [p].attrs = attribute;
383                 }
384
385                 internal void AddPermissionRequests (PermissionSet required, PermissionSet optional, PermissionSet refused)
386                 {
387 #if !MOBILE
388                         if (created)
389                                 throw new InvalidOperationException ("Assembly was already saved.");
390
391                         // required for base Assembly class (so the permissions
392                         // can be used even if the assembly isn't saved to disk)
393                         _minimum = required;
394                         _optional = optional;
395                         _refuse = refused;
396
397                         // required to reuse AddDeclarativeSecurity support 
398                         // already present in the runtime
399                         if (required != null) {
400                                 permissions_minimum = new RefEmitPermissionSet [1];
401                                 permissions_minimum [0] = new RefEmitPermissionSet (
402                                         SecurityAction.RequestMinimum, required.ToXml ().ToString ());
403                         }
404                         if (optional != null) {
405                                 permissions_optional = new RefEmitPermissionSet [1];
406                                 permissions_optional [0] = new RefEmitPermissionSet (
407                                         SecurityAction.RequestOptional, optional.ToXml ().ToString ());
408                         }
409                         if (refused != null) {
410                                 permissions_refused = new RefEmitPermissionSet [1];
411                                 permissions_refused [0] = new RefEmitPermissionSet (
412                                         SecurityAction.RequestRefuse, refused.ToXml ().ToString ());
413                         }
414 #endif
415                 }
416
417                 // Still in use by al.exe
418                 internal void EmbedResourceFile (string name, string fileName)
419                 {
420                         EmbedResourceFile (name, fileName, ResourceAttributes.Public);
421                 }
422
423                 void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
424                 {
425                         if (resources != null) {
426                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
427                                 System.Array.Copy(resources, new_r, resources.Length);
428                                 resources = new_r;
429                         } else {
430                                 resources = new MonoResource [1];
431                         }
432                         int p = resources.Length - 1;
433                         resources [p].name = name;
434                         resources [p].attrs = attribute;
435                         try {
436                                 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
437                                 long len = s.Length;
438                                 resources [p].data = new byte [len];
439                                 s.Read (resources [p].data, 0, (int)len);
440                                 s.Close ();
441                         } catch {
442                         }
443                 }
444 /*
445                 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
446                 {
447                         if (resources != null) {
448                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
449                                 System.Array.Copy(resources, new_r, resources.Length);
450                                 resources = new_r;
451                         } else {
452                                 resources = new MonoResource [1];
453                         }
454                         int p = resources.Length - 1;
455                         resources [p].name = name;
456                         resources [p].attrs = attribute;
457                         resources [p].data = blob;
458                 }
459 */
460
461                 public static AssemblyBuilder DefineDynamicAssembly (AssemblyName name, AssemblyBuilderAccess access)
462                 {
463                         if (name == null)
464                                 throw new ArgumentNullException ("name");
465
466                         return new AssemblyBuilder (name, null, access, false);
467                 }
468
469                 public static AssemblyBuilder DefineDynamicAssembly (AssemblyName name, AssemblyBuilderAccess access, IEnumerable<CustomAttributeBuilder> assemblyAttributes)
470                 {
471                         throw new NotImplementedException ();
472                 }
473
474                 public ModuleBuilder DefineDynamicModule (string name)
475                 {
476                         return DefineDynamicModule (name, name, false, true);
477                 }
478
479                 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
480                 {
481                         return DefineDynamicModule (name, name, emitSymbolInfo, true);
482                 }
483
484                 public ModuleBuilder DefineDynamicModule(string name, string fileName)
485                 {
486                         return DefineDynamicModule (name, fileName, false, false);
487                 }
488
489                 public ModuleBuilder DefineDynamicModule (string name, string fileName,
490                                                           bool emitSymbolInfo)
491                 {
492                         return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
493                 }
494
495                 private ModuleBuilder DefineDynamicModule (string name, string fileName, bool emitSymbolInfo, bool transient)
496                 {
497                         check_name_and_filename (name, fileName, false);
498
499                         if (!transient) {
500                                 if (Path.GetExtension (fileName) == String.Empty)
501                                         throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
502                                 if (!IsSave)
503                                         throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
504                                 if (created)
505                                         throw new InvalidOperationException ("Assembly was already saved.");
506                         }
507
508                         ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
509
510                         if ((modules != null) && is_module_only)
511                                 throw new InvalidOperationException ("A module-only assembly can only contain one module.");
512
513                         if (modules != null) {
514                                 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
515                                 System.Array.Copy(modules, new_modules, modules.Length);
516                                 modules = new_modules;
517                         } else {
518                                 modules = new ModuleBuilder [1];
519                         }
520                         modules [modules.Length - 1] = r;
521                         return r;
522                 }
523
524                 public IResourceWriter DefineResource (string name, string description, string fileName)
525                 {
526                         return DefineResource (name, description, fileName, ResourceAttributes.Public);
527                 }
528
529                 public IResourceWriter DefineResource (string name, string description,
530                                                        string fileName, ResourceAttributes attribute)
531                 {
532                         IResourceWriter writer;
533
534                         // description seems to be ignored
535                         AddResourceFile (name, fileName, attribute, false);
536                         writer = new ResourceWriter (fileName);
537                         if (resource_writers == null)
538                                 resource_writers = new ArrayList ();
539                         resource_writers.Add (writer);
540                         return writer;
541                 }
542
543                 private void AddUnmanagedResource (Win32Resource res) {
544                         MemoryStream ms = new MemoryStream ();
545                         res.WriteTo (ms);
546
547                         if (win32_resources != null) {
548                                 MonoWin32Resource[] new_res = new MonoWin32Resource [win32_resources.Length + 1];
549                                 System.Array.Copy (win32_resources, new_res, win32_resources.Length);
550                                 win32_resources = new_res;
551                         }
552                         else
553                                 win32_resources = new MonoWin32Resource [1];
554
555                         win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ());
556                 }
557
558                 [MonoTODO ("Not currently implemenented")]
559                 public void DefineUnmanagedResource (byte[] resource)
560                 {
561                         if (resource == null)
562                                 throw new ArgumentNullException ("resource");
563                         if (native_resource != NativeResourceType.None)
564                                 throw new ArgumentException ("Native resource has already been defined.");
565
566                         // avoid definition of more than one unmanaged resource
567                         native_resource = NativeResourceType.Unmanaged;
568
569                         /*
570                          * The format of the argument byte array is not documented
571                          * so this method is impossible to implement.
572                          *
573                          * https://connect.microsoft.com/VisualStudio/feedback/details/95784/fatal-assemblybuilder-defineunmanagedresource-byte-and-modulebuilder-defineunmanagedresource-byte-bugs-renders-them-useless
574                          */
575
576                         throw new NotImplementedException ();
577                 }
578
579                 public void DefineUnmanagedResource (string resourceFileName)
580                 {
581                         if (resourceFileName == null)
582                                 throw new ArgumentNullException ("resourceFileName");
583                         if (resourceFileName.Length == 0)
584                                 throw new ArgumentException ("resourceFileName");
585                         if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
586                                 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exist or is a directory.");
587                         if (native_resource != NativeResourceType.None)
588                                 throw new ArgumentException ("Native resource has already been defined.");
589
590                         // avoid definition of more than one unmanaged resource
591                         native_resource = NativeResourceType.Unmanaged;
592
593                         using (FileStream fs = new FileStream (resourceFileName, FileMode.Open, FileAccess.Read)) {
594                                 Win32ResFileReader reader = new Win32ResFileReader (fs);
595
596                                 foreach (Win32EncodedResource res in reader.ReadResources ()) {
597                                         if (res.Name.IsName || res.Type.IsName)
598                                                 throw new InvalidOperationException ("resource files with named resources or non-default resource types are not supported.");
599
600                                         AddUnmanagedResource (res);
601                                 }
602                         }
603                 }
604
605                 public void DefineVersionInfoResource ()
606                 {
607                         if (native_resource != NativeResourceType.None)
608                                 throw new ArgumentException ("Native resource has already been defined.");
609
610                         // avoid definition of more than one unmanaged resource
611                         native_resource = NativeResourceType.Assembly;
612
613                         version_res = new Win32VersionResource (1, 0, false);
614                 }
615
616                 public void DefineVersionInfoResource (string product, string productVersion,
617                                                        string company, string copyright, string trademark)
618                 {
619                         if (native_resource != NativeResourceType.None)
620                                 throw new ArgumentException ("Native resource has already been defined.");
621
622                         // avoid definition of more than one unmanaged resource
623                         native_resource = NativeResourceType.Explicit;
624
625                         /*
626                          * We can only create the resource later, when the file name and
627                          * the binary version is known.
628                          */
629
630                         version_res = new Win32VersionResource (1, 0, false);
631                         version_res.ProductName = product != null ? product : " ";
632                         version_res.ProductVersion = productVersion != null ? productVersion : " ";
633                         version_res.CompanyName = company != null ? company : " ";
634                         version_res.LegalCopyright = copyright != null ? copyright : " ";
635                         version_res.LegalTrademarks = trademark != null ? trademark : " ";
636                 }
637
638                 private void DefineVersionInfoResourceImpl (string fileName)
639                 {
640                         if (versioninfo_culture != null)
641                                 version_res.FileLanguage = new CultureInfo (versioninfo_culture).LCID;
642                         version_res.Version = version == null ? "0.0.0.0" : version;
643
644                         if (cattrs != null) {
645                                 switch (native_resource) {
646                                 case NativeResourceType.Assembly:
647                                         foreach (CustomAttributeBuilder cb in cattrs) {
648                                                 string attrname = cb.Ctor.ReflectedType.FullName;
649
650                                                 if (attrname == "System.Reflection.AssemblyProductAttribute")
651                                                         version_res.ProductName = cb.string_arg ();
652                                                 else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
653                                                         version_res.CompanyName = cb.string_arg ();
654                                                 else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
655                                                         version_res.LegalCopyright = cb.string_arg ();
656                                                 else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
657                                                         version_res.LegalTrademarks = cb.string_arg ();
658                                                 else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
659                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
660                                                 } else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") {
661                                                         version_res.FileVersion = cb.string_arg ();
662                                                 } else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
663                                                         version_res.ProductVersion = cb.string_arg ();
664                                                 else if (attrname == "System.Reflection.AssemblyTitleAttribute")
665                                                         version_res.FileDescription = cb.string_arg ();
666                                                 else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
667                                                         version_res.Comments = cb.string_arg ();
668                                         }
669                                         break;
670                                 case NativeResourceType.Explicit:
671                                         foreach (CustomAttributeBuilder cb in cattrs) {
672                                                 string attrname = cb.Ctor.ReflectedType.FullName;
673
674                                                 if (attrname == "System.Reflection.AssemblyCultureAttribute") {
675                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
676                                                 } else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
677                                                         version_res.Comments = cb.string_arg ();
678                                         }
679                                         break;
680                                 }
681                         }
682
683                         version_res.OriginalFilename = fileName;
684                         version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
685
686                         AddUnmanagedResource (version_res);
687                 }
688
689                 public ModuleBuilder GetDynamicModule (string name)
690                 {
691                         if (name == null)
692                                 throw new ArgumentNullException ("name");
693                         if (name.Length == 0)
694                                 throw new ArgumentException ("Empty name is not legal.", "name");
695
696                         if (modules != null)
697                                 for (int i = 0; i < modules.Length; ++i)
698                                         if (modules [i].name == name)
699                                                 return modules [i];
700                         return null;
701                 }
702
703                 public override Type[] GetExportedTypes ()
704                 {
705                         throw not_supported ();
706                 }
707
708                 public override FileStream GetFile (string name)
709                 {
710                         throw not_supported ();
711                 }
712
713                 public override FileStream[] GetFiles(bool getResourceModules) {
714                         throw not_supported ();
715                 }
716
717                 internal override Module[] GetModulesInternal () {
718                         if (modules == null)
719                                 return new Module [0];
720                         else
721                                 return (Module[])modules.Clone ();
722                 }
723
724                 internal override Type[] GetTypes (bool exportedOnly) {
725                         Type[] res = null;
726                         if (modules != null) {
727                                 for (int i = 0; i < modules.Length; ++i) {
728                                         Type[] types = modules [i].GetTypes ();
729                                         if (res == null)
730                                                 res = types;
731                                         else {
732                                                 Type[] tmp = new Type [res.Length + types.Length];
733                                                 Array.Copy (res, 0, tmp, 0, res.Length);
734                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
735                                         }
736                                 }
737                         }
738                         if (loaded_modules != null) {
739                                 for (int i = 0; i < loaded_modules.Length; ++i) {
740                                         Type[] types = loaded_modules [i].GetTypes ();
741                                         if (res == null)
742                                                 res = types;
743                                         else {
744                                                 Type[] tmp = new Type [res.Length + types.Length];
745                                                 Array.Copy (res, 0, tmp, 0, res.Length);
746                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
747                                         }
748                                 }
749                         }
750
751                         if (res != null) {
752                                 List<Exception> exceptions = null;
753                                 foreach (var type in res) {
754                                         if (type is TypeBuilder) {
755                                                 if (exceptions == null)
756                                                         exceptions = new List <Exception> ();
757                                                 exceptions.Add (new TypeLoadException (string.Format ("Type '{0}' is not finished", type.FullName))); 
758                                         }
759                                 }
760                                 if (exceptions != null)
761                                         throw new ReflectionTypeLoadException (new Type [exceptions.Count], exceptions.ToArray ());
762                         }
763                         
764                         return res == null ? Type.EmptyTypes : res;
765                 }
766
767                 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
768                         throw not_supported ();
769                 }
770
771                 public override string[] GetManifestResourceNames() {
772                         throw not_supported ();
773                 }
774
775                 public override Stream GetManifestResourceStream(string name) {
776                         throw not_supported ();
777                 }
778                 public override Stream GetManifestResourceStream(Type type, string name) {
779                         throw not_supported ();
780                 }
781
782                 internal bool IsSave {
783                         get {
784                                 return access != (uint)AssemblyBuilderAccess.Run;
785                         }
786                 }
787
788                 internal bool IsRun {
789                         get {
790                                 return access == (uint)AssemblyBuilderAccess.Run || access == (uint)AssemblyBuilderAccess.RunAndSave
791                                          || access == (uint)AssemblyBuilderAccess.RunAndCollect
792                                 ;
793
794                         }
795                 }
796 /*
797                 internal bool IsCollectible {
798                         get {
799                                 return access == (uint)AssemblyBuilderAccess.RunAndCollect;
800                         }
801                 }
802 */
803                 internal string AssemblyDir {
804                         get {
805                                 return dir;
806                         }
807                 }
808
809                 /*
810                  * Mono extension. If this is set, the assembly can only contain one
811                  * module, access should be Save, and the saved image will not contain an
812                  * assembly manifest.
813                  */
814                 internal bool IsModuleOnly {
815                         get {
816                                 return is_module_only;
817                         }
818                         set {
819                                 is_module_only = value;
820                         }
821                 }
822
823                 ModuleBuilder manifest_module;
824
825                 //
826                 // MS.NET seems to return a ModuleBuilder when GetManifestModule () is called
827                 // on an assemblybuilder.
828                 //
829                 internal override Module GetManifestModule () {
830                         if (manifest_module == null)
831                                 manifest_module = DefineDynamicModule ("Default Dynamic Module");
832                         return manifest_module;
833                 }
834
835                 [MonoLimitation ("No support for PE32+ assemblies for AMD64 and IA64")]
836                 public 
837                 void Save (string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
838                 {
839                         this.peKind = portableExecutableKind;
840                         this.machine = imageFileMachine;
841
842                         if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || (peKind & PortableExecutableKinds.Unmanaged32Bit) != 0)
843                                 throw new NotImplementedException (peKind.ToString ());
844                         if (machine == ImageFileMachine.IA64 || machine == ImageFileMachine.AMD64)
845                                 throw new NotImplementedException (machine.ToString ());
846
847                         if (resource_writers != null) {
848                                 foreach (IResourceWriter writer in resource_writers) {
849                                         writer.Generate ();
850                                         writer.Close ();
851                                 }
852                         }
853
854                         // Create a main module if not already created
855                         ModuleBuilder mainModule = null;
856                         if (modules != null) {
857                                 foreach (ModuleBuilder module in modules)
858                                         if (module.FullyQualifiedName == assemblyFileName)
859                                                 mainModule = module;
860                         }
861                         if (mainModule == null)
862                                 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
863
864                         if (!is_module_only)
865                                 mainModule.IsMain = true;
866
867                         /* 
868                          * Create a new entry point if the one specified
869                          * by the user is in another module.
870                          */
871                         if ((entry_point != null) && entry_point.DeclaringType.Module != mainModule) {
872                                 Type[] paramTypes;
873                                 if (entry_point.GetParametersCount () == 1)
874                                         paramTypes = new Type [] { typeof (string) };
875                                 else
876                                         paramTypes = Type.EmptyTypes;
877
878                                 MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes);
879                                 ILGenerator ilgen = mb.GetILGenerator ();
880                                 if (paramTypes.Length == 1)
881                                         ilgen.Emit (OpCodes.Ldarg_0);
882                                 ilgen.Emit (OpCodes.Tailcall);
883                                 ilgen.Emit (OpCodes.Call, entry_point);
884                                 ilgen.Emit (OpCodes.Ret);
885
886                                 entry_point = mb;
887                         }
888
889                         if (version_res != null)
890                                 DefineVersionInfoResourceImpl (assemblyFileName);
891
892                         if (sn != null) {
893                                 // runtime needs to value to embed it into the assembly
894                                 public_key = sn.PublicKey;
895                         }
896
897                         foreach (ModuleBuilder module in modules)
898                                 if (module != mainModule)
899                                         module.Save ();
900
901                         // Write out the main module at the end, because it needs to
902                         // contain the hash of the other modules
903                         mainModule.Save ();
904
905                         if ((sn != null) && (sn.CanSign)) {
906                                 sn.Sign (System.IO.Path.Combine (this.AssemblyDir, assemblyFileName));
907                         }
908
909                         created = true;
910                 }
911
912                 public void Save (string assemblyFileName)
913                 {
914                         Save (assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
915                 }
916
917                 public void SetEntryPoint (MethodInfo entryMethod)
918                 {
919                         SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
920                 }
921
922                 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
923                 {
924                         if (entryMethod == null)
925                                 throw new ArgumentNullException ("entryMethod");
926                         if (entryMethod.DeclaringType.Assembly != this)
927                                 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
928
929                         entry_point = entryMethod;
930                         pekind = fileKind;
931                 }
932
933                 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) 
934                 {
935                         if (customBuilder == null)
936                                 throw new ArgumentNullException ("customBuilder");
937
938                         if (cattrs != null) {
939                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
940                                 cattrs.CopyTo (new_array, 0);
941                                 new_array [cattrs.Length] = customBuilder;
942                                 cattrs = new_array;
943                         } else {
944                                 cattrs = new CustomAttributeBuilder [1];
945                                 cattrs [0] = customBuilder;
946                         }
947                 }
948
949                 [ComVisible (true)]
950                 public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
951                         if (con == null)
952                                 throw new ArgumentNullException ("con");
953                         if (binaryAttribute == null)
954                                 throw new ArgumentNullException ("binaryAttribute");
955
956                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
957                 }
958
959                 private Exception not_supported () {
960                         // Strange message but this is what MS.NET prints...
961                         return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
962                 }
963
964                 private void check_name_and_filename (string name, string fileName,
965                                                                                           bool fileNeedsToExists) {
966                         if (name == null)
967                                 throw new ArgumentNullException ("name");
968                         if (fileName == null)
969                                 throw new ArgumentNullException ("fileName");
970                         if (name.Length == 0)
971                                 throw new ArgumentException ("Empty name is not legal.", "name");
972                         if (fileName.Length == 0)
973                                 throw new ArgumentException ("Empty file name is not legal.", "fileName");
974                         if (Path.GetFileName (fileName) != fileName)
975                                 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.", "fileName");
976
977                         // Resource files are created/searched under the assembly storage
978                         // directory
979                         string fullFileName = fileName;
980                         if (dir != null)
981                                 fullFileName = Path.Combine (dir, fileName);
982
983                         if (fileNeedsToExists && !File.Exists (fullFileName))
984                                 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
985
986                         if (resources != null) {
987                                 for (int i = 0; i < resources.Length; ++i) {
988                                         if (resources [i].filename == fullFileName)
989                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
990                                         if (resources [i].name == name)
991                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
992                                 }
993                         }
994
995                         if (modules != null) {
996                                 for (int i = 0; i < modules.Length; ++i) {
997                                         // Use fileName instead of fullFileName here
998                                         if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
999                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
1000                                         if (modules [i].Name == name)
1001                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
1002                                 }
1003                         }
1004                 }
1005
1006                 private String create_assembly_version (String version) {
1007                         String[] parts = version.Split ('.');
1008                         int[] ver = new int [4] { 0, 0, 0, 0 };
1009
1010                         if ((parts.Length < 0) || (parts.Length > 4))
1011                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1012
1013                         for (int i = 0; i < parts.Length; ++i) {
1014                                 if (parts [i] == "*") {
1015                                         DateTime now = DateTime.Now;
1016
1017                                         if (i == 2) {
1018                                                 ver [2] = (now - new DateTime (2000, 1, 1)).Days;
1019                                                 if (parts.Length == 3)
1020                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1021                                         }
1022                                         else
1023                                                 if (i == 3)
1024                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1025                                         else
1026                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1027                                 }
1028                                 else {
1029                                         try {
1030                                                 ver [i] = Int32.Parse (parts [i]);
1031                                         }
1032                                         catch (FormatException) {
1033                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1034                                         }
1035                                 }
1036                         }
1037
1038                         return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];
1039                 }
1040
1041                 private string GetCultureString (string str)
1042                 {
1043                         return (str == "neutral" ? String.Empty : str);
1044                 }
1045
1046                 /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
1047                 internal Type MakeGenericType (Type gtd, Type[] typeArguments)
1048                 {
1049                         return new TypeBuilderInstantiation (gtd, typeArguments);
1050                 }
1051
1052                 void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1053                 {
1054                         throw new NotImplementedException ();
1055                 }
1056
1057                 void _AssemblyBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1058                 {
1059                         throw new NotImplementedException ();
1060                 }
1061
1062                 void _AssemblyBuilder.GetTypeInfoCount (out uint pcTInfo)
1063                 {
1064                         throw new NotImplementedException ();
1065                 }
1066
1067                 void _AssemblyBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1068                 {
1069                         throw new NotImplementedException ();
1070                 }
1071
1072                 public override Type GetType (string name, bool throwOnError, bool ignoreCase)
1073                 {
1074                         if (name == null)
1075                                 throw new ArgumentNullException (name);
1076                         if (name.Length == 0)
1077                         throw new ArgumentException ("name", "Name cannot be empty");
1078
1079                         var res = InternalGetType (null, name, throwOnError, ignoreCase);
1080                         if (res is TypeBuilder) {
1081                                 if (throwOnError)
1082                                         throw new TypeLoadException (string.Format ("Could not load type '{0}' from assembly '{1}'", name, this.name));
1083                                 return null;
1084                         }
1085                         return res;
1086                 }
1087
1088                 public override Module GetModule (String name)
1089                 {
1090                         if (name == null)
1091                                 throw new ArgumentNullException ("name");
1092                         if (name.Length == 0)
1093                                 throw new ArgumentException ("Name can't be empty");
1094
1095                         if (modules == null)
1096                                 return null;
1097
1098                         foreach (Module module in modules) {
1099                                 if (module.ScopeName == name)
1100                                         return module;
1101                         }
1102
1103                         return null;
1104                 }
1105
1106                 public override Module[] GetModules (bool getResourceModules)
1107                 {
1108                         Module[] modules = GetModulesInternal ();
1109
1110                         if (!getResourceModules) {
1111                                 var result = new List<Module> (modules.Length);
1112                                 foreach (Module m in modules)
1113                                         if (!m.IsResource ())
1114                                                 result.Add (m);
1115                                 return result.ToArray ();
1116                         }
1117                         return modules;
1118                 }
1119
1120                 public override AssemblyName GetName (bool copiedName)
1121                 {
1122                         var aname = AssemblyName.Create (this, false);
1123
1124                         if (sn != null) {
1125                                 aname.SetPublicKey (sn.PublicKey);
1126                                 aname.SetPublicKeyToken (sn.PublicKeyToken);
1127                         }
1128                         return aname;
1129
1130                 }
1131
1132                 [MonoTODO ("This always returns an empty array")]
1133                 public override AssemblyName[] GetReferencedAssemblies () {
1134                         return GetReferencedAssemblies (this);
1135                 }
1136
1137                 public override Module[] GetLoadedModules (bool getResourceModules)
1138                 {
1139                         return GetModules (getResourceModules);
1140                 }
1141
1142                 //FIXME MS has issues loading satelite assemblies from SRE
1143                 public override Assembly GetSatelliteAssembly (CultureInfo culture)
1144                 {
1145                         return GetSatelliteAssembly (culture, null, true);
1146                 }
1147
1148                 //FIXME MS has issues loading satelite assemblies from SRE
1149                 public override Assembly GetSatelliteAssembly (CultureInfo culture, Version version)
1150                 {
1151                         return GetSatelliteAssembly (culture, version, true);
1152                 }
1153
1154                 public override Module ManifestModule {
1155                         get {
1156                                 return GetManifestModule ();
1157                         }
1158                 }
1159
1160                 public override bool GlobalAssemblyCache {
1161                         get {
1162                                 return false;
1163                         }
1164                 }
1165
1166                 public override bool IsDynamic {
1167                         get { return true; }
1168                 }
1169
1170                 public override bool Equals (object obj)
1171                 {
1172                         return base.Equals (obj);
1173                 }
1174
1175                 public override int GetHashCode ()
1176                 {
1177                         return base.GetHashCode ();
1178                 }
1179
1180                 public override bool IsDefined (Type attributeType, bool inherit)
1181                 {
1182                         return base.IsDefined (attributeType, inherit);
1183                 }
1184
1185                 public override object[] GetCustomAttributes (bool inherit)
1186                 {
1187                         return base.GetCustomAttributes (inherit);
1188                 }
1189
1190                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
1191                 {
1192                         return base.GetCustomAttributes (attributeType, inherit);
1193                 }
1194
1195                 public override string FullName {
1196                         get { return base.FullName; }
1197                 }
1198         }
1199 }
1200 #endif