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

📄 emitcodegen.cs

📁 charp compiler
💻 CS
📖 第 1 页 / 共 5 页
字号:
            return;
        }
        
        
        //
        // Begin a new method definition.
        //

        SetCurrentMethod(nodeMethod);

        string stMethodName         = nodeMethod.Name;
        SymbolEngine.MethodExpEntry symbol
                                    = nodeMethod.Symbol;
        
        
        Log.WriteLine(Log.LF.CodeGen, "Generating body for method '{0}' of class '{1}'", stMethodName, symbol.SymbolClass.FullName);
        
        Debug.Assert(!symbol.SymbolClass.IsInterface, "Don't codegen method bodies for interfaces");
        Debug.Assert(!symbol.Node.Mods.IsAbstract, "Don't codegen abstract methods");

        //
        // Get signature from the parameters
        //
        
        int iParam = 0;
        
        AST.ParamVarDecl [] alParamDecls = nodeMethod.Params;
        /*
        Type [] alParamTypes = new Type[alParamDecls.Length];
        
        foreach(AST.ParamVarDecl nodeParamDecl in alParamDecls)
        {
            SymbolEngine.ParamVarExpEntry sym = nodeParamDecl.ParamSymbol;
            alParamTypes[iParam] = sym.m_type.CLRType;
            iParam++;
        }
                
        */
                       
        ConstructorBuilder bldCtor = null;
        MethodBuilder bldMethod = null;
        // get the generator for either a Ctor or a method
        if (symbol.IsCtor)
        {            
            bldCtor = symbol.Info as ConstructorBuilder;
            Debug.Assert(bldCtor != null);            
            m_ilGenerator = bldCtor.GetILGenerator();
                        
        }
        else
        {
        
            Type typeReturn = symbol.m_type.CLRType;
            Debug.Assert(typeReturn != null, "Semantic check should catch null return type");
        
            bldMethod = symbol.Info as MethodBuilder;
            Debug.Assert(bldMethod != null);
            
            m_ilGenerator   = bldMethod.GetILGenerator();

        }
        
        // Now, doesn't matter if we're a ctor or a method. Just need an ilgenerator
        Debug.Assert(m_ilGenerator != null);
        Debug.Assert((bldCtor == null) ^ (bldMethod == null));

        //
        // Begin a new scope.
        //

        //
        // Assign builders & slots for parameters
        //
        
        // Note that CLR reserves parameter slot 0 for 'this' pointer
        // So start number the user parameters at 1
        if (nodeMethod.Mods.IsStatic)
        {
            //Debug.Assert(!symbol.IsCtor, "Static ctors are not supported");
            iParam = 0;
        }
        else 
        {
            iParam = 1;
        }
                
        int i = 1;
        foreach(AST.ParamVarDecl nodeParamDecl in alParamDecls)
        {
            SymbolEngine.ParamVarExpEntry sym = nodeParamDecl.ParamSymbol;
            
            // Set parameter attributes. These are rather counter-intuitive, but
            // this is what C# sets them too.
            ParameterAttributes attrs = ParameterAttributes.None;
            switch (nodeParamDecl.Flow)
            {
            case AST.EArgFlow.cIn:      attrs = ParameterAttributes.None;   break;
            case AST.EArgFlow.cOut:     attrs = ParameterAttributes.Out;    break;
            case AST.EArgFlow.cRef:     attrs = ParameterAttributes.None;   break;
            }
            
            ParameterBuilder p1 = (symbol.IsCtor) ?                
                bldCtor.DefineParameter(i, attrs, sym.Name) :
                bldMethod.DefineParameter(i, attrs, sym.Name) ;
                
            
            
            sym.Builder = p1;
            sym.CodeGenSlot = iParam;
        
            i++;
            iParam++;
        }

        // All returns are really just a jump to the end where we have a single
        // common return.        
        m_lblReturn = m_ilGenerator.DefineLabel();
        
        //
        // Assign builders & slots for locals. Resolve variables in nested scopes
        // here by just flattening them all to be in a single scope and then
        // giving them each unique slots. This is not optimal since we 
        // don't reuse slots for vars in disjoint scopes.
        // @todo - how do we want to resolve vars in nested scopes?
        // @todo - How should SymbolResolution & Codegen split the responsibilities
        //          for nested vars? Currently, it's all on codegen.
        //
        int iLocalSlot = 0;
        AssignLocalSlots(nodeMethod.Body, ref iLocalSlot);

        // Assign a localvar to hold the return value.
        // This way we can return from inside an exception-block        
        bool fHasReturn = !nodeMethod.Symbol.IsCtor && (nodeMethod.Symbol.RetType.CLRType != typeof(void));
        
        if (fHasReturn)
        {
            m_localReturnValue = m_ilGenerator.DeclareLocal(nodeMethod.Symbol.RetType.CLRType);
        } else {
            m_localReturnValue = null;
        }
        
        // When we return, we need to know whether to do a 'br' or a 'leave'.
        // So maintain a counter of how deep in the try/catch/finally blocks we are.
        // If the depth==0, then 'br' is ok, else we have to use 'leave'
        m_cTryDepth = 0;
        


        //
        // Generate each of the statements in the method.
        //

        AST.Statement[] al = nodeMethod.Body.Statements;
        foreach (AST.Statement nodeStatement in al)
        {
            nodeStatement.Generate(this);
            Debug.Assert(m_cTryDepth == 0);
        }


        //
        // End the scope.
        //


        // Generate end-of-method.
        m_ilGenerator.MarkLabel(m_lblReturn);
        if (fHasReturn)
        {
            this.Emit_Ldloc(m_localReturnValue);
        }
        
        // Mark the last character of the methoddecl for the implied return
        FileRange f = nodeMethod.Location;
        //this.MarkSequencePoint(new FileRange(f.Filename, f.RowEnd, f.ColEnd));
        m_ilGenerator.Emit(OpCodes.Ret);
    
        m_ilGenerator = null;

        SetCurrentMethod(null);
    }
