Merge branch 'marek'
[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 (CompilerContext ctx)
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                                 var cg = ctx.PredefinedAttributes.CompilerGenerated;
292                                 foreach (TypeBuilder type_builder in helper_classes) {
293                                         cg.EmitAttribute (type_builder);
294                                         type_builder.CreateType ();
295                                 }
296                         }
297                         
298                         helper_classes = null;
299                 }
300
301                 /// <summary>
302                 ///   Used to register classes that need to be closed after all the
303                 ///   user defined classes
304                 /// </summary>
305                 public static void RegisterCompilerGeneratedType (TypeBuilder helper_class)
306                 {
307                         if (helper_classes == null)
308                                 helper_classes = new List<TypeBuilder> ();
309
310                         helper_classes.Add (helper_class);
311                 }
312                 
313                 // <summary>
314                 //   Populates the structs and classes with fields and methods
315                 // </summary>
316                 //
317                 // This is invoked after all interfaces, structs and classes
318                 // have been defined through `ResolveTree' 
319                 static public void PopulateTypes ()
320                 {
321                         foreach (TypeContainer tc in ToplevelTypes.Types)
322                                 tc.ResolveTypeParameters ();
323
324                         foreach (TypeContainer tc in ToplevelTypes.Types) {
325                                 try {
326                                         tc.Define ();
327                                 } catch (Exception e) {
328                                         throw new InternalErrorException (tc, e);
329                                 }
330                         }
331                 }
332
333                 static public void EmitCode ()
334                 {
335                         foreach (var tc in ToplevelTypes.Types)
336                                 tc.DefineConstants ();
337
338                         HackCorlib ();
339
340                         foreach (TypeContainer tc in ToplevelTypes.Types)
341                                 tc.EmitType ();
342
343                         if (ToplevelTypes.Compiler.Report.Errors > 0)
344                                 return;
345
346                         foreach (TypeContainer tc in ToplevelTypes.Types)
347                                 tc.VerifyMembers ();
348
349                         if (root.CompilerGeneratedClasses != null)
350                                 foreach (CompilerGeneratedClass c in root.CompilerGeneratedClasses)
351                                         c.EmitType ();
352
353                         CodeGen.Assembly.Emit (root);
354                         root.Emit ();
355                 }
356                 
357                 //
358                 // Public Field, used to track which method is the public entry
359                 // point.
360                 //
361                 static public Method EntryPoint;
362
363                 //
364                 // These are used to generate unique names on the structs and fields.
365                 //
366                 static int field_count;
367                 
368                 //
369                 // Makes an initialized struct, returns the field builder that
370                 // references the data.  Thanks go to Sergey Chaban for researching
371                 // how to do this.  And coming up with a shorter mechanism than I
372                 // was able to figure out.
373                 //
374                 // This works but makes an implicit public struct $ArrayType$SIZE and
375                 // makes the fields point to it.  We could get more control if we did
376                 // use instead:
377                 //
378                 // 1. DefineNestedType on the impl_details_class with our struct.
379                 //
380                 // 2. Define the field on the impl_details_class
381                 //
382                 static public FieldBuilder MakeStaticData (byte [] data)
383                 {
384                         FieldBuilder fb;
385                         
386                         if (impl_details_class == null){
387                                 impl_details_class = ToplevelTypes.Builder.DefineType (
388                                         "<PrivateImplementationDetails>",
389                                         TypeAttributes.NotPublic,
390                                         TypeManager.object_type.GetMetaInfo ());
391                                 
392                                 RegisterCompilerGeneratedType (impl_details_class);
393                         }
394
395                         fb = impl_details_class.DefineInitializedData (
396                                 "$$field-" + (field_count++), data,
397                                 FieldAttributes.Static | FieldAttributes.Assembly);
398                         
399                         return fb;
400                 }
401         }
402 }