2009-10-16 Marek Safar <marek.safar@gmail.com>
[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;
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
52                 public static MetadataVersion MetadataCompatibilityVersion;
53
54                 //
55                 // We keep strongname related info here because
56                 // it's also used as complier options from CSC 8.x
57                 //
58                 public static string StrongNameKeyFile;
59                 public static string StrongNameKeyContainer;
60                 public static bool StrongNameDelaySign;
61
62                 //
63                 // If set, enable XML documentation generation
64                 //
65                 public static Documentation Documentation;
66
67                 static public string MainClass;
68
69                 // 
70                 // The default compiler checked state
71                 //
72                 static public bool Checked;
73
74                 //
75                 // If true, it means that the compiler is executing as
76                 // in eval mode so unresolved variables are resolved in
77                 // static classes maintained by the eval engine.
78                 //
79                 static public bool EvalMode;
80
81                 //
82                 // If true, the compiler is operating in statement mode,
83                 // this currently turns local variable declaration into
84                 // static variables of a class
85                 //
86                 static public bool StatementMode;
87                 
88                 //
89                 // Whether to allow Unsafe code
90                 //
91                 static public bool Unsafe;
92
93                 //
94                 // Whether we are being linked against the standard libraries.
95                 // This is only used to tell whether `System.Object' should
96                 // have a base class or not.
97                 //
98                 public static bool StdLib;
99
100                 public static bool NeedsEntryPoint {
101                         get { return Target == Target.Exe || Target == Target.WinExe; }
102                 }
103
104                 //
105                 // COMPILER OPTIONS CLASS END
106                 //
107
108                 //
109                 // Contains the parsed tree
110                 //
111                 static ModuleContainer root;
112
113                 //
114                 // This hashtable contains all of the #definitions across the source code
115                 // it is used by the ConditionalAttribute handler.
116                 //
117                 static ArrayList AllDefines;
118                 
119                 //
120                 // This keeps track of the order in which classes were defined
121                 // so that we can poulate them in that order.
122                 //
123                 // Order is important, because we need to be able to tell, by
124                 // examining the list of methods of the base class, which ones are virtual
125                 // or abstract as well as the parent names (to implement new, 
126                 // override).
127                 //
128                 static ArrayList type_container_resolve_order;
129
130                 //
131                 // Holds a reference to the Private Implementation Details
132                 // class.
133                 //
134                 static ArrayList helper_classes;
135                 
136                 static TypeBuilder impl_details_class;
137
138                 //
139                 // Constructor
140                 //
141                 static RootContext ()
142                 {
143                         Reset (true);
144                 }
145
146                 public static void PartialReset ()
147                 {
148                         Reset (false);
149                 }
150                 
151                 public static void Reset (bool full)
152                 {
153                         if (full)
154                                 root = null;
155                         
156                         type_container_resolve_order = new ArrayList ();
157                         EntryPoint = null;
158                         Checked = false;
159                         Unsafe = false;
160                         StdLib = true;
161                         StrongNameKeyFile = null;
162                         StrongNameKeyContainer = null;
163                         StrongNameDelaySign = false;
164                         MainClass = null;
165                         Target = Target.Exe;
166                         TargetExt = ".exe";
167                         Platform = Platform.AnyCPU;
168                         Version = LanguageVersion.Default;
169                         Documentation = null;
170                         impl_details_class = null;
171                         helper_classes = null;
172
173                         MetadataCompatibilityVersion = MetadataVersion.v2;
174
175                         //
176                         // Setup default defines
177                         //
178                         AllDefines = new ArrayList ();
179                         AddConditional ("__MonoCS__");
180                 }
181
182                 public static void AddConditional (string p)
183                 {
184                         if (AllDefines.Contains (p))
185                                 return;
186                         AllDefines.Add (p);
187                 }
188
189                 public static bool IsConditionalDefined (string value)
190                 {
191                         return AllDefines.Contains (value);
192                 }
193
194                 static public ModuleContainer ToplevelTypes {
195                         get { return root; }
196                         set { root = value; }
197                 }
198
199                 public static void RegisterOrder (TypeContainer tc)
200                 {
201                         type_container_resolve_order.Add (tc);
202                 }
203                 
204                 // <remarks>
205                 //   This function is used to resolve the hierarchy tree.
206                 //   It processes interfaces, structs and classes in that order.
207                 //
208                 //   It creates the TypeBuilder's as it processes the user defined
209                 //   types.  
210                 // </remarks>
211                 static public void ResolveTree ()
212                 {
213                         root.Resolve ();
214
215                         //
216                         // Interfaces are processed next, as classes and
217                         // structs might inherit from an object or implement
218                         // a set of interfaces, we need to be able to tell
219                         // them appart by just using the TypeManager.
220                         //
221                         foreach (TypeContainer tc in root.Types)
222                                 tc.CreateType ();
223
224                         foreach (TypeContainer tc in root.Types)
225                                 tc.DefineType ();
226
227                         if (root.Delegates != null)
228                                 foreach (Delegate d in root.Delegates) 
229                                         d.DefineType ();
230                 }
231
232                 // <summary>
233                 //   Closes all open types
234                 // </summary>
235                 //
236                 // <remarks>
237                 //   We usually use TypeBuilder types.  When we are done
238                 //   creating the type (which will happen after we have added
239                 //   methods, fields, etc) we need to "Define" them before we
240                 //   can save the Assembly
241                 // </remarks>
242                 static public void CloseTypes ()
243                 {
244                         //
245                         // We do this in two passes, first we close the structs,
246                         // then the classes, because it seems the code needs it this
247                         // way.  If this is really what is going on, we should probably
248                         // make sure that we define the structs in order as well.
249                         //
250                         foreach (TypeContainer tc in type_container_resolve_order){
251                                 if (tc.Kind == Kind.Struct && tc.Parent == root){
252                                         tc.CloseType ();
253                                 }
254                         }
255
256                         foreach (TypeContainer tc in type_container_resolve_order){
257                                 if (!(tc.Kind == Kind.Struct && tc.Parent == root))
258                                         tc.CloseType ();                                        
259                         }
260                         
261                         if (root.Delegates != null)
262                                 foreach (Delegate d in root.Delegates)
263                                         d.CloseType ();
264
265
266                         //
267                         // If we have a <PrivateImplementationDetails> class, close it
268                         //
269                         if (helper_classes != null){
270                                 foreach (TypeBuilder type_builder in helper_classes) {
271                                         PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (type_builder);
272                                         type_builder.CreateType ();
273                                 }
274                         }
275                         
276                         type_container_resolve_order = null;
277                         helper_classes = null;
278                         //root = null;
279                         TypeManager.CleanUp ();
280                 }
281
282                 /// <summary>
283                 ///   Used to register classes that need to be closed after all the
284                 ///   user defined classes
285                 /// </summary>
286                 public static void RegisterCompilerGeneratedType (TypeBuilder helper_class)
287                 {
288                         if (helper_classes == null)
289                                 helper_classes = new ArrayList ();
290
291                         helper_classes.Add (helper_class);
292                 }
293                 
294                 static public DeclSpace PopulateCoreType (TypeContainer root, string name)
295                 {
296                         DeclSpace ds = (DeclSpace) root.GetDefinition (name);
297                         // Core type was imported
298                         if (ds == null)
299                                 return null;
300
301                         ds.Define ();
302                         return ds;
303                 }
304                 
305                 static public void BootCorlib_PopulateCoreTypes ()
306                 {
307                         // Clear -nostdlib flag when object type is imported
308                         if (PopulateCoreType (root, "System.Object") == null)
309                                 RootContext.StdLib = true;
310
311                         PopulateCoreType (root, "System.ValueType");
312                         PopulateCoreType (root, "System.Attribute");
313                         PopulateCoreType (root, "System.Runtime.CompilerServices.IndexerNameAttribute");
314                 }
315                 
316                 // <summary>
317                 //   Populates the structs and classes with fields and methods
318                 // </summary>
319                 //
320                 // This is invoked after all interfaces, structs and classes
321                 // have been defined through `ResolveTree' 
322                 static public void PopulateTypes ()
323                 {
324
325                         if (type_container_resolve_order != null){
326                                 foreach (TypeContainer tc in type_container_resolve_order)
327                                         tc.ResolveType ();
328                                 foreach (TypeContainer tc in type_container_resolve_order) {
329                                         try {
330                                                 tc.Define ();
331                                         } catch (Exception e) {
332                                                 throw new InternalErrorException (tc, e);
333                                         }
334                                 }
335                         }
336
337                         ArrayList delegates = root.Delegates;
338                         if (delegates != null){
339                                 foreach (Delegate d in delegates)
340                                         d.Define ();
341                         }
342
343                         //
344                         // Check for cycles in the struct layout
345                         //
346                         if (type_container_resolve_order != null){
347                                 Hashtable seen = new Hashtable ();
348                                 foreach (TypeContainer tc in type_container_resolve_order)
349                                         TypeManager.CheckStructCycles (tc, seen);
350                         }
351                 }
352
353                 static public void EmitCode ()
354                 {
355                         if (type_container_resolve_order != null) {
356                                 foreach (TypeContainer tc in type_container_resolve_order)
357                                         tc.EmitType ();
358
359                                 if (RootContext.ToplevelTypes.Compiler.Report.Errors > 0)
360                                         return;
361
362                                 foreach (TypeContainer tc in type_container_resolve_order)
363                                         tc.VerifyMembers ();
364                         }
365                         
366                         if (root.Delegates != null) {
367                                 foreach (Delegate d in root.Delegates)
368                                         d.Emit ();
369                         }                       
370
371                         CodeGen.Assembly.Emit (root);
372                         root.Emit ();
373                 }
374                 
375                 //
376                 // Public Field, used to track which method is the public entry
377                 // point.
378                 //
379                 static public Method EntryPoint;
380
381                 //
382                 // These are used to generate unique names on the structs and fields.
383                 //
384                 static int field_count;
385                 
386                 //
387                 // Makes an initialized struct, returns the field builder that
388                 // references the data.  Thanks go to Sergey Chaban for researching
389                 // how to do this.  And coming up with a shorter mechanism than I
390                 // was able to figure out.
391                 //
392                 // This works but makes an implicit public struct $ArrayType$SIZE and
393                 // makes the fields point to it.  We could get more control if we did
394                 // use instead:
395                 //
396                 // 1. DefineNestedType on the impl_details_class with our struct.
397                 //
398                 // 2. Define the field on the impl_details_class
399                 //
400                 static public FieldBuilder MakeStaticData (byte [] data)
401                 {
402                         FieldBuilder fb;
403                         
404                         if (impl_details_class == null){
405                                 impl_details_class = ToplevelTypes.Builder.DefineType (
406                                         "<PrivateImplementationDetails>",
407                                         TypeAttributes.NotPublic,
408                                         TypeManager.object_type);
409                                 
410                                 RegisterCompilerGeneratedType (impl_details_class);
411                         }
412
413                         fb = impl_details_class.DefineInitializedData (
414                                 "$$field-" + (field_count++), data,
415                                 FieldAttributes.Static | FieldAttributes.Assembly);
416                         
417                         return fb;
418                 }
419
420                 public static void CheckUnsafeOption (Location loc, Report Report)
421                 {
422                         if (!Unsafe) {
423                                 Report.Error (227, loc, 
424                                         "Unsafe code requires the `unsafe' command line option to be specified");
425                         }
426                 }
427         }
428 }