Avoid random failure in CountdownEvent unit test
[mono.git] / mcs / class / corlib / System.Reflection.Emit / AssemblyBuilder.cs
old mode 100755 (executable)
new mode 100644 (file)
index 344395b..5f49190
@@ -39,14 +39,24 @@ using System.Runtime.Serialization;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Collections;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
+using System.Security;
 using System.Security.Cryptography;
 using System.Security.Permissions;
 
 using Mono.Security;
 using Mono.Security.Cryptography;
 
-namespace System.Reflection.Emit {
+namespace System.Reflection.Emit
+{
+       internal enum NativeResourceType
+       {
+               None,
+               Unmanaged,
+               Assembly,
+               Explicit
+       }
 
        internal struct RefEmitPermissionSet {
                public SecurityAction action;
@@ -64,6 +74,7 @@ namespace System.Reflection.Emit {
                public string filename;
                public ResourceAttributes attrs;
                public int offset;
+               public Stream stream;
        }
 
        internal struct MonoWin32Resource {
@@ -80,9 +91,126 @@ namespace System.Reflection.Emit {
                }
        }
 
-       public sealed class AssemblyBuilder : Assembly {
-               #region Sync with reflection.h
-               private IntPtr dynamic_assembly;
+       internal class GenericInstanceKey {
+               Type gtd;
+               internal Type[] args;
+               int hash_code;
+
+               internal GenericInstanceKey (Type gtd, Type[] args)
+               {
+                       this.gtd = gtd;
+                       this.args = args;
+
+                       hash_code = gtd.GetHashCode ();
+                       for (int i = 0; i < args.Length; ++i)
+                               hash_code ^= args [i].GetHashCode ();
+               }
+
+               static bool IsBoundedVector (Type type) {
+                       ArrayType at = type as ArrayType;
+                       if (at != null)
+                               return at.GetEffectiveRank () == 1;
+                       return type.ToString ().EndsWith ("[*]", StringComparison.Ordinal); /*Super uggly hack, SR doesn't allow one to query for it */
+               }
+
+               static bool TypeEquals (Type a, Type b) {
+                       if (a == b)
+                               return true;
+
+                       if (a.HasElementType) {
+                               if (!b.HasElementType)
+                                       return false;
+                               if (!TypeEquals (a.GetElementType (), b.GetElementType ()))
+                                       return false;
+                               if (a.IsArray) {
+                                       if (!b.IsArray)
+                                               return false;
+                                       int rank = a.GetArrayRank ();
+                                       if (rank != b.GetArrayRank ())
+                                               return false;
+                                       if (rank == 1 && IsBoundedVector (a) != IsBoundedVector (b))
+                                               return false;
+                               } else if (a.IsByRef) {
+                                       if (!b.IsByRef)
+                                               return false;
+                               } else if (a.IsPointer) {
+                                       if (!b.IsPointer)
+                                               return false;
+                               }
+                               return true;
+                       }
+
+                       if (a.IsGenericType) {
+                               if (!b.IsGenericType)
+                                       return false;
+                               if (a.IsGenericParameter)
+                                       return a == b;
+                               if (a.IsGenericParameter) //previous test should have caught it
+                                       return false;
+
+                               if (a.IsGenericTypeDefinition) {
+                                       if (!b.IsGenericTypeDefinition)
+                                               return false;
+                               } else {
+                                       if (b.IsGenericTypeDefinition)
+                                               return false;
+                                       if (!TypeEquals (a.GetGenericTypeDefinition (), b.GetGenericTypeDefinition ()))
+                                               return false;
+
+                                       Type[] argsA = a.GetGenericArguments ();
+                                       Type[] argsB = b.GetGenericArguments ();
+                                       for (int i = 0; i < argsA.Length; ++i) {
+                                               if (!TypeEquals (argsA [i], argsB [i]))
+                                                       return false;
+                                       }
+                               }
+                       }
+
+                       /*
+                       Now only non-generic, non compound types are left. To properly deal with user
+                       types we would have to call UnderlyingSystemType, but we let them have their
+                       own instantiation as this is MS behavior and mcs (pre C# 4.0, at least) doesn't
+                       depend on proper UT canonicalization.
+                       */
+                       return a == b;
+               }
+
+               public override bool Equals (object obj)
+               {
+                       GenericInstanceKey other = obj as GenericInstanceKey;
+                       if (other == null)
+                               return false;
+                       if (gtd != other.gtd)
+                               return false;
+                       for (int i = 0; i < args.Length; ++i) {
+                               Type a = args [i];
+                               Type b = other.args [i];
+                               /*
+                               We must cannonicalize as much as we can. Using equals means that some resulting types
+                               won't have the exact same types as the argument ones. 
+                               For example, flyweight types used array, pointer and byref will should this behavior.
+                               MCS seens to be resilient to this problem so hopefully this won't show up.   
+                               */
+                               if (a != b && !a.Equals (b))
+                                       return false;
+                       }
+                       return true;
+               }
+
+               public override int GetHashCode ()
+               {
+                       return hash_code;
+               }
+       }
+
+
+       [ComVisible (true)]
+       [ComDefaultInterface (typeof (_AssemblyBuilder))]
+       [ClassInterface (ClassInterfaceType.None)]
+       public sealed class AssemblyBuilder : Assembly, _AssemblyBuilder {
+#pragma warning disable 169, 414
+               #region Sync with object-internals.h
+               private UIntPtr dynamic_assembly; /* GC-tracked */
                private MethodInfo entry_point;
                private ModuleBuilder[] modules;
                private string name;
@@ -99,7 +227,17 @@ namespace System.Reflection.Emit {
                uint access;
                Module[] loaded_modules;
                MonoWin32Resource[] win32_resources;
+               private RefEmitPermissionSet[] permissions_minimum;
+               private RefEmitPermissionSet[] permissions_optional;
+               private RefEmitPermissionSet[] permissions_refused;
+               PortableExecutableKinds peKind;
+               ImageFileMachine machine;
+               bool corlib_internal;
+               Type[] type_forwarders;
+               byte[] pktoken;
                #endregion
+#pragma warning restore 169, 414
+               
                internal Type corlib_object_type = typeof (System.Object);
                internal Type corlib_value_type = typeof (System.ValueType);
                internal Type corlib_enum_type = typeof (System.Enum);
@@ -109,21 +247,56 @@ namespace System.Reflection.Emit {
                bool created;
                bool is_module_only;
                private Mono.Security.StrongName sn;
+               NativeResourceType native_resource;
+               readonly bool is_compiler_context;
+               string versioninfo_culture;
+               Hashtable generic_instances = new Hashtable ();
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private static extern void basic_init (AssemblyBuilder ab);
-               
-               internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) {
+
+               /* Keep this in sync with codegen.cs in mcs */
+               private const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
+
+               internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access, bool corlib_internal)
+               {
+                       is_compiler_context = (access & COMPILER_ACCESS) != 0;
+
+                       // remove Mono specific flag to allow enum check to pass
+                       access &= ~COMPILER_ACCESS;
+
+#if MOONLIGHT
+                       // only "Run" is supported by Silverlight
+                       // however SMCS requires more than this but runs outside the CoreCLR sandbox
+                       if (SecurityManager.SecurityEnabled && (access != AssemblyBuilderAccess.Run))
+                               throw new ArgumentException ("access");
+#endif
+
+                       if (!Enum.IsDefined (typeof (AssemblyBuilderAccess), access))
+                               throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+                                       "Argument value {0} is not valid.", (int) access),
+                                       "access");
+
+#if NET_4_0
+                       if ((access & AssemblyBuilderAccess.RunAndCollect) == AssemblyBuilderAccess.RunAndCollect)
+                               throw new NotSupportedException ("RunAndCollect not yet supported.");
+#endif
+
                        name = n.Name;
-                       if (directory == null || directory == String.Empty)
+                       this.access = (uint)access;
+                       flags = (uint) n.Flags;
+
+                       // don't call GetCurrentDirectory for Run-only builders (CAS may not like that)
+                       if (IsSave && (directory == null || directory.Length == 0)) {
                                dir = Directory.GetCurrentDirectory ();
-                       else
+                       } else {
                                dir = directory;
-                       this.access = (uint)access;
+                       }
 
                        /* Set defaults from n */
                        if (n.CultureInfo != null) {
                                culture = n.CultureInfo.Name;
+                               versioninfo_culture = n.CultureInfo.Name;
                        }
                        Version v = n.Version;
                        if (v != null) {
@@ -133,8 +306,7 @@ namespace System.Reflection.Emit {
                        if (n.KeyPair != null) {
                                // full keypair is available (for signing)
                                sn = n.KeyPair.StrongName ();
-                       }
-                       else {
+                       } else {
                                // public key is available (for delay-signing)
                                byte[] pk = n.GetPublicKey ();
                                if ((pk != null) && (pk.Length > 0)) {
@@ -142,6 +314,20 @@ namespace System.Reflection.Emit {
                                }
                        }
 
+                       if (sn != null)
+                               flags |= (uint) AssemblyNameFlags.PublicKey;
+
+                       this.corlib_internal = corlib_internal;
+                       if (sn != null) {
+                               this.pktoken = new byte[sn.PublicKeyToken.Length * 2];
+                               int pkti = 0;
+                               foreach (byte pkb in sn.PublicKeyToken) {
+                                       string part = pkb.ToString("x2");
+                                       this.pktoken[pkti++] = (byte)part[0];
+                                       this.pktoken[pkti++] = (byte)part[1];
+                               }
+                       }
+
                        basic_init (this);
                }
 
@@ -163,14 +349,17 @@ namespace System.Reflection.Emit {
                        }
                }
 
-#if NET_1_1
                /* This is to keep signature compatibility with MS.NET */
                public override string ImageRuntimeVersion {
                        get {
                                return base.ImageRuntimeVersion;
                        }
                }
-#endif
+
+               [MonoTODO]
+               public override bool ReflectionOnly {
+                       get { return base.ReflectionOnly; }
+               }
 
                public void AddResourceFile (string name, string fileName)
                {
@@ -204,12 +393,48 @@ namespace System.Reflection.Emit {
                        resources [p].attrs = attribute;
                }
 
+               /// <summary>
+               /// Don't change the method name and parameters order. It is used by mcs 
+               /// </summary>
+               internal void AddPermissionRequests (PermissionSet required, PermissionSet optional, PermissionSet refused)
+               {
+#if !NET_2_1
+                       if (created)
+                               throw new InvalidOperationException ("Assembly was already saved.");
+
+                       // required for base Assembly class (so the permissions
+                       // can be used even if the assembly isn't saved to disk)
+                       _minimum = required;
+                       _optional = optional;
+                       _refuse = refused;
+
+                       // required to reuse AddDeclarativeSecurity support 
+                       // already present in the runtime
+                       if (required != null) {
+                               permissions_minimum = new RefEmitPermissionSet [1];
+                               permissions_minimum [0] = new RefEmitPermissionSet (
+                                       SecurityAction.RequestMinimum, required.ToXml ().ToString ());
+                       }
+                       if (optional != null) {
+                               permissions_optional = new RefEmitPermissionSet [1];
+                               permissions_optional [0] = new RefEmitPermissionSet (
+                                       SecurityAction.RequestOptional, optional.ToXml ().ToString ());
+                       }
+                       if (refused != null) {
+                               permissions_refused = new RefEmitPermissionSet [1];
+                               permissions_refused [0] = new RefEmitPermissionSet (
+                                       SecurityAction.RequestRefuse, refused.ToXml ().ToString ());
+                       }
+#endif
+               }
+
+               // Still in use by al.exe
                internal void EmbedResourceFile (string name, string fileName)
                {
                        EmbedResourceFile (name, fileName, ResourceAttributes.Public);
                }
 
-               internal void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
+               void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
                {
                        if (resources != null) {
                                MonoResource[] new_r = new MonoResource [resources.Length + 1];
@@ -228,10 +453,9 @@ namespace System.Reflection.Emit {
                                s.Read (resources [p].data, 0, (int)len);
                                s.Close ();
                        } catch {
-                               /* do something */
                        }
                }
-
+/*
                internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
                {
                        if (resources != null) {
@@ -246,6 +470,22 @@ namespace System.Reflection.Emit {
                        resources [p].attrs = attribute;
                        resources [p].data = blob;
                }
+*/
+               internal void AddTypeForwarder (Type t) {
+                       if (t == null)
+                               throw new ArgumentNullException ("t");
+                       if (t.IsNested)
+                               throw new ArgumentException ();
+
+                       if (type_forwarders == null) {
+                               type_forwarders = new Type [1] { t };
+                       } else {
+                               Type[] arr = new Type [type_forwarders.Length + 1];
+                               Array.Copy (type_forwarders, arr, type_forwarders.Length);
+                               arr [type_forwarders.Length] = t;
+                               type_forwarders = arr;
+                       }
+               }
 
                public ModuleBuilder DefineDynamicModule (string name)
                {
@@ -268,8 +508,7 @@ namespace System.Reflection.Emit {
                        return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
                }
 
-               private ModuleBuilder DefineDynamicModule (string name, string fileName,
-                                                                                                  bool emitSymbolInfo, bool transient)
+               private ModuleBuilder DefineDynamicModule (string name, string fileName, bool emitSymbolInfo, bool transient)
                {
                        check_name_and_filename (name, fileName, false);
 
@@ -357,15 +596,22 @@ namespace System.Reflection.Emit {
                        win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ());
                }
 
-               [MonoTODO]
+               [MonoTODO ("Not currently implemenented")]
                public void DefineUnmanagedResource (byte[] resource)
                {
                        if (resource == null)
                                throw new ArgumentNullException ("resource");
+                       if (native_resource != NativeResourceType.None)
+                               throw new ArgumentException ("Native resource has already been defined.");
+
+                       // avoid definition of more than one unmanaged resource
+                       native_resource = NativeResourceType.Unmanaged;
 
                        /*
                         * The format of the argument byte array is not documented
                         * so this method is impossible to implement.
+                        *
+                        * https://connect.microsoft.com/VisualStudio/feedback/details/95784/fatal-assemblybuilder-defineunmanagedresource-byte-and-modulebuilder-defineunmanagedresource-byte-bugs-renders-them-useless
                         */
 
                        throw new NotImplementedException ();
@@ -375,12 +621,17 @@ namespace System.Reflection.Emit {
                {
                        if (resourceFileName == null)
                                throw new ArgumentNullException ("resourceFileName");
-                       if (resourceFileName == String.Empty)
+                       if (resourceFileName.Length == 0)
                                throw new ArgumentException ("resourceFileName");
                        if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
                                throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory.");
+                       if (native_resource != NativeResourceType.None)
+                               throw new ArgumentException ("Native resource has already been defined.");
+
+                       // avoid definition of more than one unmanaged resource
+                       native_resource = NativeResourceType.Unmanaged;
 
-                       using (FileStream fs = new FileStream (resourceFileName, FileMode.Open)) {
+                       using (FileStream fs = new FileStream (resourceFileName, FileMode.Open, FileAccess.Read)) {
                                Win32ResFileReader reader = new Win32ResFileReader (fs);
 
                                foreach (Win32EncodedResource res in reader.ReadResources ()) {
@@ -394,54 +645,35 @@ namespace System.Reflection.Emit {
 
                public void DefineVersionInfoResource ()
                {
-                       if (version_res != null)
-                               throw new ArgumentException ("Native resource has already been defined.");                      
+                       if (native_resource != NativeResourceType.None)
+                               throw new ArgumentException ("Native resource has already been defined.");
 
-                       version_res = new Win32VersionResource (1, 0);
+                       // avoid definition of more than one unmanaged resource
+                       native_resource = NativeResourceType.Assembly;
 
-                       if (cattrs != null) {
-                               foreach (CustomAttributeBuilder cb in cattrs) {
-                                       string attrname = cb.Ctor.ReflectedType.FullName;
-
-                                       if (attrname == "System.Reflection.AssemblyProductAttribute")
-                                               version_res.ProductName = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
-                                               version_res.CompanyName = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
-                                               version_res.LegalCopyright = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
-                                               version_res.LegalTrademarks = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyCultureAttribute")
-                                               version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
-                                       else if (attrname == "System.Reflection.AssemblyFileVersionAttribute")
-                                               version_res.FileVersion = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
-                                               version_res.ProductVersion = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyTitleAttribute")
-                                               version_res.FileDescription = cb.string_arg ();
-                                       else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
-                                               version_res.Comments = cb.string_arg ();
-                               }
-                       }
+                       version_res = new Win32VersionResource (1, 0, IsCompilerContext);
                }
 
                public void DefineVersionInfoResource (string product, string productVersion,
                                                       string company, string copyright, string trademark)
                {
-                       if (version_res != null)
+                       if (native_resource != NativeResourceType.None)
                                throw new ArgumentException ("Native resource has already been defined.");
 
+                       // avoid definition of more than one unmanaged resource
+                       native_resource = NativeResourceType.Explicit;
+
                        /*
                         * We can only create the resource later, when the file name and
                         * the binary version is known.
                         */
 
-                       version_res = new Win32VersionResource (1, 0);
-                       version_res.ProductName = product;
-                       version_res.ProductVersion = productVersion;
-                       version_res.CompanyName = company;
-                       version_res.LegalCopyright = copyright;
-                       version_res.LegalTrademarks = trademark;
+                       version_res = new Win32VersionResource (1, 0, false);
+                       version_res.ProductName = product != null ? product : " ";
+                       version_res.ProductVersion = productVersion != null ? productVersion : " ";
+                       version_res.CompanyName = company != null ? company : " ";
+                       version_res.LegalCopyright = copyright != null ? copyright : " ";
+                       version_res.LegalTrademarks = trademark != null ? trademark : " ";
                }
 
                /* 
@@ -451,12 +683,12 @@ namespace System.Reflection.Emit {
                {
                        if (iconFileName == null)
                                throw new ArgumentNullException ("iconFileName");
-                       if (iconFileName == String.Empty)
+                       if (iconFileName.Length == 0)
                                throw new ArgumentException ("iconFileName");
                        if (!File.Exists (iconFileName) || Directory.Exists (iconFileName))
                                throw new FileNotFoundException ("File '" + iconFileName + "' does not exists or is a directory.");
 
-                       using (FileStream fs = new FileStream (iconFileName, FileMode.Open)) {
+                       using (FileStream fs = new FileStream (iconFileName, FileMode.Open, FileAccess.Read)) {
                                Win32IconFileReader reader = new Win32IconFileReader (fs);
                                
                                ICONDIRENTRY[] entries = reader.ReadIcons ();
@@ -472,13 +704,65 @@ namespace System.Reflection.Emit {
                        }
                }
 
-               private void DefineVersionInfoResourceImpl (string fileName) {
-                       // Add missing info
-                       if (version_res.FileVersion == "0.0.0.0")
-                               version_res.FileVersion = version;
-                       version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
+               private void DefineVersionInfoResourceImpl (string fileName)
+               {
+                       if (versioninfo_culture != null)
+                               version_res.FileLanguage = new CultureInfo (versioninfo_culture).LCID;
+                       version_res.Version = version == null ? "0.0.0.0" : version;
+
+                       if (cattrs != null) {
+                               switch (native_resource) {
+                               case NativeResourceType.Assembly:
+                                       foreach (CustomAttributeBuilder cb in cattrs) {
+                                               string attrname = cb.Ctor.ReflectedType.FullName;
+
+                                               if (attrname == "System.Reflection.AssemblyProductAttribute")
+                                                       version_res.ProductName = cb.string_arg ();
+                                               else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
+                                                       version_res.CompanyName = cb.string_arg ();
+                                               else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
+                                                       version_res.LegalCopyright = cb.string_arg ();
+                                               else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
+                                                       version_res.LegalTrademarks = cb.string_arg ();
+                                               else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
+                                                       if (!IsCompilerContext)
+                                                               version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
+                                               } else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") {
+                                                       string fileversion = cb.string_arg ();
+                                                       if (!IsCompilerContext || fileversion != null && fileversion.Length != 0)
+                                                               version_res.FileVersion = fileversion;
+                                               } else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
+                                                       version_res.ProductVersion = cb.string_arg ();
+                                               else if (attrname == "System.Reflection.AssemblyTitleAttribute")
+                                                       version_res.FileDescription = cb.string_arg ();
+                                               else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
+                                                       version_res.Comments = cb.string_arg ();
+                                       }
+                                       break;
+                               case NativeResourceType.Explicit:
+                                       foreach (CustomAttributeBuilder cb in cattrs) {
+                                               string attrname = cb.Ctor.ReflectedType.FullName;
+
+                                               if (attrname == "System.Reflection.AssemblyCultureAttribute") {
+                                                       if (!IsCompilerContext)
+                                                               version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
+                                               } else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
+                                                       version_res.Comments = cb.string_arg ();
+                                       }
+                                       break;
+                               }
+                       }
+
                        version_res.OriginalFilename = fileName;
 
+                       if (IsCompilerContext) {
+                               version_res.InternalName = fileName;
+                               if (version_res.ProductVersion.Trim ().Length == 0)
+                                       version_res.ProductVersion = version_res.FileVersion;
+                       } else {
+                               version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
+                       }
+
                        AddUnmanagedResource (version_res);
                }
 
@@ -486,8 +770,8 @@ namespace System.Reflection.Emit {
                {
                        if (name == null)
                                throw new ArgumentNullException ("name");
-                       if (name == "")
-                               throw new ArgumentException ("Name can't be null");
+                       if (name.Length == 0)
+                               throw new ArgumentException ("Empty name is not legal.", "name");
 
                        if (modules != null)
                                for (int i = 0; i < modules.Length; ++i)
@@ -510,6 +794,56 @@ namespace System.Reflection.Emit {
                        throw not_supported ();
                }
 
+               internal override Module[] GetModulesInternal () {
+                       if (modules == null)
+                               return new Module [0];
+                       else
+                               return (Module[])modules.Clone ();
+               }
+
+               internal override Type[] GetTypes (bool exportedOnly) {
+                       Type[] res = null;
+                       if (modules != null) {
+                               for (int i = 0; i < modules.Length; ++i) {
+                                       Type[] types = modules [i].GetTypes ();
+                                       if (res == null)
+                                               res = types;
+                                       else {
+                                               Type[] tmp = new Type [res.Length + types.Length];
+                                               Array.Copy (res, 0, tmp, 0, res.Length);
+                                               Array.Copy (types, 0, tmp, res.Length, types.Length);
+                                       }
+                               }
+                       }
+                       if (loaded_modules != null) {
+                               for (int i = 0; i < loaded_modules.Length; ++i) {
+                                       Type[] types = loaded_modules [i].GetTypes ();
+                                       if (res == null)
+                                               res = types;
+                                       else {
+                                               Type[] tmp = new Type [res.Length + types.Length];
+                                               Array.Copy (res, 0, tmp, 0, res.Length);
+                                               Array.Copy (types, 0, tmp, res.Length, types.Length);
+                                       }
+                               }
+                       }
+
+                       if (res != null) {
+                               List<Exception> exceptions = null;
+                               foreach (var type in res) {
+                                       if (type is TypeBuilder) {
+                                               if (exceptions == null)
+                                                       exceptions = new List <Exception> ();
+                                               exceptions.Add (new TypeLoadException (string.Format ("Type '{0}' is not finished", type.FullName))); 
+                                       }
+                               }
+                               if (exceptions != null)
+                                       throw new ReflectionTypeLoadException (new Type [exceptions.Count], exceptions.ToArray ());
+                       }
+                       
+                       return res == null ? Type.EmptyTypes : res;
+               }
+
                public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
                        throw not_supported ();
                }
@@ -525,12 +859,32 @@ namespace System.Reflection.Emit {
                        throw not_supported ();
                }
 
+               /*
+                * This is set when the the AssemblyBuilder is created by (g)mcs
+                * or vbnc.
+                */
+               internal bool IsCompilerContext
+               {
+                       get { return is_compiler_context; }
+               }
+
                internal bool IsSave {
                        get {
                                return access != (uint)AssemblyBuilderAccess.Run;
                        }
                }
 
+               internal bool IsRun {
+                       get {
+                               return access == (uint)AssemblyBuilderAccess.Run || access == (uint)AssemblyBuilderAccess.RunAndSave
+#if NET_4_0
+                                        || access == (uint)AssemblyBuilderAccess.RunAndCollect
+#endif
+                               ;
+
+                       }
+               }
+
                internal string AssemblyDir {
                        get {
                                return dir;
@@ -551,8 +905,30 @@ namespace System.Reflection.Emit {
                        }
                }
 
-               public void Save (string assemblyFileName)
+               ModuleBuilder manifest_module;
+
+               //
+               // MS.NET seems to return a ModuleBuilder when GetManifestModule () is called
+               // on an assemblybuilder.
+               //
+               internal override Module GetManifestModule () {
+                       if (manifest_module == null)
+                               manifest_module = DefineDynamicModule ("Default Dynamic Module");
+                       return manifest_module;
+               }
+
+               [MonoLimitation ("No support for PE32+ assemblies for AMD64 and IA64")]
+               public 
+               void Save (string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
                {
+                       this.peKind = portableExecutableKind;
+                       this.machine = imageFileMachine;
+
+                       if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || (peKind & PortableExecutableKinds.Unmanaged32Bit) != 0)
+                               throw new NotImplementedException (peKind.ToString ());
+                       if (machine == ImageFileMachine.IA64 || machine == ImageFileMachine.AMD64)
+                               throw new NotImplementedException (machine.ToString ());
+
                        if (resource_writers != null) {
                                foreach (IResourceWriter writer in resource_writers) {
                                        writer.Generate ();
@@ -582,7 +958,7 @@ namespace System.Reflection.Emit {
                                if (entry_point.GetParameters ().Length == 1)
                                        paramTypes = new Type [] { typeof (string) };
                                else
-                                       paramTypes = new Type [0];
+                                       paramTypes = Type.EmptyTypes;
 
                                MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes);
                                ILGenerator ilgen = mb.GetILGenerator ();
@@ -618,6 +994,11 @@ namespace System.Reflection.Emit {
                        created = true;
                }
 
+               public void Save (string assemblyFileName)
+               {
+                       Save (assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
+               }
+
                public void SetEntryPoint (MethodInfo entryMethod)
                {
                        SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
@@ -639,30 +1020,35 @@ namespace System.Reflection.Emit {
                        if (customBuilder == null)
                                throw new ArgumentNullException ("customBuilder");
 
-                       string attrname = customBuilder.Ctor.ReflectedType.FullName;
-                       byte[] data;
-                       int pos;
-
-                       if (attrname == "System.Reflection.AssemblyVersionAttribute") {
-                               version = create_assembly_version (customBuilder.string_arg ());
-                               return;
-                       } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
-                               culture = customBuilder.string_arg ();
-                       } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
-                               data = customBuilder.Data;
-                               pos = 2;
-                               algid = (uint)data [pos];
-                               algid |= ((uint)data [pos + 1]) << 8;
-                               algid |= ((uint)data [pos + 2]) << 16;
-                               algid |= ((uint)data [pos + 3]) << 24;
-                       } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
-                               data = customBuilder.Data;
-                               pos = 2;
-                               flags = (uint)data [pos];
-                               flags |= ((uint)data [pos + 1]) << 8;
-                               flags |= ((uint)data [pos + 2]) << 16;
-                               flags |= ((uint)data [pos + 3]) << 24;
-                               return;
+                       if (IsCompilerContext) {
+                               string attrname = customBuilder.Ctor.ReflectedType.FullName;
+                               byte [] data;
+                               int pos;
+
+                               if (attrname == "System.Reflection.AssemblyVersionAttribute") {
+                                       version = create_assembly_version (customBuilder.string_arg ());
+                                       return;
+                               } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
+                                       culture = GetCultureString (customBuilder.string_arg ());
+                               } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
+                                       data = customBuilder.Data;
+                                       pos = 2;
+                                       algid = (uint) data [pos];
+                                       algid |= ((uint) data [pos + 1]) << 8;
+                                       algid |= ((uint) data [pos + 2]) << 16;
+                                       algid |= ((uint) data [pos + 3]) << 24;
+                               } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
+                                       data = customBuilder.Data;
+                                       pos = 2;
+                                       flags |= (uint) data [pos];
+                                       flags |= ((uint) data [pos + 1]) << 8;
+                                       flags |= ((uint) data [pos + 2]) << 16;
+                                       flags |= ((uint) data [pos + 3]) << 24;
+
+                                       // ignore PublicKey flag if assembly is not strongnamed
+                                       if (sn == null)
+                                               flags &= ~(uint) AssemblyNameFlags.PublicKey;
+                               }
                        }
 
                        if (cattrs != null) {
@@ -676,6 +1062,7 @@ namespace System.Reflection.Emit {
                        }
                }
 
+               [ComVisible (true)]
                public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
                        if (con == null)
                                throw new ArgumentNullException ("con");
@@ -708,12 +1095,12 @@ namespace System.Reflection.Emit {
                                throw new ArgumentNullException ("name");
                        if (fileName == null)
                                throw new ArgumentNullException ("fileName");
-                       if (name == "")
-                               throw new ArgumentException ("name cannot be empty", "name");
-                       if (fileName == "")
-                               throw new ArgumentException ("fileName cannot be empty", "fileName");
+                       if (name.Length == 0)
+                               throw new ArgumentException ("Empty name is not legal.", "name");
+                       if (fileName.Length == 0)
+                               throw new ArgumentException ("Empty file name is not legal.", "fileName");
                        if (Path.GetFileName (fileName) != fileName)
-                               throw new ArgumentException ("fileName '" + fileName + "' must not include a path.");
+                               throw new ArgumentException ("fileName '" + fileName + "' must not include a path.", "fileName");
 
                        // Resource files are created/searched under the assembly storage
                        // directory
@@ -778,5 +1165,143 @@ namespace System.Reflection.Emit {
 
                        return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];
                }
+
+               private string GetCultureString (string str)
+               {
+                       return (str == "neutral" ? String.Empty : str);
+               }
+
+               internal override AssemblyName UnprotectedGetName ()
+               {
+                       AssemblyName an = base.UnprotectedGetName ();
+                       if (sn != null) {
+                               an.SetPublicKey (sn.PublicKey);
+                               an.SetPublicKeyToken (sn.PublicKeyToken);
+                       }
+                       return an;
+               }
+
+               /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
+               internal Type MakeGenericType (Type gtd, Type[] typeArguments)
+               {
+                       if (!IsCompilerContext)
+                               return new MonoGenericClass (gtd, typeArguments);
+
+                       GenericInstanceKey key = new GenericInstanceKey (gtd, typeArguments);
+                       MonoGenericClass res = (MonoGenericClass)generic_instances [key];
+                       if (res == null) {
+                               res = new MonoGenericClass (gtd, typeArguments);
+                               generic_instances [key] = res;
+                       }
+                       return res;
+               }
+
+               void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _AssemblyBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _AssemblyBuilder.GetTypeInfoCount (out uint pcTInfo)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _AssemblyBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
+               {
+                       throw new NotImplementedException ();
+               }
+
+#if NET_4_0 || MOONLIGHT
+               public override Type GetType (string name, bool throwOnError, bool ignoreCase)
+               {
+                       if (name == null)
+                               throw new ArgumentNullException (name);
+                       if (name.Length == 0)
+                       throw new ArgumentException ("name", "Name cannot be empty");
+
+                       var res = InternalGetType (null, name, throwOnError, ignoreCase);
+                       if (res is TypeBuilder) {
+                               if (throwOnError)
+                                       throw new TypeLoadException (string.Format ("Could not load type '{0}' from assembly '{1}'", name, this.name));
+                               return null;
+                       }
+                       return res;
+               }
+
+               public override Module GetModule (String name)
+               {
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+                       if (name.Length == 0)
+                               throw new ArgumentException ("Name can't be empty");
+
+                       if (modules == null)
+                               return null;
+
+                       foreach (Module module in modules) {
+                               if (module.ScopeName == name)
+                                       return module;
+                       }
+
+                       return null;
+               }
+
+               public override Module[] GetModules (bool getResourceModules)
+               {
+                       Module[] modules = GetModulesInternal ();
+
+                       if (!getResourceModules) {
+                               var result = new List<Module> (modules.Length);
+                               foreach (Module m in modules)
+                                       if (!m.IsResource ())
+                                               result.Add (m);
+                               return result.ToArray ();
+                       }
+                       return modules;
+               }
+
+               [MonoTODO ("This always returns an empty array")]
+               public override AssemblyName[] GetReferencedAssemblies () {
+                       return GetReferencedAssemblies (this);
+               }
+
+               public override Module[] GetLoadedModules (bool getResourceModules)
+               {
+                       return GetModules (getResourceModules);
+               }
+
+               //FIXME MS has issues loading satelite assemblies from SRE
+               public override Assembly GetSatelliteAssembly (CultureInfo culture)
+               {
+                       return GetSatelliteAssembly (culture, null, true);
+               }
+
+               //FIXME MS has issues loading satelite assemblies from SRE
+               public override Assembly GetSatelliteAssembly (CultureInfo culture, Version version)
+               {
+                       return GetSatelliteAssembly (culture, version, true);
+               }
+
+               public override Module ManifestModule {
+                       get {
+                               return GetManifestModule ();
+                       }
+               }
+
+               public override bool GlobalAssemblyCache {
+                       get {
+                               return false;
+                       }
+               }
+
+               public override bool IsDynamic {
+                       get { return true; }
+               }
+#endif
        }
 }