#endregion

#region Generate Variable slot assignments 
    /***************************************************************************\
    * EmitCodeGen.AssignLocalSlots
    * 
    * 
    * Recursive function to assign slots/builders to all local variables.
    * iLocalSlot is a counter for the current slot number and must be unique
    * for each local variable. So start it at 0 and let it keep going up.
    \***************************************************************************/

    protected void 
    AssignLocalSlots(
        AST.BlockStatement block,
        ref int iLocalSlot
    )
    {
        if (block == null)
            return;
            
        AST.LocalVarDecl [] alLocalDecls = block.Locals;
           
        // Generate slots/builders for all locals in this block
        foreach(AST.LocalVarDecl nodeLocalDecl in alLocalDecls)
        {
            SymbolEngine.LocalVarExpEntry sym = nodeLocalDecl.LocalSymbol;
            LocalBuilder l1 = m_ilGenerator.DeclareLocal(sym.m_type.CLRType);

            if (m_fDebugInfo)
            {
                l1.SetLocalSymInfo(sym.Name);
            }
            
            sym.Builder = l1;
            //sym.CodeGenSlot = iLocalSlot;
            
            iLocalSlot++;
        }

        // Call on all nested blocks
        AST.Statement [] stmtList = block.Statements;
        foreach(AST.Statement s in stmtList)
        {
            
            AssignLocalSlots(s, ref iLocalSlot);            
        }
    }
    
    protected void 
    AssignLocalSlots(
        AST.Statement s,
        ref int iLocalSlot
    )
    {
        if (s == null)
            return;
            
        AST.BlockStatement blockNested = s as AST.BlockStatement;
        if (blockNested != null)
        {
            AssignLocalSlots(blockNested, ref iLocalSlot);
            return;
        }
        
        // @todo - this is a total hack. We special case the different AST types.
        // Need to decide a good way to resolve nested locals            
        AST.IfStatement s2 = s as AST.IfStatement;
        if (s2 != null)
        {               
            AssignLocalSlots(s2.ThenStmt, ref iLocalSlot);            
            AssignLocalSlots(s2.ElseStmt, ref iLocalSlot);
            return;
        }
        
        AST.LoopStatement s3 = s as AST.LoopStatement;
        if (s3 != null)
        {
            AssignLocalSlots(s3.BodyStmt, ref iLocalSlot);
            return;
        }
        
        AST.TryStatement s4 = s as AST.TryStatement;
        if (s4 != null)
        {
            AssignLocalSlots(s4.TryStmt, ref iLocalSlot);
            foreach(AST.CatchHandler c in s4.CatchHandlers)
                AssignLocalSlots(c.Body, ref iLocalSlot);
            AssignLocalSlots(s4.FinallyStmt, ref iLocalSlot);        
        }
        
        AST.ForeachStatement s5 = s as AST.ForeachStatement;
        if (s5 != null)
        {
            AssignLocalSlots(s5.ResolvedStmt, ref iLocalSlot);
        }
        
        AST.SwitchStatement s6 = s as AST.SwitchStatement;
        if (s6 != null)
        {
            AssignLocalSlots(s6.ResolvedStatement, ref iLocalSlot);
        }
        
    }
#endregion


#region Generate Statements
    /***************************************************************************\
    *
    * EmitCodeGen.Generate
    *
    * Generate() recursively generates the statement defined by the given node.
    *
    \***************************************************************************/

    public void
    Generate(
        AST.ReturnStatement nodeStmt)
    {        
        MarkSequencePoint(nodeStmt.Location);
        
        AST.Exp exp = nodeStmt.Expression;
        if (exp != null)
        {            
            //exp.Generate(this);
            AST.MethodDecl m = GetCurrentMethod();
            Debug.Assert(m != null);

            GenerateBoxable(exp, m.Symbol.RetType.CLRType);
            this.Emit_Stloc(m_localReturnValue);
        }
        
        EmitReturn();
    }

    /***************************************************************************\
    *
    * EmitCodeGen.Generate
    *
    * Generate() recursively generates the statement defined by the given node.
    *
    \***************************************************************************/
    public void
    Generate(
        AST.WhileStatement nodeStmt
    )
    {
#if false
// while(TestExp) BodyStmt;
       
        lContinue:
            [TestExp]
            brfalse l2;
            [BodyStmt]
            goto l1;
        lBreak:
#endif        
        Label lContinue = m_ilGenerator.DefineLabel();
        Label lBreak = m_ilGenerator.DefineLabel();

        m_ilGenerator.MarkLabel(lContinue);
        MarkSequencePoint(nodeStmt.TestExp.Location);
        nodeStmt.TestExp.GenerateAsRight(this);
        m_ilGenerator.Emit(OpCodes.Brfalse, lBreak);

        LoopFrame f = new LoopFrame(lBreak, lContinue);
        PushLoopFrame(f);

        nodeStmt.BodyStmt.Generate(this);
        m_ilGenerator.Emit(OpCodes.Br, lContinue);

        PopLoopFrame(f);

        m_ilGenerator.MarkLabel(lBreak);
    }

    /***************************************************************************\
    *
    * EmitCodeGen.Generate
    *
    * Generate() recursively generates the statement defined by the given node.
    *
    \***************************************************************************/
    public void
        Generate(
        AST.DoStatement nodeStmt
        )
    {
#if false
// do BodyStmt while (TestExp);
       
        l1:            
            [BodyStmt]
        lContinue:
            [TestExp]
            brtrue l1;        
        lBreak:
#endif
        Label l1 = m_ilGenerator.DefineLabel();
        Label lContinue = m_ilGenerator.DefineLabel();
        Label lBreak = m_ilGenerator.DefineLabel();
        

        LoopFrame f = new LoopFrame(lBreak, lContinue);
        PushLoopFrame(f);

        m_ilGenerator.MarkLabel(l1);  

⌨️ 快捷键说明

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