2010-01-20 Zoltan Varga <vargaz@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.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
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 ModuleCompiled 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 List<string> 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 List<TypeContainer> type_container_resolve_order;
129
130                 //
131                 // Holds a reference to the Private Implementation Details
132                 // class.
133                 //
134                 static List<TypeBuilder> 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 List<TypeContainer> ();
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 #if NET_4_0
174                         MetadataCompatibilityVersion = MetadataVersion.v4;
175 #else
176                         MetadataCompatibilityVersion = MetadataVersion.v2;
177 #endif
178
179                         //
180                         // Setup default defines
181                         //
182                         AllDefines = new List<string> ();
183                         AddConditional ("__MonoCS__");
184                 }
185
186                 public static void AddConditional (string p)
187                 {
188                         if (AllDefines.Contains (p))
189                                 return;
190                         AllDefines.Add (p);
191                 }
192
193                 public static bool IsConditionalDefined (string value)
194                 {
195                         return AllDefines.Contains (value);
196                 }
197
198                 static public ModuleCompiled ToplevelTypes {
199                         get { return root; }
200                         set { root = value; }
201                 }
202
203                 public static void RegisterOrder (TypeContainer tc)
204                 {
205                         type_container_resolve_order.Add (tc);
206                 }
207                 
208                 // <remarks>
209                 //   This function is used to resolve the hierarchy tree.
210                 //   It processes interfaces, structs and classes in that order.
211                 //
212                 //   It creates the TypeBuilder's as it processes the user defined
213                 //   types.  
214                 // </remarks>
215                 static public void ResolveTree ()
216                 {
217                         root.Resolve ();
218
219                         //
220                         // Interfaces are processed next, as classes and
221                         // structs might inherit from an object or implement
222                         // a set of interfaces, we need to be able to tell
223                         // them appart by just using the TypeManager.
224                         //
225                         foreach (TypeContainer tc in root.Types)
226                                 tc.CreateType ();
227
228                         foreach (TypeContainer tc in root.Types)
229                                 tc.DefineType ();
230
231                         if (root.Delegates != null)
232                                 foreach (Delegate d in root.Delegates) 
233                                         d.DefineType ();
234                 }
235
236                 // <summary>
237                 //   Closes all open types
238                 // </summary>
239                 //
240                 // <remarks>
241                 //   We usually use TypeBuilder types.  When we are done
242                 //   creating the type (which will happen after we have added
243                 //   methods, fields, etc) we need to "Define" them before we
244                 //   can save the Assembly
245                 // </remarks>
246                 static public void CloseTypes ()
247                 {
248                         //
249                         // We do this in two passes, first we close the structs,
250                         // then the classes, because it seems the code needs it this
251                         // way.  If this is really what is going on, we should probably
252                         // make sure that we define the structs in order as well.
253                         //
254                         foreach (TypeContainer tc in type_container_resolve_order){
255                                 if (tc.Kind == MemberKind.Struct && tc.Parent == root){
256                                         tc.CloseType ();
257                                 }
258                         }
259
260                         foreach (TypeContainer tc in type_container_resolve_order){
261                                 if (!(tc.Kind == MemberKind.Struct && tc.Parent == root))
262                                         tc.CloseType ();                                        
263                         }
264                         
265                         if (root.Delegates != null)
266                                 foreach (Delegate d in root.Delegates)
267                                         d.CloseType ();
268
269
270                         //
271                         // If we have a <PrivateImplementationDetails> class, close it
272                         //
273                         if (helper_classes != null){
274                                 foreach (TypeBuilder type_builder in helper_classes) {
275                                         PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (type_builder);
276                                         type_builder.CreateType ();
277                                 }
278                         }
279                         
280                         type_container_resolve_order = null;
281                         helper_classes = null;
282                         //root = null;
283                         TypeManager.CleanUp ();
284                 }
285
286                 /// <summary>
287                 ///   Used to register classes that need to be closed after all the
288                 ///   user defined classes
289                 /// </summary>
290                 public static void RegisterCompilerGeneratedType (TypeBuilder helper_class)
291                 {
292                         if (helper_classes == null)
293                                 helper_classes = new List<TypeBuilder> ();
294
295                         helper_classes.Add (helper_class);
296                 }
297                 
298                 static public DeclSpace PopulateCoreType (TypeContainer root, string name)
299                 {
300                         DeclSpace ds = (DeclSpace) root.GetDefinition (name);
301                         // Core type was imported
302                         if (ds == null)
303                                 return null;
304
305                         ds.Define ();
306                         return ds;
307                 }
308                 
309                 static public void BootCorlib_PopulateCoreTypes ()
310                 {
311                         // Clear -nostdlib flag when object type is imported
312                         if (PopulateCoreType (root, "System.Object") == null)
313                                 RootContext.StdLib = true;
314
315                         PopulateCoreType (root, "System.ValueType");
316                         PopulateCoreType (root, "System.Attribute");
317                         PopulateCoreType (root, "System.Runtime.CompilerServices.IndexerNameAttribute");
318                 }
319                 
320                 // <summary>
321                 //   Populates the structs and classes with fields and methods
322                 // </summary>
323                 //
324                 // This is invoked after all interfaces, structs and classes
325                 // have been defined through `ResolveTree' 
326                 static public void PopulateTypes ()
327                 {
328
329                         if (type_container_resolve_order != null){
330                                 foreach (TypeContainer tc in type_container_resolve_order)
331                                         tc.ResolveType ();
332                                 foreach (TypeContainer tc in type_container_resolve_order) {
333                                         try {
334                                                 tc.Define ();
335                                         } catch (Exception e) {
336                                                 throw new InternalErrorException (tc, e);
337                                         }
338                                 }
339                         }
340
341                         var delegates = root.Delegates;
342                         if (delegates != null){
343                                 foreach (Delegate d in delegates)
344                                         d.Define ();
345                         }
346
347                         //
348                         // Check for cycles in the struct layout
349                         //
350                         if (type_container_resolve_order != null){
351                                 var seen = new Dictionary<TypeContainer, object> ();
352                                 foreach (TypeContainer tc in type_container_resolve_order)
353                                         TypeManager.CheckStructCycles (tc, seen);
354                         }
355                 }
356
357                 static public void EmitCode ()
358                 {
359                         if (type_container_resolve_order != null) {
360                                 foreach (TypeContainer tc in type_container_resolve_order)
361                                         tc.EmitType ();
362
363                                 if (ToplevelTypes.Compiler.Report.Errors > 0)
364                                         return;
365
366                                 foreach (TypeContainer tc in type_container_resolve_order)
367                                         tc.VerifyMembers ();
368                         }
369                         
370                         if (root.Delegates != null) {
371                                 foreach (Delegate d in root.Delegates)
372                                         d.Emit ();
373                         }                       
374
375                         CodeGen.Assembly.Emit (root);
376                         root.Emit ();
377                 }
378                 
379                 //
380                 // Public Field, used to track which method is the public entry
381                 // point.
382                 //
383                 static public Method EntryPoint;
384
385                 //
386                 // These are used to generate unique names on the structs and fields.
387                 //
388                 static int field_count;
389                 
390                 //
391                 // Makes an initialized struct, returns the field builder that
392                 // references the data.  Thanks go to Sergey Chaban for researching
393                 // how to do this.  And coming up with a shorter mechanism than I
394                 // was able to figure out.
395                 //
396                 // This works but makes an implicit public struct $ArrayType$SIZE and
397                 // makes the fields point to it.  We could get more control if we did
398                 // use instead:
399                 //
400                 // 1. DefineNestedType on the impl_details_class with our struct.
401                 //
402                 // 2. Define the field on the impl_details_class
403                 //
404                 static public FieldBuilder MakeStaticData (byte [] data)
405                 {
406                         FieldBuilder fb;
407                         
408                         if (impl_details_class == null){
409                                 impl_details_class = ToplevelTypes.Builder.DefineType (
410                                         "<PrivateImplementationDetails>",
411                                         TypeAttributes.NotPublic,
412                                         TypeManager.object_type);
413                                 
414                                 RegisterCompilerGeneratedType (impl_details_class);
415                         }
416
417                         fb = impl_details_class.DefineInitializedData (
418                                 "$$field-" + (field_count++), data,
419                                 FieldAttributes.Static | FieldAttributes.Assembly);
420                         
421                         return fb;
422                 }
423
424                 public static void CheckUnsafeOption (Location loc, Report Report)
425                 {
426                         if (!Unsafe) {
427                                 Report.Error (227, loc, 
428                                         "Unsafe code requires the `unsafe' command line option to be specified");
429                         }
430                 }
431         }
432 }