In Assembly:
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ModuleBuilder.cs
index abc01249b8c7b9006f74bd357d8297e75dedb59b..672be8b6b6129c6830d81650b440bb8dc32d7280 100644 (file)
@@ -42,9 +42,14 @@ using System.Resources;
 using System.Globalization;
 
 namespace System.Reflection.Emit {
-       public class ModuleBuilder : Module {
-               #region Sync with reflection.h
-               private IntPtr dynamic_image;
+       [ComVisible (true)]
+       [ComDefaultInterface (typeof (_ModuleBuilder))]
+       [ClassInterface (ClassInterfaceType.None)]
+       public class ModuleBuilder : Module, _ModuleBuilder {
+
+#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;
@@ -56,6 +61,8 @@ 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;
@@ -63,11 +70,15 @@ namespace System.Reflection.Emit {
                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;
@@ -82,6 +93,32 @@ namespace System.Reflection.Emit {
                        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 NET_2_1 && !MONOTOUCH
+                               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)
+                                       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);
+                       }
                }
 
                public override string FullyQualifiedName {get { return fqname;}}
@@ -109,13 +146,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);
@@ -161,12 +201,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");
@@ -174,8 +209,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);
@@ -193,8 +227,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);
@@ -206,6 +239,8 @@ namespace System.Reflection.Emit {
                }
 
                public TypeBuilder DefineType (string name, TypeAttributes attr) {
+                       if ((attr & TypeAttributes.Interface) != 0)
+                               return DefineType (name, attr, null, null);
                        return DefineType (name, attr, typeof(object), null);
                }
 
@@ -213,11 +248,8 @@ namespace System.Reflection.Emit {
                        return DefineType (name, attr, parent, null);
                }
 
-               private TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces, PackingSize packsize, int typesize) {
-                       if (name_cache.Contains (name))
-                               throw new ArgumentException ("Duplicate type name within an assembly.");
-
-                       TypeBuilder res = new TypeBuilder (this, name, attr, parent, interfaces, packsize, typesize, null);
+               private void AddType (TypeBuilder tb)
+               {
                        if (types != null) {
                                if (types.Length == num_types) {
                                        TypeBuilder[] new_types = new TypeBuilder [types.Length * 2];
@@ -227,16 +259,34 @@ namespace System.Reflection.Emit {
                        } else {
                                types = new TypeBuilder [1];
                        }
-                       types [num_types] = res;
+                       types [num_types] = tb;
                        num_types ++;
-                       name_cache.Add (name, res);
+               }
+
+               private TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces, PackingSize packingSize, int typesize) {
+                       TypeBuilder res = new TypeBuilder (this, name, attr, parent, interfaces, packingSize, typesize, null);
+                       AddType (res);
+                       
+                       try {
+                               name_cache.Add (name, res);
+                       } catch {
+                               throw new ArgumentException ("Duplicate type name within an assembly.");
+                       }
+                       
                        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];
+               }
 
+               [ComVisible (true)]
                public TypeBuilder DefineType (string name, TypeAttributes attr, Type parent, Type[] interfaces) {
                        return DefineType (name, attr, parent, interfaces, PackingSize.Unspecified, TypeBuilder.UnspecifiedTypeSize);
                }
@@ -249,8 +299,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) {
@@ -258,14 +308,22 @@ namespace System.Reflection.Emit {
                }
 
                public EnumBuilder DefineEnum( string name, TypeAttributes visibility, Type underlyingType) {
+                       if (name_cache.Contains (name))
+                               throw new ArgumentException ("Duplicate type name within an assembly.");
+
                        EnumBuilder eb = new EnumBuilder (this, name, visibility, underlyingType);
+                       TypeBuilder res = eb.GetTypeBuilder ();
+                       AddType (res);
+                       name_cache.Add (name, res);
                        return eb;
                }
 
+               [ComVisible (true)]
                public override Type GetType( string className) {
                        return GetType (className, false, false);
                }
                
+               [ComVisible (true)]
                public override Type GetType( string className, bool ignoreCase) {
                        return GetType (className, false, ignoreCase);
                }
@@ -313,8 +371,15 @@ namespace System.Reflection.Emit {
                        }
                        return null;
                }
-               
-               public override Type GetType (string className, bool throwOnError, bool ignoreCase) {
+
+               [ComVisible (true)]
+               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;
@@ -348,9 +413,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) {
@@ -378,27 +450,38 @@ namespace System.Reflection.Emit {
                                cattrs [0] = customBuilder;
                        }
                }
+
+               [ComVisible (true)]
                public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
                        SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
                }
 
                public ISymbolWriter GetSymWriter () {
-                       return null;
+                       return symbolWriter;
                }
 
-               public ISymbolDocumentWriter DefineDocument (string url, Guid language, Guid languageVendor, Guid documentType) {
-                       return null;
+               public ISymbolDocumentWriter DefineDocument (string url, Guid language, Guid languageVendor, Guid documentType)
+               {
+                       if (symbolWriter != null)
+                               return symbolWriter.DefineDocument (url, language, languageVendor, documentType);
+                       else
+                               return null;
                }
 
                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;
                }
 
@@ -414,8 +497,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) {
@@ -459,6 +542,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)
                {
@@ -489,7 +597,7 @@ namespace System.Reflection.Emit {
                        return GetMethodToken (GetArrayMethod (arrayClass, methodName, callingConvention, returnType, parameterTypes));
                }
 
-
+               [ComVisible (true)]
                public MethodToken GetConstructorToken (ConstructorInfo con)
                {
                        if (con == null)
@@ -537,7 +645,7 @@ namespace System.Reflection.Emit {
                        return new TypeToken (GetToken (type));
                }
 
-               public TypeToken GetTypeToken (string type)
+               public TypeToken GetTypeToken (string name)
                {
                        return GetTypeToken (GetType (name));
                }
@@ -572,6 +680,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);
@@ -598,15 +713,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);
@@ -614,7 +746,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);
                        
@@ -622,6 +760,12 @@ namespace System.Reflection.Emit {
                        // The constant 0x80000000 is internal to Mono, it means `make executable'
                        //
                        File.SetAttributes (fileName, (FileAttributes) (unchecked ((int) 0x80000000)));
+                       
+                       if (types != null && symbolWriter != null) {
+                               for (int i = 0; i < num_types; ++i)
+                                       types [i].GenerateDebugInfo (symbolWriter);
+                               symbolWriter.Close ();
+                       }
                }
 
                internal string FileName {
@@ -638,12 +782,38 @@ 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)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _ModuleBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _ModuleBuilder.GetTypeInfoCount (out uint pcTInfo)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _ModuleBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
+               {
+                       throw new NotImplementedException ();
                }
        }
 
@@ -672,3 +842,4 @@ namespace System.Reflection.Emit {
                }
        }
 }
+