New tests.
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ModuleBuilder.cs
index 36820b23c9f14cb8554d783ecef9b5da02fcc154..8033613647b05c858e120c66f8bd54dd4bde8741 100644 (file)
@@ -34,6 +34,7 @@
 using System;
 using System.Reflection;
 using System.Collections;
+using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Diagnostics.SymbolStore;
@@ -42,14 +43,14 @@ using System.Resources;
 using System.Globalization;
 
 namespace System.Reflection.Emit {
-#if NET_2_0
        [ComVisible (true)]
        [ComDefaultInterface (typeof (_ModuleBuilder))]
-#endif
        [ClassInterface (ClassInterfaceType.None)]
        public class ModuleBuilder : Module, _ModuleBuilder {
-               #region Sync with reflection.h
-               private IntPtr dynamic_image;
+
+#pragma warning disable 169, 414
+               #region Sync with object-internals.h
+               private UIntPtr dynamic_image; /* GC-tracked */
                private int num_types;
                private TypeBuilder[] types;
                private CustomAttributeBuilder[] cattrs;
@@ -61,19 +62,24 @@ namespace System.Reflection.Emit {
                bool is_main;
                private MonoResource[] resources;
                #endregion
+#pragma warning restore 169, 414
+               
                private TypeBuilder global_type;
                private Type global_type_created;
                Hashtable name_cache;
-               Hashtable us_string_cache = new Hashtable ();
+               Dictionary<string, int> us_string_cache;
                private int[] table_indexes;
                bool transient;
                ModuleBuilderTokenGenerator token_gen;
-               ArrayList resource_writers = null;
+               Hashtable resource_writers;
                ISymbolWriter symbolWriter;
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private static extern void basic_init (ModuleBuilder ab);
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private static extern void set_wrappers_type (ModuleBuilder mb, Type ab);
+
                internal ModuleBuilder (AssemblyBuilder assb, string name, string fullyqname, bool emitSymbolInfo, bool transient) {
                        this.name = this.scopename = name;
                        this.fqname = fullyqname;
@@ -84,21 +90,36 @@ namespace System.Reflection.Emit {
                        // guid = Guid.NewGuid().ToByteArray ();
                        table_idx = get_next_table_index (this, 0x00, true);
                        name_cache = new Hashtable ();
+                       us_string_cache = new Dictionary<string, int> (512);
 
                        basic_init (this);
 
                        CreateGlobalType ();
-                       
+
+                       if (assb.IsRun) {
+                               TypeBuilder tb = new TypeBuilder (this, TypeAttributes.Abstract, 0xFFFFFF); /*last valid token*/
+                               Type type = tb.CreateType ();
+                               set_wrappers_type (this, type);
+                       }
+
                        if (emitSymbolInfo) {
+#if MOONLIGHT
+                               symbolWriter = new Mono.CompilerServices.SymbolWriter.SymbolWriterImpl (this);
+#else
                                Assembly asm = Assembly.LoadWithPartialName ("Mono.CompilerServices.SymbolWriter");
+                               if (asm == null)
+                                       throw new ExecutionEngineException ("The assembly for default symbol writer cannot be loaded");
+
                                Type t = asm.GetType ("Mono.CompilerServices.SymbolWriter.SymbolWriterImpl");
-                               if (t != null) {
-                                       symbolWriter = (ISymbolWriter) Activator.CreateInstance (t, new object[] { this });
-                                       string fileName = fqname;
-                                       if (assemblyb.AssemblyDir != null)
-                                               fileName = Path.Combine (assemblyb.AssemblyDir, fileName);
-                                       symbolWriter.Initialize (IntPtr.Zero, fileName, true);
-                               }
+                               if (t == null)
+                                       throw new ExecutionEngineException ("The type that implements the default symbol writer interface cannot be found");
+
+                               symbolWriter = (ISymbolWriter) Activator.CreateInstance (t, new object[] { this });
+#endif
+                               string fileName = fqname;
+                               if (assemblyb.AssemblyDir != null)
+                                       fileName = Path.Combine (assemblyb.AssemblyDir, fileName);
+                               symbolWriter.Initialize (IntPtr.Zero, fileName, true);
                        }
                }
 
@@ -127,13 +148,16 @@ namespace System.Reflection.Emit {
                        return fb;
                }
 
-               public FieldBuilder DefineUninitializedData( string name, int size, FieldAttributes attributes) {
+               public FieldBuilder DefineUninitializedData (string name, int size, FieldAttributes attributes)
+               {
                        if (name == null)
                                throw new ArgumentNullException ("name");
                        if (global_type_created != null)
                                throw new InvalidOperationException ("global fields already created");
-                       if (global_type == null)
-                               global_type = new TypeBuilder (this, 0);
+                       if ((size <= 0) || (size > 0x3f0000))
+                               throw new ArgumentException ("size", "Data size must be > 0 and < 0x3f0000");
+
+                       CreateGlobalType ();
 
                        string typeName = "$ArrayType$" + size;
                        Type datablobtype = GetType (typeName, false, false);
@@ -179,12 +203,7 @@ namespace System.Reflection.Emit {
                        return DefineGlobalMethod (name, attributes, callingConvention, returnType, null, null, parameterTypes, null, null);
                }
 
-#if NET_2_0 || BOOTSTRAP_NET_2_0
-               public
-#else
-               internal
-#endif
-               MethodBuilder DefineGlobalMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
+               public MethodBuilder DefineGlobalMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
                {
                        if (name == null)
                                throw new ArgumentNullException ("name");
@@ -192,8 +211,7 @@ namespace System.Reflection.Emit {
                                throw new ArgumentException ("global methods must be static");
                        if (global_type_created != null)
                                throw new InvalidOperationException ("global methods already created");
-                       if (global_type == null)
-                               global_type = new TypeBuilder (this, 0);
+                       CreateGlobalType ();
                        MethodBuilder mb = global_type.DefineMethod (name, attributes, callingConvention, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
 
                        addGlobalMethod (mb);
@@ -211,8 +229,7 @@ namespace System.Reflection.Emit {
                                throw new ArgumentException ("global methods must be static");
                        if (global_type_created != null)
                                throw new InvalidOperationException ("global methods already created");
-                       if (global_type == null)
-                               global_type = new TypeBuilder (this, 0);
+                       CreateGlobalType ();
                        MethodBuilder mb = global_type.DefinePInvokeMethod (name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
 
                        addGlobalMethod (mb);
@@ -248,23 +265,30 @@ namespace System.Reflection.Emit {
                        num_types ++;
                }
 
-               private TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces, PackingSize packsize, int typesize) {
-                       if (name_cache.Contains (name))
+               private TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces, PackingSize packingSize, int typesize) {
+                       if (name == null)
+                               throw new ArgumentNullException ("fullname");
+                       if (name_cache.ContainsKey (name))
                                throw new ArgumentException ("Duplicate type name within an assembly.");
-
-                       TypeBuilder res = new TypeBuilder (this, name, attr, parent, interfaces, packsize, typesize, null);
+                       TypeBuilder res = new TypeBuilder (this, name, attr, parent, interfaces, packingSize, typesize, null);
                        AddType (res);
+
                        name_cache.Add (name, res);
+                       
                        return res;
                }
 
-               internal void RegisterTypeName (TypeBuilder tb, string name) {
+               internal void RegisterTypeName (TypeBuilder tb, string name)
+               {
                        name_cache.Add (name, tb);
                }
+               
+               internal TypeBuilder GetRegisteredType (string name)
+               {
+                       return (TypeBuilder) name_cache [name];
+               }
 
-#if NET_2_0
                [ComVisible (true)]
-#endif
                public TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces) {
                        return DefineType (name, attr, parent, interfaces, PackingSize.Unspecified, TypeBuilder.UnspecifiedTypeSize);
                }
@@ -277,8 +301,8 @@ namespace System.Reflection.Emit {
                        return DefineType (name, attr, parent, null, packsize, TypeBuilder.UnspecifiedTypeSize);
                }
 
-               public TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, PackingSize packsize, int typesize) {
-                       return DefineType (name, attr, parent, null, packsize, typesize);
+               public TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize) {
+                       return DefineType (name, attr, parent, null, packingSize, typesize);
                }
 
                public MethodInfo GetArrayMethod( Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes) {
@@ -296,16 +320,12 @@ namespace System.Reflection.Emit {
                        return eb;
                }
 
-#if NET_2_0
                [ComVisible (true)]
-#endif
                public override Type GetType( string className) {
                        return GetType (className, false, false);
                }
                
-#if NET_2_0
                [ComVisible (true)]
-#endif
                public override Type GetType( string className, bool ignoreCase) {
                        return GetType (className, false, ignoreCase);
                }
@@ -354,10 +374,14 @@ namespace System.Reflection.Emit {
                        return null;
                }
 
-#if NET_2_0
                [ComVisible (true)]
-#endif         
-               public override Type GetType (string className, bool throwOnError, bool ignoreCase) {
+               public override Type GetType (string className, bool throwOnError, bool ignoreCase)
+               {
+                       if (className == null)
+                               throw new ArgumentNullException ("className");
+                       if (className.Length == 0)
+                               throw new ArgumentException ("className");
+
                        int subt;
                        string orig = className;
                        string modifiers;
@@ -391,9 +415,16 @@ namespace System.Reflection.Emit {
                        }
                        if ((result == null) && throwOnError)
                                throw new TypeLoadException (orig);
-                       if (result != null && (modifiers != null))
-                               return create_modified_type (result, modifiers);
-                       return result;
+                       if (result != null && (modifiers != null)) {
+                               Type mt = create_modified_type (result, modifiers);
+                               result = mt as TypeBuilder;
+                               if (result == null)
+                                       return mt;
+                       }
+                       if (result != null && result.is_created)
+                               return result.CreateType ();
+                       else
+                               return result;
                }
 
                internal int get_next_table_index (object obj, int table, bool inc) {
@@ -422,9 +453,7 @@ namespace System.Reflection.Emit {
                        }
                }
 
-#if NET_2_0
                [ComVisible (true)]
-#endif
                public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
                        SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
                }
@@ -444,12 +473,17 @@ namespace System.Reflection.Emit {
                public override Type [] GetTypes ()
                {
                        if (types == null)
-                               return new TypeBuilder [0];
+                               return Type.EmptyTypes;
 
                        int n = num_types;
-                       TypeBuilder [] copy = new TypeBuilder [n];
+                       Type [] copy = new Type [n];
                        Array.Copy (types, copy, n);
 
+                       // MS replaces the typebuilders with their created types
+                       for (int i = 0; i < copy.Length; ++i)
+                               if (types [i].is_created)
+                                       copy [i] = types [i].CreateType ();
+
                        return copy;
                }
 
@@ -465,8 +499,8 @@ namespace System.Reflection.Emit {
                                throw new InvalidOperationException ("The assembly is transient");
                        ResourceWriter writer = new ResourceWriter (new MemoryStream ());
                        if (resource_writers == null)
-                               resource_writers = new ArrayList ();
-                       resource_writers.Add (writer);
+                               resource_writers = new Hashtable ();
+                       resource_writers [name] = writer;
 
                        // The data is filled out later
                        if (resources != null) {
@@ -510,6 +544,31 @@ namespace System.Reflection.Emit {
                        throw new NotImplementedException ();
                }
 
+               public void DefineManifestResource (string name, Stream stream, ResourceAttributes attribute) {
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+                       if (name == String.Empty)
+                               throw new ArgumentException ("name cannot be empty");
+                       if (stream == null)
+                               throw new ArgumentNullException ("stream");
+                       if (transient)
+                               throw new InvalidOperationException ("The module is transient");
+                       if (!assemblyb.IsSave)
+                               throw new InvalidOperationException ("The assembly is transient");
+
+                       if (resources != null) {
+                               MonoResource[] new_r = new MonoResource [resources.Length + 1];
+                               System.Array.Copy(resources, new_r, resources.Length);
+                               resources = new_r;
+                       } else {
+                               resources = new MonoResource [1];
+                       }
+                       int p = resources.Length - 1;
+                       resources [p].name = name;
+                       resources [p].attrs = attribute;
+                       resources [p].stream = stream;
+               }
+
                [MonoTODO]
                public void SetSymCustomAttribute (string name, byte[] data)
                {
@@ -540,9 +599,7 @@ namespace System.Reflection.Emit {
                        return GetMethodToken (GetArrayMethod (arrayClass, methodName, callingConvention, returnType, parameterTypes));
                }
 
-#if NET_2_0
                [ComVisible (true)]
-#endif
                public MethodToken GetConstructorToken (ConstructorInfo con)
                {
                        if (con == null)
@@ -590,7 +647,7 @@ namespace System.Reflection.Emit {
                        return new TypeToken (GetToken (type));
                }
 
-               public TypeToken GetTypeToken (string type)
+               public TypeToken GetTypeToken (string name)
                {
                        return GetTypeToken (GetType (name));
                }
@@ -605,11 +662,14 @@ namespace System.Reflection.Emit {
                private static extern int getMethodToken (ModuleBuilder mb, MethodInfo method,
                                                          Type[] opt_param_types);
 
-               internal int GetToken (string str) {
-                       if (us_string_cache.Contains (str))
-                               return (int)us_string_cache [str];
-                       int result = getUSIndex (this, str);
-                       us_string_cache [str] = result;
+               internal int GetToken (string str)
+               {
+                       int result;
+                       if (!us_string_cache.TryGetValue (str, out result)) {
+                               result = getUSIndex (this, str);
+                               us_string_cache [str] = result;
+                       }
+                       
                        return result;
                }
 
@@ -625,6 +685,13 @@ namespace System.Reflection.Emit {
                        return getToken (this, helper);
                }
 
+               /*
+                * Register the token->obj mapping with the runtime so the Module.Resolve... 
+                * methods will work for obj.
+                */
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal extern void RegisterToken (object obj, int token);
+
                internal TokenGenerator GetTokenGenerator () {
                        if (token_gen == null)
                                token_gen = new ModuleBuilderTokenGenerator (this);
@@ -651,15 +718,32 @@ namespace System.Reflection.Emit {
                        if ((global_type != null) && (global_type_created == null))
                                global_type_created = global_type.CreateType ();
 
-                       if (resource_writers != null) {
-                               for (int i = 0; i < resource_writers.Count; ++i) {
-                                       ResourceWriter writer = (ResourceWriter)resource_writers [i];
-                                       writer.Generate ();
-                                       MemoryStream stream = (MemoryStream)writer.Stream;
-                                       resources [i].data = new byte [stream.Length];
-                                       stream.Seek (0, SeekOrigin.Begin);
-                                       stream.Read (resources [i].data, 0, (int)stream.Length);
-                               }                                       
+                       if (resources != null) {
+                               for (int i = 0; i < resources.Length; ++i) {
+                                       IResourceWriter rwriter;
+                                       if (resource_writers != null && (rwriter = resource_writers [resources [i].name] as IResourceWriter) != null) {
+                                               ResourceWriter writer = (ResourceWriter)rwriter;
+                                               writer.Generate ();
+                                               MemoryStream mstream = (MemoryStream)writer.Stream;
+                                               resources [i].data = new byte [mstream.Length];
+                                               mstream.Seek (0, SeekOrigin.Begin);
+                                               mstream.Read (resources [i].data, 0, (int)mstream.Length);
+                                               continue;
+                                       }
+                                       Stream stream = resources [i].stream;
+
+                                       // According to MSDN docs, the stream is read during assembly save, not earlier
+                                       if (stream != null) {
+                                               try {
+                                                       long len = stream.Length;
+                                                       resources [i].data = new byte [len];
+                                                       stream.Seek (0, SeekOrigin.Begin);
+                                                       stream.Read (resources [i].data, 0, (int)len);
+                                               } catch {
+                                                       /* do something */
+                                               }
+                                       }
+                               }
                        }
 
                        build_metadata (this);
@@ -667,7 +751,13 @@ namespace System.Reflection.Emit {
                        string fileName = fqname;
                        if (assemblyb.AssemblyDir != null)
                                fileName = Path.Combine (assemblyb.AssemblyDir, fileName);
-                       
+
+                       try {
+                               // We mmap the file, so unlink the previous version since it may be in use
+                               File.Delete (fileName);
+                       } catch {
+                               // We can safely ignore
+                       }
                        using (FileStream file = new FileStream (fileName, FileMode.Create, FileAccess.Write))
                                WriteToFile (file.Handle);
                        
@@ -697,12 +787,18 @@ namespace System.Reflection.Emit {
 
                internal void CreateGlobalType () {
                        if (global_type == null)
-                               global_type = new TypeBuilder (this, 0);
+                               global_type = new TypeBuilder (this, 0, 1);
+               }
+
+               internal override Guid GetModuleVersionId ()
+               {
+                       return new Guid (guid);
                }
 
+               // Used by mcs, the symbol writer, and mdb through reflection
                internal static Guid Mono_GetGuid (ModuleBuilder mb)
                {
-                       return new Guid (mb.guid);
+                       return mb.GetModuleVersionId ();
                }
 
                void _ModuleBuilder.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
@@ -724,6 +820,103 @@ namespace System.Reflection.Emit {
                {
                        throw new NotImplementedException ();
                }
+
+#if NET_4_0
+               public override Assembly Assembly {
+                       get { return assemblyb; }
+               }
+
+               public override string Name {
+                       get { return name; }
+               }
+
+               public override string ScopeName {
+                       get { return name; }
+               }
+
+               public override Guid ModuleVersionId {
+                       get {
+                               return GetModuleVersionId ();
+                       }
+               }
+
+               //XXX resource modules can't be defined with ModuleBuilder
+               public override bool IsResource ()
+               {
+                       return false;
+               }
+
+               protected override MethodInfo GetMethodImpl (string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) 
+               {
+                       if (global_type_created == null)
+                               return null;
+                       if (types == null)
+                               return global_type_created.GetMethod (name);
+                       return global_type_created.GetMethod (name, bindingAttr, binder, callConvention, types, modifiers);
+               }
+
+               public override FieldInfo ResolveField (int metadataToken, Type [] genericTypeArguments, Type [] genericMethodArguments) {
+                       ResolveTokenError error;
+
+                       IntPtr handle = ResolveFieldToken (_impl, metadataToken, ptrs_from_types (genericTypeArguments), ptrs_from_types (genericMethodArguments), out error);
+                       if (handle == IntPtr.Zero)
+                               throw resolve_token_exception (metadataToken, error, "Field");
+                       else
+                               return FieldInfo.GetFieldFromHandle (new RuntimeFieldHandle (handle));
+               }
+
+               public override MemberInfo ResolveMember (int metadataToken, Type [] genericTypeArguments, Type [] genericMethodArguments) {
+
+                       ResolveTokenError error;
+
+                       MemberInfo m = ResolveMemberToken (_impl, metadataToken, ptrs_from_types (genericTypeArguments), ptrs_from_types (genericMethodArguments), out error);
+                       if (m == null)
+                               throw resolve_token_exception (metadataToken, error, "MemberInfo");
+                       else
+                               return m;
+               }
+
+               public override MethodBase ResolveMethod (int metadataToken, Type [] genericTypeArguments, Type [] genericMethodArguments) {
+                       ResolveTokenError error;
+
+                       IntPtr handle = ResolveMethodToken (_impl, metadataToken, ptrs_from_types (genericTypeArguments), ptrs_from_types (genericMethodArguments), out error);
+                       if (handle == IntPtr.Zero)
+                               throw resolve_token_exception (metadataToken, error, "MethodBase");
+                       else
+                               return MethodBase.GetMethodFromHandleNoGenericCheck (new RuntimeMethodHandle (handle));
+               }
+
+               public override string ResolveString (int metadataToken) {
+                       ResolveTokenError error;
+
+                       string s = ResolveStringToken (_impl, metadataToken, out error);
+                       if (s == null)
+                               throw resolve_token_exception (metadataToken, error, "string");
+                       else
+                               return s;
+               }
+
+               public override byte[] ResolveSignature (int metadataToken) {
+                       ResolveTokenError error;
+
+                   byte[] res = ResolveSignature (_impl, metadataToken, out error);
+                       if (res == null)
+                               throw resolve_token_exception (metadataToken, error, "signature");
+                       else
+                               return res;
+               }
+
+               public override Type ResolveType (int metadataToken, Type [] genericTypeArguments, Type [] genericMethodArguments) {
+                       ResolveTokenError error;
+
+                       IntPtr handle = ResolveTypeToken (_impl, metadataToken, ptrs_from_types (genericTypeArguments), ptrs_from_types (genericMethodArguments), out error);
+                       if (handle == IntPtr.Zero)
+                               throw resolve_token_exception (metadataToken, error, "Type");
+                       else
+                               return Type.GetTypeFromHandle (new RuntimeTypeHandle (handle));
+               }
+
+#endif
        }
 
        internal class ModuleBuilderTokenGenerator : TokenGenerator {