⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emitcodegen.cs

📁 charp compiler
💻 CS
📖 第 1 页 / 共 5 页
字号:
                   
        string stName = stParent + "+" + args.Name;
        //string stName = args.Name;
        
        #if false
        // Debugging help
        Type [] ts = m_bldModule.GetTypes();
        foreach(Type t2 in ts)
        {
            Console.WriteLine("{0},{1}", t2.FullName, t2.GetType());            
        }
        #endif
    
        // ...
        // The ResolveCreateType() event is fundamentally broken for Emit in V1 of .NET.
        // The args just give us the short name of a class (ex 'B'). So we don't know 
        // if the class is a nested (really 'A+B') or a value type field.
        // Since we get an ambiguous name, we have to guess what it really is
        // But we may guess wrong. It could be either a nested class or a valuetype field.
        // Assume the nested class (more common) and assert elsewise. 
        // Until this dumb bug is fixed, we can't do any better.        
        //
        // What this means is that we can't build nested-types with the same flexibility as
        // CSC.exe. (JScript, which uses Emit, also ahas the same problem).
        Type t = ModuleBuilder_GetType(m_bldModule, stName);
        Debug.Assert(t != null, "@todo - Can't find class '" + stName + "'. This may be due to a bug in emit regarding nested classes.");
            
        // If the type isn't already baked, then bake it.        
        System.Reflection.Emit.TypeBuilder tb = t as System.Reflection.Emit.TypeBuilder;
        if (tb != null)
        {
            CreateType(tb);
        } else {
            Log.WriteLine(Log.LF.CodeGen, "'{0}' already created.", stName);
        }
        
        
        // We're suppose to return the assembly that the type was found in.
        // That's just the assembly we're creating.
        return this.m_bldModule.Assembly;
    }
    
    
    //-------------------------------------------------------------------------
    // Given an array of the assemblies that we reference (not including mscorlib)
    // return a CLRTypeProvider for symbol resolution to use.
    //-------------------------------------------------------------------------
    public virtual ICLRtypeProvider GetProvider(Assembly [] assemblyRefs)
    {
        SetImportedAssemblies(assemblyRefs);
        return this;
    }

    /***************************************************************************\
    *
    * EmitCodeGen.BeginOutput
    *
    * BeginOutput() initializes CodeGen for output to a specific file.
    *
    \***************************************************************************/
    
    public virtual void
    BeginOutput(       
        string [] stFilenames)
    {
        // We know that all of the options have been processed by this point.
        
        // If no output filename was supplied via /out, then use the first
        // name in the stFilenames list with the appropriate extension
        if (m_stOutputName == null)
        {
            string stDefault = stFilenames[0];
            
            string stExt = "";
            switch(m_TargetType)
            {
                case TargetType.Dll:
                    stExt = "dll"; break;
                case TargetType.Console:
                case TargetType.Windows:
                    stExt = "exe"; break;
            }
            
            m_stOutputName = System.IO.Path.ChangeExtension(stDefault, stExt);
        }
        
        string stShortName = System.IO.Path.GetFileNameWithoutExtension(m_stOutputName);
       
            
        m_alClasses         = new ArrayList();
                                    
		m_domain            = Thread.GetDomain();
        if (m_domain == null)
        {
            throw new AppDomainUnloadedException("Unable to retrieve AppDomain");
        }


        //
        // Setup the AssemblyName
        //

		AssemblyName asmName = new AssemblyName();

		// Note that we must exclude the extension or fusion gets confused.
		// Specifiy the full filename when we save
               
		asmName.Name = stShortName;


        //
        // Create a ModuleBuilder for our output executable file
        //

		//m_bldAssembly = m_domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
		m_bldAssembly = m_domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Save);
        Debug.Assert(m_bldAssembly != null);

		m_bldModule = m_bldAssembly.DefineDynamicModule(m_stOutputName, m_stOutputName, m_fDebugInfo);
        Debug.Assert(m_bldModule != null);


        // Hook up the event listening.        
        m_resolveHandler = new ResolveEventHandler(this.ResolveCreateType);
        m_domain.TypeResolve += m_resolveHandler;


        // Create all the PDB documents
        if (m_fDebugInfo)
        {
            // @todo - can we totally replace m_symWriter w/ emit?
            m_symWriter = m_bldModule.GetSymWriter();
            Guid g = Guid.Empty;
            
            m_stFilenames = stFilenames;
            m_symDocs = new ISymbolDocumentWriter[stFilenames.Length];
            for(int i = 0; i < stFilenames.Length; i++)
            {            
                m_symDocs[i] = 
                    m_symWriter.DefineDocument(stFilenames[i], 
                    g, 
                    g, 
                    g);
                Debug.Assert(m_symDocs[i] != null);                    
            }
        }
        
        // Get some standard hooks
        // Codegen for typeof(t) must call 'System.Type::GetTypeFromHandle()'
        // So get the methodinfo for that ahead of time.
        System.Type t = typeof(Type);        
        m_infoGetTypeFromHandle = t.GetMethod("GetTypeFromHandle");
        Debug.Assert(m_infoGetTypeFromHandle != null);
    }

    // Lookup a string filename to get the PDB document info    
    void SetCurrentDebugDocument(FileRange location)
    {
        // Nothing to do if we're not setting debug information.
        if (!m_fDebugInfo)
            return;
            
        string stFilename = location.Filename;
        
        // We know m_symDocs & m_stFilenames are parallel arrays.
        // So search the string array and return from the doc array.
        for(int i = 0; i < m_stFilenames.Length; i++)
        {
            if (m_stFilenames[i] == stFilename)
            {
                m_symCurrentDoc = m_symDocs[i];
                return;
            }
        }
        
        Debug.Assert(false, "Unknown document:" + stFilename);        
    }


    //-------------------------------------------------------------------------
    // Actually do the codegen, given the root of the tree
    //-------------------------------------------------------------------------
    public virtual void DoCodeGen(AST.ProgramDecl root)
    {
        this.Generate(root);
    }
    
    /***************************************************************************\
    *
    * EmitCodeGen.EndOutput
    *
    * EndOutput() commits any outstanding data and generates the module and assembly.
    *
    \***************************************************************************/

    public virtual void
    EndOutput()
    {
        //
        // Setup an entry point
        //

        PEFileKinds kind;
        switch (m_TargetType)
        {
        case TargetType.Console:
            kind = PEFileKinds.ConsoleApplication;
            break;

        case TargetType.Windows:
            kind = PEFileKinds.WindowApplication;
            break;

        case TargetType.Dll:
            kind = PEFileKinds.Dll;
            break;

        default:
            throw new ArgumentOutOfRangeException("Unknown Target type");
        }

        //
        // Find Main() entry point for an .exe
        //
        if (m_TargetType == TargetType.Console || m_TargetType == TargetType.Windows)
        {   
            MethodInfo miMain = null;
        
            if (m_stMainClass != null)
            {
                // A class was specified containing the main method
                Type tEntry = this.m_bldModule.GetType(m_stMainClass);
                if (tEntry == null)
                {
                    PrintError_EntryClassNotFound(m_stMainClass);
                }
                miMain = tEntry.GetMethod("Main");
                if (miMain != null)
                {
                    // Ensure that the main method is valid.
                    if (!miMain.IsStatic)
                        miMain = null;
                }
                
            } else {
                // No explicit class specified, search for main method
                // It's an error if there are multiple valid mains.                
                foreach (Type typeClass in m_alClasses)
                {
                    MethodInfo miTemp = typeClass.GetMethod("Main", 
                            BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic);

                    if (miTemp != null)
                    {
                        if (miMain == null)
                        {
                            // Main has not already been found, so store this first copy.
                            miMain = miTemp;
                        }
                        else
                        {                            
                            // Main has already been found, so we may be using the wrong one.
                            this.PrintError_DuplicateMain();
                        }
                    }
                }
            } // end search
            
            // By now, we'd better have a main method;
            if (miMain == null)
            {                    
                this.PrintError_NoMain();
            } 
            else 
            {
                m_bldAssembly.SetEntryPoint(miMain, kind);
            }
            
        } // set Main() entry point

        

        //
        // Save to a file
        // This will also do a whole bunch of verfication / Checks. If we have errors
        // elsewhere, this may throw an exception
        
        try
        {    
            Log.WriteLine(Log.LF.CodeGen, "About to save Assembly:" + m_stOutputName);
            m_bldAssembly.Save(m_stOutputName);
            Log.WriteLine(Log.LF.CodeGen, "Save completed successfully");
        }
        // IO exceptions are ok. For example, we can't write to the file
        // But anything else means that we made a mistake somewhere in codegen / resolution.
        catch(System.IO.IOException e)
        {
            PrintError_IOException(e.Message);
        }
        
        
        // Unhook listeners
        m_domain.TypeResolve -= m_resolveHandler;
        m_resolveHandler = null;
        
    }

