Less static is good for my health
[mono.git] / mcs / mcs / roottypes.cs
index d6fd7ca2db729ddf64c5feb46f6a77f20812c186..c448081e1402dc97f95b73b0c8de023ba227e05a 100644 (file)
 
 using System;
 using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
 using System.Runtime.InteropServices;
 using Mono.CompilerServices.SymbolWriter;
 
+#if STATIC
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
+using System.Reflection;
+using System.Reflection.Emit;
+#endif
+
 namespace Mono.CSharp
 {
        //
@@ -24,7 +30,93 @@ namespace Mono.CSharp
        //
        public class ModuleContainer : TypeContainer
        {
-               public CharSet DefaultCharSet = CharSet.Ansi;
+#if STATIC
+               //
+               // Compiler generated container for static data
+               //
+               sealed class StaticDataContainer : CompilerGeneratedClass
+               {
+                       Dictionary<int, Struct> size_types;
+                       new int fields;
+
+                       public StaticDataContainer (ModuleContainer module)
+                               : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
+                       {
+                               size_types = new Dictionary<int, Struct> ();
+                       }
+
+                       public override void CloseType ()
+                       {
+                               base.CloseType ();
+
+                               foreach (var entry in size_types) {
+                                       entry.Value.CloseType ();
+                               }
+                       }
+
+                       public FieldSpec DefineInitializedData (byte[] data, Location loc)
+                       {
+                               Struct size_type;
+                               if (!size_types.TryGetValue (data.Length, out size_type)) {
+                                       //
+                                       // Build common type for this data length. We cannot use
+                                       // DefineInitializedData because it creates public type,
+                                       // and its name is not unique among modules
+                                       //
+                                       size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, Location), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
+                                       size_type.CreateType ();
+                                       size_type.DefineType ();
+
+                                       size_types.Add (data.Length, size_type);
+
+                                       var pa = Module.PredefinedAttributes.StructLayout;
+                                       if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.short_type)) {
+                                               var argsEncoded = new AttributeEncoder ();
+                                               argsEncoded.Encode ((short) LayoutKind.Explicit);
+
+                                               var field_size = pa.GetField ("Size", TypeManager.int32_type, Location);
+                                               var pack = pa.GetField ("Pack", TypeManager.int32_type, Location);
+                                               if (field_size != null) {
+                                                       argsEncoded.EncodeNamedArguments (
+                                                               new[] { field_size, pack },
+                                                               new[] { new IntConstant ((int) data.Length, Location), new IntConstant (1, Location) }
+                                                       );
+                                               }
+
+                                               pa.EmitAttribute (size_type.TypeBuilder, argsEncoded);
+                                       }
+                               }
+
+                               var name = "$field-" + fields.ToString ("X");
+                               ++fields;
+                               const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
+                               var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
+                               fbuilder.__SetDataAndRVA (data);
+
+                               return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
+                       }
+               }
+
+               StaticDataContainer static_data;
+
+               //
+               // Makes const data field inside internal type container
+               //
+               public FieldSpec MakeStaticData (byte[] data, Location loc)
+               {
+                       if (static_data == null) {
+                               static_data = new StaticDataContainer (this);
+                               static_data.CreateType ();
+                               static_data.DefineType ();
+
+                               AddCompilerGeneratedClass (static_data);
+                       }
+
+                       return static_data.DefineInitializedData (data, loc);
+               }
+#endif
+
+               public CharSet? DefaultCharSet;
                public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
 
                Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
@@ -35,12 +127,7 @@ namespace Mono.CSharp
                Dictionary<string, RootNamespace> alias_ns;
 
                ModuleBuilder builder;
-               int static_data_counter;
-
-               // HACK
-               public List<Enum> hack_corlib_enums = new List<Enum> ();
 
-               bool has_default_charset;
                bool has_extenstion_method;
 
                PredefinedAttributes predefined_attributes;
@@ -89,7 +176,7 @@ namespace Mono.CSharp
 
                public bool HasDefaultCharSet {
                        get {
-                               return has_default_charset;
+                               return DefaultCharSet.HasValue;
                        }
                }
 
@@ -178,7 +265,25 @@ namespace Mono.CSharp
                                return;
                        }
 
-                       if (a.Type == pa.CLSCompliant) {
+                       if (a.Type == pa.DefaultCharset) {
+                               switch (a.GetCharSetValue ()) {
+                               case CharSet.Ansi:
+                               case CharSet.None:
+                                       break;
+                               case CharSet.Auto:
+                                       DefaultCharSet = CharSet.Auto;
+                                       DefaultCharSetType = TypeAttributes.AutoClass;
+                                       break;
+                               case CharSet.Unicode:
+                                       DefaultCharSet = CharSet.Unicode;
+                                       DefaultCharSetType = TypeAttributes.UnicodeClass;
+                                       break;
+                               default:
+                                       Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
+                                               a.GetSignatureForError ());
+                                       break;
+                               }
+                       } else if (a.Type == pa.CLSCompliant) {
                                Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
                                if (cls == null) {
                                        Report.Warning (3012, 1, a.Location,
@@ -194,10 +299,8 @@ namespace Mono.CSharp
                        builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
                }
 
-               public new void CloseType ()
+               public override void CloseType ()
                {
-                       HackCorlibEnums ();
-
                        foreach (TypeContainer tc in types) {
                                tc.CloseType ();
                        }
@@ -205,15 +308,6 @@ namespace Mono.CSharp
                        if (compiler_generated != null)
                                foreach (CompilerGeneratedClass c in compiler_generated)
                                        c.CloseType ();
-
-                       //
-                       // If we have a <PrivateImplementationDetails> class, close it
-                       //
-                       if (TypeBuilder != null) {
-                               var cg = PredefinedAttributes.CompilerGenerated;
-                               cg.EmitAttribute (TypeBuilder);
-                               TypeBuilder.CreateType ();
-                       }
                }
 
                public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
@@ -240,20 +334,20 @@ namespace Mono.CSharp
                        return rn;
                }
 
-               public new void Define ()
+               public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
                {
-                       builder = assembly.CreateModuleBuilder ();
-
-                       // FIXME: Temporary hack for repl to reset
-                       TypeBuilder = null;
-
-                       // TODO: It should be done much later when the types are resolved
-                       // but that require DefineType clean-up
-                       ResolveGlobalAttributes ();
+                       this.assembly = assembly;
+                       builder = moduleBuilder;
+               }
 
+               public new void CreateType ()
+               {
                        foreach (TypeContainer tc in types)
                                tc.CreateType ();
+               }
 
+               public new void Define ()
+               {
                        InitializePredefinedTypes ();
 
                        foreach (TypeContainer tc in types)
@@ -276,7 +370,7 @@ namespace Mono.CSharp
                        if (OptAttributes != null)
                                OptAttributes.Emit ();
 
-                       if (RootContext.Unsafe) {
+                       if (Compiler.Settings.Unsafe) {
                                var pa = PredefinedAttributes.UnverifiableCode;
                                if (pa.IsDefined)
                                        pa.EmitAttribute (builder);
@@ -285,8 +379,6 @@ namespace Mono.CSharp
                        foreach (var tc in types)
                                tc.DefineConstants ();
 
-                       HackCorlib ();
-
                        foreach (TypeContainer tc in types)
                                tc.EmitType ();
 
@@ -333,50 +425,6 @@ namespace Mono.CSharp
                        return "<module>";
                }
 
-               void HackCorlib ()
-               {
-                       if (RootContext.StdLib)
-                               return;
-
-                       //
-                       // HACK: When building corlib mcs uses loaded mscorlib which
-                       // has different predefined types and this method sets mscorlib types
-                       // to be same to avoid type check errors in CreateType.
-                       //
-                       var type = typeof (Type);
-                       var system_4_type_arg = new[] { type, type, type, type };
-
-                       MethodInfo set_corlib_type_builders =
-                               typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
-                               "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
-                               system_4_type_arg, null);
-
-                       if (set_corlib_type_builders == null) {
-                               Compiler.Report.Warning (-26, 3,
-                                       "The compilation may fail due to missing `System.Reflection.Emit.AssemblyBuilder.SetCorlibTypeBuilders(...)' method");
-                               return;
-                       }
-
-                       object[] args = new object[4];
-                       args[0] = TypeManager.object_type.GetMetaInfo ();
-                       args[1] = TypeManager.value_type.GetMetaInfo ();
-                       args[2] = TypeManager.enum_type.GetMetaInfo ();
-                       args[3] = TypeManager.void_type.GetMetaInfo ();
-                       set_corlib_type_builders.Invoke (assembly.Builder, args);
-               }
-
-               void HackCorlibEnums ()
-               {
-                       if (RootContext.StdLib)
-                               return;
-
-                       // Another Mono corlib HACK
-                       // mono_class_layout_fields requires to have enums created
-                       // before creating a class which used the enum for any of its fields
-                       foreach (var e in hack_corlib_enums)
-                               e.CloseType ();
-               }
-
                public void InitializePredefinedTypes ()
                {
                        predefined_attributes = new PredefinedAttributes (this);
@@ -387,46 +435,6 @@ namespace Mono.CSharp
                {
                        return DeclaringAssembly.IsCLSCompliant;
                }
-               
-               public AssemblyDefinition MakeExecutable (string name)
-               {
-                       assembly = new AssemblyDefinition (this, name);
-                       return assembly;
-               }
-               
-               public AssemblyDefinition MakeExecutable (string name, string fileName)
-               {
-                       assembly = new AssemblyDefinition (this, name, fileName);
-                       return assembly;
-               }
-
-               //
-               // Makes an initialized struct, returns the field builder that
-               // references the data.  Thanks go to Sergey Chaban for researching
-               // how to do this.  And coming up with a shorter mechanism than I
-               // was able to figure out.
-               //
-               // This works but makes an implicit public struct $ArrayType$SIZE and
-               // makes the fields point to it.  We could get more control if we did
-               // use instead:
-               //
-               // 1. DefineNestedType on the impl_details_class with our struct.
-               //
-               // 2. Define the field on the impl_details_class
-               //
-               public FieldBuilder MakeStaticData (byte[] data)
-               {
-                       if (TypeBuilder == null) {
-                               TypeBuilder = builder.DefineType ("<PrivateImplementationDetails>",
-                                       TypeAttributes.NotPublic, TypeManager.object_type.GetMetaInfo ());
-                       }
-
-                       var fb = TypeBuilder.DefineInitializedData (
-                               "$$field-" + (static_data_counter++), data,
-                               FieldAttributes.Static | FieldAttributes.Assembly);
-
-                       return fb;
-               }
 
                protected override bool AddMemberType (TypeContainer ds)
                {
@@ -442,42 +450,6 @@ namespace Mono.CSharp
                        base.RemoveMemberType (ds);
                }
 
-               /// <summary>
-               /// It is called very early therefore can resolve only predefined attributes
-               /// </summary>
-               void ResolveGlobalAttributes ()
-               {
-                       if (OptAttributes == null)
-                               return;
-
-                       if (!OptAttributes.CheckTargets ())
-                               return;
-
-                       // FIXME: Define is wrong as the type may not exist yet
-                       var DefaultCharSet_attr = new PredefinedAttribute (this, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
-                       DefaultCharSet_attr.Define ();
-                       Attribute a = ResolveModuleAttribute (DefaultCharSet_attr);
-                       if (a != null) {
-                               has_default_charset = true;
-                               DefaultCharSet = a.GetCharSetValue ();
-                               switch (DefaultCharSet) {
-                               case CharSet.Ansi:
-                               case CharSet.None:
-                                       break;
-                               case CharSet.Auto:
-                                       DefaultCharSetType = TypeAttributes.AutoClass;
-                                       break;
-                               case CharSet.Unicode:
-                                       DefaultCharSetType = TypeAttributes.UnicodeClass;
-                                       break;
-                               default:
-                                       Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid", 
-                                               DefaultCharSet_attr.GetSignatureForError ());
-                                       break;
-                               }
-                       }
-               }
-
                public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
                {
                        Attribute a = OptAttributes.Search ("assembly", a_type);
@@ -487,13 +459,10 @@ namespace Mono.CSharp
                        return a;
                }
 
-               Attribute ResolveModuleAttribute (PredefinedAttribute a_type)
+               public void SetDeclaringAssembly (AssemblyDefinition assembly)
                {
-                       Attribute a = OptAttributes.Search ("module", a_type);
-                       if (a != null) {
-                               a.Resolve ();
-                       }
-                       return a;
+                       // TODO: This setter is quite ugly but I have not found a way around it yet
+                       this.assembly = assembly;
                }
        }