X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Frootcontext.cs;h=b429b974de11d5c2ee4ab09df266c47ff387ce9b;hb=5f0dc4802f69745ced8f32b39bd770f7bd134b8f;hp=a16db71a53f818fab9342a3af00fd9021c989fac;hpb=b690b5bb2f6f20823ccbb8c52f2e9189c5cc4862;p=mono.git diff --git a/mcs/mcs/rootcontext.cs b/mcs/mcs/rootcontext.cs index a16db71a53f..b429b974de1 100755 --- a/mcs/mcs/rootcontext.cs +++ b/mcs/mcs/rootcontext.cs @@ -1,7 +1,8 @@ // // rootcontext.cs: keeps track of our tree representation, and assemblies loaded. // -// Author: Miguel de Icaza (miguel@gnu.org) +// Author: Miguel de Icaza (miguel@ximian.com) +// Ravi Pratap (ravi@ximian.com) // // Licensed under the terms of the GNU GPL // @@ -11,108 +12,838 @@ using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; +using System.Diagnostics; -namespace CIR { +namespace Mono.CSharp { public class RootContext { // // Contains the parsed tree // - Tree tree; + static Tree tree; // - // Contains loaded assemblies and our generated code as we go. + // This hashtable contains all of the #definitions across the source code + // it is used by the ConditionalAttribute handler. // - TypeManager type_manager; + public static Hashtable AllDefines = new Hashtable (); + + // + // The list of global attributes (those that target the assembly) + // + static Hashtable global_attributes = new Hashtable (); + + // + // Whether we are being linked against the standard libraries. + // This is only used to tell whether `System.Object' should + // have a parent or not. + // + public static bool StdLib = true; + + // + // 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 parent's list of methods which ones are virtual + // or abstract as well as the parent names (to implement new, + // override). + // + static ArrayList type_container_resolve_order; + static ArrayList interface_resolve_order; + static ArrayList attribute_types; // - // The System.Reflection.Emit CodeGenerator + // Holds a reference to the Private Implementation Details + // class. // - CilCodeGen cg; + static TypeBuilder impl_details_class; - ModuleBuilder mb; + public static int WarningLevel = 2; - public RootContext () + // + // Constructor + // + static RootContext () { tree = new Tree (); - type_manager = new TypeManager (); + interface_resolve_order = new ArrayList (); + type_container_resolve_order = new ArrayList (); } - public TypeManager TypeManager { + static public Tree Tree { get { - return type_manager; + return tree; } } - public Tree Tree { - get { - return tree; + static public string MainClass; + + public static void RegisterOrder (Interface iface) + { + interface_resolve_order.Add (iface); + } + + public static void RegisterOrder (TypeContainer tc) + { + type_container_resolve_order.Add (tc); + } + + public static void RegisterAttribute (TypeContainer tc) + { + if (attribute_types == null) + attribute_types = new ArrayList (); + + attribute_types.Add (tc); + } + + // + // The default compiler checked state + // + static public bool Checked = false; + + // + // Whether to allow Unsafe code + // + static public bool Unsafe = false; + + static string MakeFQN (string nsn, string name) + { + string prefix = (nsn == "" ? "" : nsn + "."); + + return prefix + name; + } + + // + // 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 () + { + // + // Process the attribute types separately and before anything else + // + if (attribute_types != null) + foreach (TypeContainer tc in attribute_types) + tc.DefineType (); + + // + // 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. + // + TypeContainer root = Tree.Types; + + ArrayList ifaces = root.Interfaces; + if (ifaces != null){ + foreach (Interface i in ifaces) + i.DefineType (); } + + + foreach (TypeContainer tc in root.Types) + tc.DefineType (); + + if (root.Delegates != null) + foreach (Delegate d in root.Delegates) + d.DefineType (); + + if (root.Enums != null) + foreach (Enum e in root.Enums) + e.DefineType (); + } - public CilCodeGen CodeGen { - get { - return cg; + static void Error_TypeConflict (string name, Location loc) + { + Report.Error ( + 520, loc, "`" + name + "' conflicts with a predefined type"); + } + + static void Error_TypeConflict (string name) + { + Report.Error ( + 520, "`" + name + "' conflicts with a predefined type"); + } + + // + // Resolves a single class during the corlib bootstrap process + // + static TypeBuilder BootstrapCorlib_ResolveClass (TypeContainer root, string name) + { + object o = root.GetDefinition (name); + if (o == null){ + Report.Error (518, "The predefined type `" + name + "' is not defined"); + return null; } - set { + if (!(o is Class)){ + if (o is DeclSpace){ + DeclSpace d = (DeclSpace) o; + + Error_TypeConflict (name, d.Location); + } else + Error_TypeConflict (name); + + return null; + } + + return ((DeclSpace) o).DefineType (); + } + + // + // Resolves a struct during the corlib bootstrap process + // + static void BootstrapCorlib_ResolveStruct (TypeContainer root, string name) + { + object o = root.GetDefinition (name); + if (o == null){ + Report.Error (518, "The predefined type `" + name + "' is not defined"); + return; + } + + if (!(o is Struct)){ + if (o is DeclSpace){ + DeclSpace d = (DeclSpace) o; + + Error_TypeConflict (name, d.Location); + } else + Error_TypeConflict (name); + + return; + } + + ((DeclSpace) o).DefineType (); + } + + // + // Resolves a struct during the corlib bootstrap process + // + static void BootstrapCorlib_ResolveInterface (TypeContainer root, string name) + { + object o = root.GetDefinition (name); + if (o == null){ + Report.Error (518, "The predefined type `" + name + "' is not defined"); + return; + } + + if (!(o is Interface)){ + if (o is DeclSpace){ + DeclSpace d = (DeclSpace) o; + + Error_TypeConflict (name, d.Location); + } else + Error_TypeConflict (name); + + return; + } + + ((DeclSpace) o).DefineType (); + } + + // + // Resolves a delegate during the corlib bootstrap process + // + static void BootstrapCorlib_ResolveDelegate (TypeContainer root, string name) + { + object o = root.GetDefinition (name); + if (o == null){ + Report.Error (518, "The predefined type `" + name + "' is not defined"); + Environment.Exit (0); + } + + if (!(o is Delegate)){ + Error_TypeConflict (name); + return; + } + + ((DeclSpace) o).DefineType (); + } + + + /// + /// Resolves the core types in the compiler when compiling with --nostdlib + /// + static public void ResolveCore () + { + TypeContainer root = Tree.Types; + + TypeManager.object_type = BootstrapCorlib_ResolveClass (root, "System.Object"); + TypeManager.value_type = BootstrapCorlib_ResolveClass (root, "System.ValueType"); + TypeManager.attribute_type = BootstrapCorlib_ResolveClass (root, "System.Attribute"); + + string [] interfaces_first_stage = { + "System.IComparable", "System.ICloneable", + "System.IConvertible", + + "System.Collections.IEnumerable", + "System.Collections.ICollection", + "System.Collections.IEnumerator", + "System.Collections.IList", + "System.IAsyncResult", + "System.IDisposable", + + "System.Runtime.Serialization.ISerializable", + + "System.Reflection.IReflect", + "System.Reflection.ICustomAttributeProvider" + }; + + foreach (string iname in interfaces_first_stage) + BootstrapCorlib_ResolveInterface (root, iname); + + // + // These are the base value types + // + string [] structs_first_stage = { + "System.Byte", "System.SByte", + "System.Int16", "System.UInt16", + "System.Int32", "System.UInt32", + "System.Int64", "System.UInt64", + }; + + foreach (string cname in structs_first_stage) + BootstrapCorlib_ResolveStruct (root, cname); + + // + // Now, we can load the enumerations, after this point, + // we can use enums. + // + TypeManager.InitEnumUnderlyingTypes (); + + string [] structs_second_stage = { + "System.Single", "System.Double", + "System.Char", "System.Boolean", + "System.Decimal", "System.Void", + "System.RuntimeFieldHandle", + "System.RuntimeTypeHandle", + "System.IntPtr" + }; + + foreach (string cname in structs_second_stage) + BootstrapCorlib_ResolveStruct (root, cname); + + // + // These are classes that depends on the core interfaces + // + string [] classes_second_stage = { + "System.Reflection.MemberInfo", + "System.Type", + "System.Exception", + // - // Temporary hack, we should probably - // intialize `cg' rather than depending on - // external initialization of it. + // These are not really important in the order, but they + // are used by the compiler later on (typemanager/CoreLookupType-d) // - cg = value; - mb = cg.ModuleBuilder; + "System.Runtime.CompilerServices.RuntimeHelpers", + "System.Reflection.DefaultMemberAttribute", + "System.Threading.Monitor", + + "System.AttributeUsageAttribute", + "System.Runtime.InteropServices.DllImportAttribute", + "System.Runtime.CompilerServices.MethodImplAttribute", + "System.Runtime.InteropServices.MarshalAsAttribute", + "System.Diagnostics.ConditionalAttribute", + "System.ObsoleteAttribute", + "System.ParamArrayAttribute", + "System.Security.UnverifiableCodeAttribute", + "System.Runtime.CompilerServices.IndexerNameAttribute", + "System.Runtime.InteropServices.InAttribute" + }; + + // We must store them here before calling BootstrapCorlib_ResolveDelegate. + TypeManager.string_type = BootstrapCorlib_ResolveClass (root, "System.String"); + TypeManager.enum_type = BootstrapCorlib_ResolveClass (root, "System.Enum"); + TypeManager.array_type = BootstrapCorlib_ResolveClass (root, "System.Array"); + TypeManager.multicast_delegate_type = BootstrapCorlib_ResolveClass (root, "System.MulticastDelegate"); + TypeManager.delegate_type = BootstrapCorlib_ResolveClass (root, "System.Delegate"); + + foreach (string cname in classes_second_stage) + BootstrapCorlib_ResolveClass (root, cname); + + BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback"); + } + + // + // 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 () + { + TypeContainer root = Tree.Types; + + ArrayList ifaces = root.Interfaces; + + if (root.Enums != null) + foreach (Enum en in root.Enums) + en.CloseType (); + + if (attribute_types != null) + foreach (TypeContainer tc in attribute_types) + tc.CloseType (); + + foreach (Interface iface in interface_resolve_order) + iface.CloseType (); + + // + // 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 is Struct && tc.Parent == tree.Types){ + tc.CloseType (); + } + } + + foreach (TypeContainer tc in type_container_resolve_order){ + if (!(tc is Struct && tc.Parent == tree.Types)) + tc.CloseType (); + } + + if (root.Delegates != null) + foreach (Delegate d in root.Delegates) + d.CloseType (); + + + // + // If we have a class, close it + // + if (impl_details_class != null){ + impl_details_class.CreateType (); } } // - // Creates the Interface @iface using the ModuleBuilder + // This idea is from Felix Arrese-Igor // - // TODO: - // Resolve recursively dependencies. + // Returns : the implicit parent of a composite namespace string + // eg. Implicit parent of A.B is A // - bool CreateInterface (Interface iface) + static public string ImplicitParent (string ns) { - TypeBuilder tb; - string name = iface.Name; + int i = ns.LastIndexOf ("."); + if (i < 0) + return null; + + return ns.Substring (0, i); + } - if (iface.InTransit) - return false; + static Type NamespaceLookup (Namespace curr_ns, string name, Location loc) + { + Type t; + + // + // Try in the current namespace and all its implicit parents + // + for (string ns = curr_ns.Name; ns != null; ns = ImplicitParent (ns)) { + t = TypeManager.LookupType (MakeFQN (ns, name)); + if (t != null) + return t; + } - iface.InTransit = true; - tb = mb.DefineType (name, - TypeAttributes.Interface | - TypeAttributes.Public | - TypeAttributes.Abstract); - tb.CreateType (); - iface.Definition = tb; + // + // It's possible that name already is fully qualified. So we do + // a simple direct lookup without adding any namespace names + // + t = TypeManager.LookupType (name); + if (t != null) + return t; // - // if Recursive_Def (child) == false - // error (child.Name recursive def with iface.Name) + // Try the aliases in the current namespace // - type_manager.AddType (name, tb); + string alias = curr_ns.LookupAlias (name); + + if (alias != null) { + t = TypeManager.LookupType (alias); + if (t != null) + return t; + + t = TypeManager.LookupType (MakeFQN (alias, name)); + if (t != null) + return t; + } + + for (Namespace ns = curr_ns; ns != null; ns = ns.Parent) { + // + // Look in the namespace ns + // + t = TypeManager.LookupType (MakeFQN (ns.Name, name)); + if (t != null) + return t; + + // + // Then try with the using clauses + // + ArrayList using_list = ns.UsingTable; + + if (using_list == null) + continue; + + Type match = null; + foreach (Namespace.UsingEntry ue in using_list) { + match = TypeManager.LookupType (MakeFQN (ue.Name, name)); + if (match != null){ + if (t != null){ + DeclSpace.Error_AmbiguousTypeReference (loc, name, t, match); + return null; + } + + t = match; + ue.Used = true; + } + } + if (t != null) + return t; + + // + // Try with aliases + // + string a = ns.LookupAlias (name); + if (a != null) { + t = TypeManager.LookupType (a); + if (t != null) + return t; - iface.InTransit = false; - return true; + t = TypeManager.LookupType (MakeFQN (a, name)); + if (t != null) + return t; + } + } + + return null; } - public void ResolveInterfaceBases () + // + // Public function used to locate types, this can only + // be used after the ResolveTree function has been invoked. + // + // Returns: Type or null if they type can not be found. + // + // Come to think of it, this should be a DeclSpace + // + static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc) { - ArrayList ifaces = tree.Interfaces; + Type t; + + if (ds.Cache.Contains (name)){ + t = (Type) ds.Cache [name]; + if (t != null) + return t; + } else { + // + // For the case the type we are looking for is nested within this one + // or is in any base class + // + DeclSpace containing_ds = ds; + while (containing_ds != null){ + Type current_type = containing_ds.TypeBuilder; + + while (current_type != null) { + // + // nested class + // + t = TypeManager.LookupType (current_type.FullName + "." + name); + if (t != null){ + ds.Cache [name] = t; + return t; + } + + current_type = current_type.BaseType; + } + + containing_ds = containing_ds.Parent; + } + + t = NamespaceLookup (ds.Namespace, name, loc); + if (t != null){ + ds.Cache [name] = t; + return t; + } + } + + if (!silent) + Report.Error (246, loc, "Cannot find type `"+name+"'"); + + return null; + } - foreach (Interface iface in ifaces){ - string name = iface.Name; + // + // This is the silent version of LookupType, you can use this + // to `probe' for a type + // + static public Type LookupType (TypeContainer tc, string name, Location loc) + { + return LookupType (tc, name, true, loc); + } - DefineInterface (iface); + static public bool IsNamespace (string name) + { + Namespace ns; + + if (tree.Namespaces != null){ + ns = (Namespace) tree.Namespaces [name]; + + if (ns != null) + return true; } + + return false; } - public void ResolveClassBases () + static void Report1530 (Location loc) + { + Report.Error (1530, loc, "Keyword new not allowed for namespace elements"); + } + + static public void PopulateCoreType (TypeContainer root, string name) { + DeclSpace ds = (DeclSpace) root.GetDefinition (name); + + ds.DefineMembers (root); + ds.Define (root); + } + + static public void BootCorlib_PopulateCoreTypes () + { + TypeContainer root = tree.Types; + + PopulateCoreType (root, "System.Object"); + PopulateCoreType (root, "System.ValueType"); + PopulateCoreType (root, "System.Attribute"); + } + + // + // 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 () + { + TypeContainer root = Tree.Types; + + if (attribute_types != null) + foreach (TypeContainer tc in attribute_types) + tc.DefineMembers (root); + + if (interface_resolve_order != null){ + foreach (Interface iface in interface_resolve_order) + if ((iface.ModFlags & Modifiers.NEW) == 0) + iface.DefineMembers (root); + else + Report1530 (iface.Location); + } + + + if (type_container_resolve_order != null){ + if (RootContext.StdLib){ + foreach (TypeContainer tc in type_container_resolve_order) { + if ((tc.ModFlags & Modifiers.NEW) == 0) + tc.DefineMembers (root); + else + Report1530 (tc.Location); + } + } else { + foreach (TypeContainer tc in type_container_resolve_order) { + // When compiling corlib, these types have already been + // populated from BootCorlib_PopulateCoreTypes (). + if (((tc.Name == "System.Object") || + (tc.Name == "System.Attribute") || + (tc.Name == "System.ValueType"))) + continue; + + if ((tc.ModFlags & Modifiers.NEW) == 0) + tc.DefineMembers (root); + else + Report1530 (tc.Location); + } + } + } + + ArrayList delegates = root.Delegates; + if (delegates != null){ + foreach (Delegate d in delegates) + if ((d.ModFlags & Modifiers.NEW) == 0) + d.DefineMembers (root); + else + Report1530 (d.Location); + } + + ArrayList enums = root.Enums; + if (enums != null){ + foreach (Enum en in enums) + if ((en.ModFlags & Modifiers.NEW) == 0) + en.DefineMembers (root); + else + Report1530 (en.Location); + } + } + + static public void DefineTypes () + { + TypeContainer root = Tree.Types; + + if (attribute_types != null) + foreach (TypeContainer tc in attribute_types) + tc.Define (root); + + if (interface_resolve_order != null){ + foreach (Interface iface in interface_resolve_order) + if ((iface.ModFlags & Modifiers.NEW) == 0) + iface.Define (root); + } + + + 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"))) + continue; + + if ((tc.ModFlags & Modifiers.NEW) == 0) + tc.Define (root); + } + } + + ArrayList delegates = root.Delegates; + if (delegates != null){ + foreach (Delegate d in delegates) + if ((d.ModFlags & Modifiers.NEW) == 0) + d.Define (root); + } + + ArrayList enums = root.Enums; + if (enums != null){ + foreach (Enum en in enums) + if ((en.ModFlags & Modifiers.NEW) == 0) + en.Define (root); + } + } + + static public void EmitCode () + { + // + // Because of the strange way in which we do things, global + // attributes must be processed first. + // + if (global_attributes.Count > 0){ + AssemblyBuilder ab = CodeGen.AssemblyBuilder; + TypeContainer dummy = new TypeContainer (null, "", new Location (-1)); + EmitContext temp_ec = new EmitContext ( + dummy, Mono.CSharp.Location.Null, null, null, 0, false); + + foreach (DictionaryEntry de in global_attributes){ + Namespace ns = (Namespace) de.Key; + Attributes attrs = (Attributes) de.Value; + + dummy.Namespace = ns; + Attribute.ApplyAttributes (temp_ec, ab, ab, attrs); + } + } + + if (attribute_types != null) + foreach (TypeContainer tc in attribute_types) + tc.Emit (); + + if (type_container_resolve_order != null) { + foreach (TypeContainer tc in type_container_resolve_order) + tc.EmitConstants (); + + foreach (TypeContainer tc in type_container_resolve_order) + tc.Emit (); + } + + if (Unsafe) { + if (TypeManager.unverifiable_code_ctor == null) { + Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute."); + return; + } + + CustomAttributeBuilder cb = new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, + new object [0]); + CodeGen.ModuleBuilder.SetCustomAttribute (cb); + } + } + + // + // 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; + int size = data.Length; + + if (impl_details_class == null) + impl_details_class = CodeGen.ModuleBuilder.DefineType ( + "", TypeAttributes.NotPublic, TypeManager.object_type); + + fb = impl_details_class.DefineInitializedData ( + "$$field-" + (field_count++), data, + FieldAttributes.Static | FieldAttributes.Assembly); + + return fb; + } + + // + // Adds a global attribute that was declared in `container', + // the attribute is in `attr', and it was defined at `loc' + // + static public void AddGlobalAttributeSection (TypeContainer container, AttributeSection attr) + { + Namespace ns = container.Namespace; + Attributes a = (Attributes) global_attributes [ns]; + + if (a == null) + global_attributes [ns] = new Attributes (attr); + else + a.AddAttributeSection (attr); } } } +