#endregion Driver

#region Methods to do Generation

#region Generate Helpers
//-----------------------------------------------------------------------------
// These are emit helpers that let us abstract various emit decisions.
//-----------------------------------------------------------------------------

    // Emit a this pointer onto the stack
    void EmitThisRef()
    {    
        m_ilGenerator.Emit(OpCodes.Ldarg_0); // load a 'this' pointer
    }
    
    
    void EmitNonPolymorphicCall(SymbolEngine.MethodExpEntry sym)
    {
        Debug.Assert(sym != null);

        MethodInfo mdInfo = sym.Info as MethodInfo;
        Debug.Assert(mdInfo != null);
        
        m_ilGenerator.Emit(OpCodes.Call, mdInfo);          
    }
    
    // Emit a call/callvirt to the specified symbol
    void EmitCall(SymbolEngine.MethodExpEntry sym)
    {   
        Debug.Assert(sym != null);

        MethodInfo mdInfo = sym.Info as MethodInfo;
        Debug.Assert(mdInfo != null);
        
        if (mdInfo.IsVirtual && !sym.SymbolClass.CLRType.IsValueType)
        {
            m_ilGenerator.Emit(OpCodes.Callvirt, mdInfo);
        } 
        else 
        {
            m_ilGenerator.Emit(OpCodes.Call, mdInfo);
        }    
    }
    
    // Do a return by jumping to a standard label
    void EmitReturn()
    {
        if (m_cTryDepth == 0)
            m_ilGenerator.Emit(OpCodes.Br, m_lblReturn);
        else
            m_ilGenerator.Emit(OpCodes.Leave, m_lblReturn);
    }
    
    // Since Enter/Exit must be paired up, return an int from Enter
    // that we pass to Exit to ensure a match
    int EnterProtectedBlock()
    {
        m_cTryDepth++;
        return m_cTryDepth;
    }
    void ExitProtectedBlock(int iOldDepth)
    {           
        Debug.Assert(m_cTryDepth > 0);
        Debug.Assert(m_cTryDepth == iOldDepth);
        m_cTryDepth--;
    }
    
    // Emit the proper form of ldarg
    void Emit_Ldarg(int iSlot)
    {
        OpCode code = OpCodes.Ldarg;
        switch(iSlot)
        {
        case 0: code = OpCodes.Ldarg_0; break;
        case 1: code = OpCodes.Ldarg_1; break;
        case 2: code = OpCodes.Ldarg_2; break;
        case 3: code = OpCodes.Ldarg_3; break;        
        }
        if (4 <= iSlot && iSlot <= 255)
            code = OpCodes.Ldarg_S;
        
        if (iSlot < 4)
            m_ilGenerator.Emit(code);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -