📄 codegen.cs
字号:
//// codegen.cs: The code generator//// Author:// Miguel de Icaza (miguel@ximian.com)//// (C) 2001, 2002, 2003 Ximian, Inc.// (C) 2004 Novell, Inc.//#if !DEBUG #define PRODUCTION#endifusing System;using System.IO;using System.Collections;using System.Collections.Specialized;using System.Reflection;using System.Reflection.Emit;using System.Runtime.InteropServices;using System.Security;using System.Security.Cryptography;using System.Security.Permissions;using Mono.Security.Cryptography;namespace Mono.CSharp { /// <summary> /// Code generator class. /// </summary> public class CodeGen { static AppDomain current_domain; static public SymbolWriter SymbolWriter; public static AssemblyClass Assembly; public static ModuleClass Module; static CodeGen () { Reset (); } public static void Reset () { Assembly = new AssemblyClass (); Module = new ModuleClass (RootContext.Unsafe); } public static string Basename (string name) { int pos = name.LastIndexOf ('/'); if (pos != -1) return name.Substring (pos + 1); pos = name.LastIndexOf ('\\'); if (pos != -1) return name.Substring (pos + 1); return name; } public static string Dirname (string name) { int pos = name.LastIndexOf ('/'); if (pos != -1) return name.Substring (0, pos); pos = name.LastIndexOf ('\\'); if (pos != -1) return name.Substring (0, pos); return "."; } static public string FileName; // // Initializes the symbol writer // static void InitializeSymbolWriter (string filename) { SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder, filename); // // If we got an ISymbolWriter instance, initialize it. // if (SymbolWriter == null) { Report.Warning ( -18, "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CompilerServices.SymbolWriter directory."); return; } } // // Initializes the code generator variables // static public bool Init (string name, string output, bool want_debugging_support) { FileName = output; AssemblyName an = Assembly.GetAssemblyName (name, output); if (an == null) return false; if (an.KeyPair != null) { // If we are going to strong name our assembly make // sure all its refs are strong named foreach (Assembly a in RootNamespace.Global.Assemblies) { AssemblyName ref_name = a.GetName (); byte [] b = ref_name.GetPublicKeyToken (); if (b == null || b.Length == 0) { Report.Warning (1577, "Assembly generation failed " + "-- Referenced assembly '" + ref_name.Name + "' does not have a strong name."); //Environment.Exit (1); } } } current_domain = AppDomain.CurrentDomain; try { Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Save, Dirname (name)); } catch (ArgumentException) { // specified key may not be exportable outside it's container if (RootContext.StrongNameKeyContainer != null) { Report.Error (1548, "Could not access the key inside the container `" + RootContext.StrongNameKeyContainer + "'."); Environment.Exit (1); } return false; } catch (CryptographicException) { if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) { Report.Error (1548, "Could not use the specified key to strongname the assembly."); Environment.Exit (1); } return false; } // // Pass a path-less name to DefineDynamicModule. Wonder how // this copes with output in different directories then. // FIXME: figure out how this copes with --output /tmp/blah // // If the third argument is true, the ModuleBuilder will dynamically // load the default symbol writer. // Module.Builder = Assembly.Builder.DefineDynamicModule ( Basename (name), Basename (output), false); if (want_debugging_support) InitializeSymbolWriter (output); return true; } static public void Save (string name) { try { Assembly.Builder.Save (Basename (name)); } catch (COMException) { if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign)) throw; // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies Report.Error (1548, "Couldn't delay-sign the assembly with the '" + RootContext.StrongNameKeyFile + "', Use MCS with the Mono runtime or CSC to compile this assembly."); } catch (System.IO.IOException io) { Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message); } catch (System.UnauthorizedAccessException ua) { Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message); } if (SymbolWriter != null) SymbolWriter.WriteSymbolFile (); } } /// <summary> /// An Emit Context is created for each body of code (from methods, /// properties bodies, indexer bodies or constructor bodies) /// </summary> public class EmitContext { public readonly DeclSpace DeclSpace; public DeclSpace TypeContainer; public ILGenerator ig; /// <summary> /// This variable tracks the `checked' state of the compilation, /// it controls whether we should generate code that does overflow /// checking, or if we generate code that ignores overflows. /// /// The default setting comes from the command line option to generate /// checked or unchecked code plus any source code changes using the /// checked/unchecked statements or expressions. Contrast this with /// the ConstantCheckState flag. /// </summary> public bool CheckState; /// <summary> /// The constant check state is always set to `true' and cant be changed /// from the command line. The source code can change this setting with /// the `checked' and `unchecked' statements and expressions. /// </summary> public bool ConstantCheckState; /// <summary> /// Whether we are emitting code inside a static or instance method /// </summary> public bool IsStatic; /// <summary> /// Whether the actual created method is static or instance method. /// Althoug the method might be declared as `static', if an anonymous /// method is involved, we might turn this into an instance method. /// /// So this reflects the low-level staticness of the method, while /// IsStatic represents the semantic, high-level staticness. /// </summary> public bool MethodIsStatic; /// <summary> /// Whether we are emitting a field initializer /// </summary> public bool IsFieldInitializer; /// <summary> /// The value that is allowed to be returned or NULL if there is no /// return type. /// </summary> public Type ReturnType; /// <summary> /// Points to the Type (extracted from the TypeContainer) that /// declares this body of code /// </summary> public Type ContainerType; /// <summary> /// Whether this is generating code for a constructor /// </summary> public bool IsConstructor; /// <summary> /// Whether we're control flow analysis enabled /// </summary> public bool DoFlowAnalysis; /// <summary> /// Whether we're control flow analysis disabled on struct /// </summary> public bool OmitStructFlowAnalysis; /// <summary> /// Keeps track of the Type to LocalBuilder temporary storage created /// to store structures (used to compute the address of the structure /// value on structure method invocations) /// </summary> public Hashtable temporary_storage; public Block CurrentBlock; public int CurrentFile; /// <summary> /// The location where we store the return value. /// </summary> LocalBuilder return_value; /// <summary> /// The location where return has to jump to return the /// value /// </summary> public Label ReturnLabel; /// <summary> /// If we already defined the ReturnLabel /// </summary> public bool HasReturnLabel; /// <summary> /// Whether we are inside an iterator block. /// </summary> public bool InIterator; public bool IsLastStatement; /// <summary> /// Whether we are inside an unsafe block /// </summary> public bool InUnsafe; /// <summary> /// Whether we are in a `fixed' initialization /// </summary> public bool InFixedInitializer; public bool InRefOutArgumentResolving; public bool InCatch; public bool InFinally; /// <summary> /// Whether we are inside an anonymous method. /// </summary> public AnonymousContainer CurrentAnonymousMethod; /// <summary> /// Location for this EmitContext /// </summary> public Location loc; /// <summary> /// Inside an enum definition, we do not resolve enumeration values /// to their enumerations, but rather to the underlying type/value /// This is so EnumVal + EnumValB can be evaluated. /// /// There is no "E operator + (E x, E y)", so during an enum evaluation /// we relax the rules /// </summary> public bool InEnumContext; /// <summary> /// Anonymous methods can capture local variables and fields, /// this object tracks it. It is copied from the TopLevelBlock /// field. /// </summary> public CaptureContext capture_context; /// <summary> /// Trace when method is called and is obsolete then this member suppress message /// when call is inside next [Obsolete] method or type. /// </summary> public bool TestObsoleteMethodUsage = true; /// <summary> /// The current iterator /// </summary> public Iterator CurrentIterator; /// <summary> /// Whether we are in the resolving stage or not /// </summary> enum Phase { Created, Resolving, Emitting } Phase current_phase; FlowBranching current_flow_branching; static int next_id = 0; int id = ++next_id; public override string ToString () { return String.Format ("EmitContext ({0}:{1}:{2})", id, CurrentIterator, capture_context, loc); } public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig, Type return_type, int code_flags, bool is_constructor) { this.ig = ig; TypeContainer = parent; DeclSpace = ds; CheckState = RootContext.Checked; ConstantCheckState = true; IsStatic = (code_flags & Modifiers.STATIC) != 0; MethodIsStatic = IsStatic; InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0; ReturnType = return_type; IsConstructor = is_constructor; CurrentBlock = null; CurrentFile = 0; current_phase = Phase.Created; if (parent != null){ // Can only be null for the ResolveType contexts. ContainerType = parent.TypeBuilder; if (parent.UnsafeContext) InUnsafe = true; else InUnsafe = (code_flags & Modifiers.UNSAFE) != 0; } loc = l; if (ReturnType == TypeManager.void_type) ReturnType = null; } public EmitContext (TypeContainer tc, Location l, ILGenerator ig, Type return_type, int code_flags, bool is_constructor) : this (tc, tc, l, ig, return_type, code_flags, is_constructor) { } public EmitContext (TypeContainer tc, Location l, ILGenerator ig, Type return_type, int code_flags) : this (tc, tc, l, ig, return_type, code_flags, false) { } public FlowBranching CurrentBranching { get { return current_flow_branching; } } public bool HaveCaptureInfo { get { return capture_context != null; } } // <summary> // Starts a new code branching. This inherits the state of all local // variables and parameters from the current branching. // </summary> public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc) { current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc); return current_flow_branching; } // <summary> // Starts a new code branching for block `block'. // </summary> public FlowBranching StartFlowBranching (Block block) { FlowBranching.BranchingType type; if ((CurrentBranching != null) && (CurrentBranching.Type == FlowBranching.BranchingType.Switch)) type = FlowBranching.BranchingType.SwitchSection; else type = FlowBranching.BranchingType.Block; DoFlowAnalysis = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -