//
// rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
//
// Author: Miguel de Icaza (miguel@ximian.com)
// Ravi Pratap (ravi@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2008 Novell, Inc
using System;
using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
namespace Mono.CSharp {
public enum LanguageVersion
{
ISO_1 = 1,
Default_MCS = 2,
ISO_2 = 3,
LINQ = 4,
#if GMCS_SOURCE
Default = LINQ
#else
Default = Default_MCS
#endif
}
public class RootContext {
//
// COMPILER OPTIONS CLASS
//
public static Target Target;
public static string TargetExt;
public static bool VerifyClsCompliance = true;
public static bool Optimize = true;
public static LanguageVersion Version;
//
// We keep strongname related info here because
// it's also used as complier options from CSC 8.x
//
public static string StrongNameKeyFile;
public static string StrongNameKeyContainer;
public static bool StrongNameDelaySign;
//
// If set, enable XML documentation generation
//
public static Documentation Documentation;
static public string MainClass;
//
// The default compiler checked state
//
static public bool Checked;
//
// Whether to allow Unsafe code
//
static public bool Unsafe;
//
// Whether we are being linked against the standard libraries.
// This is only used to tell whether `System.Object' should
// have a base class or not.
//
public static bool StdLib;
public static bool NeedsEntryPoint {
get { return Target == Target.Exe || Target == Target.WinExe; }
}
//
// COMPILER OPTIONS CLASS END
//
//
// Contains the parsed tree
//
static RootTypes root;
//
// This hashtable contains all of the #definitions across the source code
// it is used by the ConditionalAttribute handler.
//
public static Hashtable AllDefines = new Hashtable ();
//
// This keeps track of the order in which classes were defined
// so that we can poulate them in that order.
//
// Order is important, because we need to be able to tell, by
// examining the list of methods of the base class, which ones are virtual
// or abstract as well as the parent names (to implement new,
// override).
//
static ArrayList type_container_resolve_order;
//
// Holds a reference to the Private Implementation Details
// class.
//
static ArrayList helper_classes;
static TypeBuilder impl_details_class;
//
// Constructor
//
static RootContext ()
{
Reset ();
}
public static void Reset ()
{
root = new RootTypes ();
type_container_resolve_order = new ArrayList ();
EntryPoint = null;
Report.WarningLevel = 3;
Checked = false;
Unsafe = false;
StdLib = true;
StrongNameKeyFile = null;
StrongNameKeyContainer = null;
StrongNameDelaySign = false;
MainClass = null;
Target = Target.Exe;
TargetExt = ".exe";
Version = LanguageVersion.Default;
Documentation = null;
impl_details_class = null;
helper_classes = null;
}
static public RootTypes ToplevelTypes {
get { return root; }
}
public static void RegisterOrder (TypeContainer tc)
{
type_container_resolve_order.Add (tc);
}
//
// This function is used to resolve the hierarchy tree.
// It processes interfaces, structs and classes in that order.
//
// It creates the TypeBuilder's as it processes the user defined
// types.
//
static public void ResolveTree ()
{
//
// Interfaces are processed next, as classes and
// structs might inherit from an object or implement
// a set of interfaces, we need to be able to tell
// them appart by just using the TypeManager.
//
foreach (TypeContainer tc in root.Types)
tc.CreateType ();
foreach (TypeContainer tc in root.Types)
tc.DefineType ();
if (root.Delegates != null)
foreach (Delegate d in root.Delegates)
d.DefineType ();
}
//
// Closes all open types
//
//
//
// We usually use TypeBuilder types. When we are done
// creating the type (which will happen after we have added
// methods, fields, etc) we need to "Define" them before we
// can save the Assembly
//
static public void CloseTypes ()
{
//
// We do this in two passes, first we close the structs,
// then the classes, because it seems the code needs it this
// way. If this is really what is going on, we should probably
// make sure that we define the structs in order as well.
//
foreach (TypeContainer tc in type_container_resolve_order){
if (tc.Kind == Kind.Struct && tc.Parent == root){
tc.CloseType ();
}
}
foreach (TypeContainer tc in type_container_resolve_order){
if (!(tc.Kind == Kind.Struct && tc.Parent == root))
tc.CloseType ();
}
if (root.Delegates != null)
foreach (Delegate d in root.Delegates)
d.CloseType ();
//
// If we have a class, close it
//
if (helper_classes != null){
foreach (TypeBuilder type_builder in helper_classes) {
#if GMCS_SOURCE
type_builder.SetCustomAttribute (TypeManager.GetCompilerGeneratedAttribute (Location.Null));
#endif
type_builder.CreateType ();
}
}
type_container_resolve_order = null;
helper_classes = null;
//root = null;
TypeManager.CleanUp ();
}
///
/// Used to register classes that need to be closed after all the
/// user defined classes
///
public static void RegisterCompilerGeneratedType (TypeBuilder helper_class)
{
if (helper_classes == null)
helper_classes = new ArrayList ();
helper_classes.Add (helper_class);
}
static public void PopulateCoreType (TypeContainer root, string name)
{
DeclSpace ds = (DeclSpace) root.GetDefinition (name);
// Core type was imported
if (ds == null)
return;
ds.DefineMembers ();
ds.Define ();
}
static public void BootCorlib_PopulateCoreTypes ()
{
PopulateCoreType (root, "System.Object");
PopulateCoreType (root, "System.ValueType");
PopulateCoreType (root, "System.Attribute");
PopulateCoreType (root, "System.Runtime.CompilerServices.IndexerNameAttribute");
}
//
// Populates the structs and classes with fields and methods
//
//
// This is invoked after all interfaces, structs and classes
// have been defined through `ResolveTree'
static public void PopulateTypes ()
{
if (type_container_resolve_order != null){
foreach (TypeContainer tc in type_container_resolve_order)
tc.ResolveType ();
foreach (TypeContainer tc in type_container_resolve_order)
tc.DefineMembers ();
}
ArrayList delegates = root.Delegates;
if (delegates != null){
foreach (Delegate d in delegates)
d.DefineMembers ();
}
//
// Check for cycles in the struct layout
//
if (type_container_resolve_order != null){
Hashtable seen = new Hashtable ();
foreach (TypeContainer tc in type_container_resolve_order)
TypeManager.CheckStructCycles (tc, seen);
}
}
//
// DefineTypes is used to fill in the members of each type.
//
static public void DefineTypes ()
{
ArrayList delegates = root.Delegates;
if (delegates != null){
foreach (Delegate d in delegates)
d.Define ();
}
if (type_container_resolve_order != null){
foreach (TypeContainer tc in type_container_resolve_order) {
// When compiling corlib, these types have already been
// populated from BootCorlib_PopulateCoreTypes ().
if (!RootContext.StdLib &&
((tc.Name == "System.Object") ||
(tc.Name == "System.Attribute") ||
(tc.Name == "System.ValueType") ||
(tc.Name == "System.Runtime.CompilerServices.IndexerNameAttribute")))
continue;
tc.Define ();
}
}
}
static public void EmitCode ()
{
if (type_container_resolve_order != null) {
foreach (TypeContainer tc in type_container_resolve_order)
tc.EmitType ();
if (Report.Errors > 0)
return;
foreach (TypeContainer tc in type_container_resolve_order)
tc.VerifyMembers ();
}
if (root.Delegates != null) {
foreach (Delegate d in root.Delegates)
d.Emit ();
}
CodeGen.Assembly.Emit (root);
CodeGen.Module.Emit (root);
}
//
// Public Field, used to track which method is the public entry
// point.
//
static public MethodInfo EntryPoint;
//
// Track the location of the entry point.
//
static public Location EntryPointLocation;
//
// These are used to generate unique names on the structs and fields.
//
static int field_count;
//
// 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
//
static public FieldBuilder MakeStaticData (byte [] data)
{
FieldBuilder fb;
if (impl_details_class == null){
impl_details_class = CodeGen.Module.Builder.DefineType (
"",
TypeAttributes.NotPublic,
TypeManager.object_type);
RegisterCompilerGeneratedType (impl_details_class);
}
fb = impl_details_class.DefineInitializedData (
"$$field-" + (field_count++), data,
FieldAttributes.Static | FieldAttributes.Assembly);
return fb;
}
public static void CheckUnsafeOption (Location loc)
{
if (!Unsafe) {
Report.Error (227, loc,
"Unsafe code requires the `unsafe' command line option to be specified");
}
}
}
}