Fix corlib self referencing bug.
[mono.git] / mcs / mcs / rootcontext.cs
1 //
2 // rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //            Ravi Pratap  (ravi@ximian.com)
6 //            Marek Safar  (marek.safar@gmail.com)
7 //
8 //
9 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 //
11 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
12 // Copyright 2004-2008 Novell, Inc
13
14 using System;
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Diagnostics;
19
20 namespace Mono.CSharp {
21
22         public enum LanguageVersion
23         {
24                 ISO_1           = 1,
25                 ISO_2           = 2,
26                 V_3             = 3,
27                 V_4             = 4,
28                 Future          = 100,
29
30                 Default         = LanguageVersion.V_4,
31         }
32
33         public enum MetadataVersion
34         {
35                 v1,
36                 v2,
37                 v4
38         }
39
40         public class RootContext {
41
42                 //
43                 // COMPILER OPTIONS CLASS
44                 //
45                 public static Target Target;
46                 public static Platform Platform;
47                 public static string TargetExt;
48                 public static bool VerifyClsCompliance = true;
49                 public static bool Optimize = true;
50                 public static LanguageVersion Version;
51                 public static bool EnhancedWarnings;
52
53                 public static MetadataVersion MetadataCompatibilityVersion;
54
55                 //
56                 // We keep strongname related info here because
57                 // it's also used as complier options from CSC 8.x
58                 //
59                 public static string StrongNameKeyFile;
60                 public static string StrongNameKeyContainer;
61                 public static bool StrongNameDelaySign;
62
63                 //
64                 // If set, enable XML documentation generation
65                 //
66                 public static Documentation Documentation;
67
68                 static public string MainClass;
69
70                 // 
71                 // The default compiler checked state
72                 //
73                 static public bool Checked;
74
75                 //
76                 // If true, it means that the compiler is executing as
77                 // in eval mode so unresolved variables are resolved in
78                 // static classes maintained by the eval engine.
79                 //
80                 static public bool EvalMode;
81
82                 //
83                 // If true, the compiler is operating in statement mode,
84                 // this currently turns local variable declaration into
85                 // static variables of a class
86                 //
87                 static public bool StatementMode;
88                 
89                 //
90                 // Whether to allow Unsafe code
91                 //
92                 static public bool Unsafe;
93
94                 //
95                 // Whether we are being linked against the standard libraries.
96                 // This is only used to tell whether `System.Object' should
97                 // have a base class or not.
98                 //
99                 public static bool StdLib;
100
101                 public static bool NeedsEntryPoint {
102                         get { return Target == Target.Exe || Target == Target.WinExe; }
103                 }
104
105                 //
106                 // COMPILER OPTIONS CLASS END
107                 //
108
109                 //
110                 // Contains the parsed tree
111                 //
112                 static ModuleCompiled root;
113
114                 //
115                 // This hashtable contains all of the #definitions across the source code
116                 // it is used by the ConditionalAttribute handler.
117                 //
118                 static List<string> AllDefines;
119                 
120                 //
121                 // Holds a reference to the Private Implementation Details
122                 // class.
123                 //
124                 static List<TypeBuilder> helper_classes;
125                 
126                 static TypeBuilder impl_details_class;
127
128                 public static List<Enum> hack_corlib_enums = new List<Enum> ();
129
130                 //
131                 // Constructor
132                 //
133                 static RootContext ()
134                 {
135                         Reset (true);
136                 }
137
138                 public static void PartialReset ()
139                 {
140                         Reset (false);
141                 }
142                 
143                 public static void Reset (bool full)
144                 {
145                         impl_details_class = null;
146                         helper_classes = null;
147
148                         if (!full)
149                                 return;
150                         
151                         EntryPoint = null;
152                         Checked = false;
153                         Unsafe = false;
154                         StdLib = true;
155                         StrongNameKeyFile = null;
156                         StrongNameKeyContainer = null;
157                         StrongNameDelaySign = false;
158                         MainClass = null;
159                         Target = Target.Exe;
160                         TargetExt = ".exe";
161                         Platform = Platform.AnyCPU;
162                         Version = LanguageVersion.Default;
163                         Documentation = null;
164                         impl_details_class = null;
165                         helper_classes = null;
166
167 #if NET_4_0
168                         MetadataCompatibilityVersion = MetadataVersion.v4;
169 #else
170                         MetadataCompatibilityVersion = MetadataVersion.v2;
171 #endif
172
173                         //
174                         // Setup default defines
175                         //
176                         AllDefines = new List<string> ();
177                         AddConditional ("__MonoCS__");
178                 }
179
180                 public static void AddConditional (string p)
181                 {
182                         if (AllDefines.Contains (p))
183                                 return;
184                         AllDefines.Add (p);
185                 }
186
187                 public static bool IsConditionalDefined (string value)
188                 {
189                         return AllDefines.Contains (value);
190                 }
191
192                 static public ModuleCompiled ToplevelTypes {
193                         get { return root; }
194                         set { root = value; }
195                 }
196
197                 // <remarks>
198                 //   This function is used to resolve the hierarchy tree.
199                 //   It processes interfaces, structs and classes in that order.
200                 //
201                 //   It creates the TypeBuilder's as it processes the user defined
202                 //   types.  
203                 // </remarks>
204                 static public void ResolveTree ()
205                 {
206                         root.Resolve ();
207
208                         //
209                         // Interfaces are processed next, as classes and
210                         // structs might inherit from an object or implement
211                         // a set of interfaces, we need to be able to tell
212                         // them appart by just using the TypeManager.
213                         //
214                         foreach (TypeContainer tc in root.Types)
215                                 tc.CreateType ();
216
217                         foreach (TypeContainer tc in root.Types)
218                                 tc.DefineType ();
219                 }
220
221                 static void HackCorlib ()
222                 {
223                         if (StdLib)
224                                 return;
225
226                         //
227                         // HACK: When building corlib mcs uses loaded mscorlib which
228                         // has different predefined types and this method sets mscorlib types
229                         // to be same to avoid type check errors in CreateType.
230                         //
231                         var type = typeof (Type);
232                         var system_4_type_arg = new[] { type, type, type, type };
233
234                         MethodInfo set_corlib_type_builders =
235                                 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
236                                 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
237                                 system_4_type_arg, null);
238
239                         if (set_corlib_type_builders == null) {
240                                 root.Compiler.Report.Warning (-26, 3, "The compilation may fail due to missing `{0}.SetCorlibTypeBuilders(...)' method",
241                                         typeof (System.Reflection.Emit.AssemblyBuilder).FullName);
242                                 return;
243                         }
244
245                         object[] args = new object[4];
246                         args[0] = TypeManager.object_type.GetMetaInfo ();
247                         args[1] = TypeManager.value_type.GetMetaInfo ();
248                         args[2] = TypeManager.enum_type.GetMetaInfo ();
249                         args[3] = TypeManager.void_type.GetMetaInfo ();
250                         set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
251                 }
252
253                 static void HackCorlibEnums ()
254                 {
255                         if (StdLib)
256                                 return;
257
258                         // Another Mono corlib HACK
259                         // mono_class_layout_fields requires to have enums created
260                         // before creating a class which used the enum for any of its fields
261                         foreach (var e in hack_corlib_enums)
262                                 e.CloseType ();
263                 }
264
265                 // <summary>
266                 //   Closes all open types
267                 // </summary>
268                 //
269                 // <remarks>
270                 //   We usually use TypeBuilder types.  When we are done
271                 //   creating the type (which will happen after we have added
272                 //   methods, fields, etc) we need to "Define" them before we
273                 //   can save the Assembly
274                 // </remarks>
275                 static public void CloseTypes ()
276                 {
277                         HackCorlibEnums ();
278
279                         foreach (TypeContainer tc in root.Types){
280                                 tc.CloseType ();
281                         }
282
283                         if (root.CompilerGeneratedClasses != null)
284                                 foreach (CompilerGeneratedClass c in root.CompilerGeneratedClasses)
285                                         c.CloseType ();
286
287                         //
288                         // If we have a <PrivateImplementationDetails> class, close it
289                         //
290                         if (helper_classes != null){
291                                 foreach (TypeBuilder type_builder in helper_classes) {
292                                         PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (type_builder);
293                                         type_builder.CreateType ();
294                                 }
295                         }
296                         
297                         helper_classes = null;
298                 }
299
300                 /// <summary>
301                 ///   Used to register classes that need to be closed after all the
302                 ///   user defined classes
303                 /// </summary>
304                 public static void RegisterCompilerGeneratedType (TypeBuilder helper_class)
305                 {
306                         if (helper_classes == null)
307                                 helper_classes = new List<TypeBuilder> ();
308
309                         helper_classes.Add (helper_class);
310                 }
311                 
312                 // <summary>
313                 //   Populates the structs and classes with fields and methods
314                 // </summary>
315                 //
316                 // This is invoked after all interfaces, structs and classes
317                 // have been defined through `ResolveTree' 
318                 static public void PopulateTypes ()
319                 {
320                         foreach (TypeContainer tc in ToplevelTypes.Types)
321                                 tc.ResolveTypeParameters ();
322
323                         foreach (TypeContainer tc in ToplevelTypes.Types) {
324                                 try {
325                                         tc.Define ();
326                                 } catch (Exception e) {
327                                         throw new InternalErrorException (tc, e);
328                                 }
329                         }
330                 }
331
332                 static public void EmitCode ()
333                 {
334                         foreach (var tc in ToplevelTypes.Types)
335                                 tc.DefineConstants ();
336
337                         HackCorlib ();
338
339                         foreach (TypeContainer tc in ToplevelTypes.Types)
340                                 tc.EmitType ();
341
342                         if (ToplevelTypes.Compiler.Report.Errors > 0)
343                                 return;
344
345                         foreach (TypeContainer tc in ToplevelTypes.Types)
346                                 tc.VerifyMembers ();
347
348                         if (root.CompilerGeneratedClasses != null)
349                                 foreach (CompilerGeneratedClass c in root.CompilerGeneratedClasses)
350                                         c.EmitType ();
351
352                         CodeGen.Assembly.Emit (root);
353                         root.Emit ();
354                 }
355                 
356                 //
357                 // Public Field, used to track which method is the public entry
358                 // point.
359                 //
360                 static public Method EntryPoint;
361
362                 //
363                 // These are used to generate unique names on the structs and fields.
364                 //
365                 static int field_count;
366                 
367                 //
368                 // Makes an initialized struct, returns the field builder that
369                 // references the data.  Thanks go to Sergey Chaban for researching
370                 // how to do this.  And coming up with a shorter mechanism than I
371                 // was able to figure out.
372                 //
373                 // This works but makes an implicit public struct $ArrayType$SIZE and
374                 // makes the fields point to it.  We could get more control if we did
375                 // use instead:
376                 //
377                 // 1. DefineNestedType on the impl_details_class with our struct.
378                 //
379                 // 2. Define the field on the impl_details_class
380                 //
381                 static public FieldBuilder MakeStaticData (byte [] data)
382                 {
383                         FieldBuilder fb;
384                         
385                         if (impl_details_class == null){
386                                 impl_details_class = ToplevelTypes.Builder.DefineType (
387                                         "<PrivateImplementationDetails>",
388                                         TypeAttributes.NotPublic,
389                                         TypeManager.object_type.GetMetaInfo ());
390                                 
391                                 RegisterCompilerGeneratedType (impl_details_class);
392                         }
393
394                         fb = impl_details_class.DefineInitializedData (
395                                 "$$field-" + (field_count++), data,
396                                 FieldAttributes.Static | FieldAttributes.Assembly);
397                         
398                         return fb;
399                 }
400         }
401 }