Example #1
0
        private void EmitGenerator(CodeGen ncg)
        {
            YieldTarget[] targets = YieldLabelBuilder.BuildYieldTargets(this, ncg);

            Label[] jumpTable = new Label[yieldCount];
            for (int i = 0; i < yieldCount; i++)
            {
                jumpTable[i] = targets[i].topBranchTarget;
            }
            ncg.yieldLabels = jumpTable;

            ncg.PushTryBlock();
            ncg.BeginExceptionBlock();

            ncg.Emit(OpCodes.Ldarg_0);
            ncg.EmitFieldGet(typeof(Generator), "location");
            ncg.Emit(OpCodes.Switch, jumpTable);

            // fall-through on first pass
            // yield statements will insert the needed labels after their returns
            body.Emit(ncg);

            // fall-through is almost always possible in generators, so this
            // is almost always needed
            ncg.EmitReturnInGenerator(null);

            // special handling for StopIteration thrown in body
            ncg.BeginCatchBlock(typeof(StopIterationException));
            ncg.EndExceptionBlock();
            ncg.EmitReturnInGenerator(null);
            ncg.PopTargets();

            ncg.Finish();
        }
Example #2
0
        private void EmitFunctionImplementation(CodeGen cg, CodeGen icg, bool context)
        {
            if (context)
            {
                if (IsClosure)
                {
                    icg.StaticLinkSlot = icg.GetArgumentSlot(0);
                }
                icg.ContextSlot = icg.GetArgumentSlot(0);
                icg.ModuleSlot  = new PropertySlot(icg.ContextSlot, typeof(ICallerContext).GetProperty("Module"));
            }

            if (EmitLocalDictionary)
            {
                PromoteLocalsToEnvironment();
            }

            if (Options.TracebackSupport)
            {
                // push a try for traceback support
                icg.PushTryBlock();
                icg.BeginExceptionBlock();
            }

            // emit the actual body
            if (yieldCount > 0)
            {
                EmitGeneratorBody(icg, cg);
            }
            else
            {
                EmitFunctionBody(icg, cg);
            }

            if (Options.TracebackSupport)
            {
                // push a fault block (runs only if there's an exception, doesn't handle the exception)
                icg.PopTargets();
                if (icg.IsDynamicMethod)
                {
                    icg.BeginCatchBlock(typeof(Exception));
                }
                else
                {
                    icg.BeginFaultBlock();
                }

                EmitUpdateTraceBack(icg, cg);

                // end the exception block
                if (icg.IsDynamicMethod)
                {
                    icg.Emit(OpCodes.Rethrow);
                }
                icg.EndExceptionBlock();
            }

            icg.Finish();
        }
        public static void EmitStackTraceFaultBlock(CodeGen cg, string name, string displayName)
        {
            Contract.RequiresNotNull(cg, "cg");
            Contract.RequiresNotNull(name, "name");
            Contract.RequiresNotNull(displayName, "displayName");

            if (ScriptDomainManager.Options.DynamicStackTraceSupport)
            {
                // push a fault block (runs only if there's an exception, doesn't handle the exception)
                cg.PopTargets();
                if (cg.IsDynamicMethod)
                {
                    cg.BeginCatchBlock(typeof(Exception));
                }
                else
                {
                    cg.BeginFaultBlock();
                }

                cg.EmitCodeContext();
                if (cg.IsDynamicMethod)
                {
                    cg.ConstantPool.AddData(cg.MethodBase).EmitGet(cg);
                }
                else
                {
                    cg.Emit(OpCodes.Ldtoken, cg.MethodInfo);
                    cg.EmitCall(typeof(MethodBase), "GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle) });
                }
                cg.EmitString(name);
                cg.EmitString(displayName);
                cg.EmitGetCurrentLine();
                cg.EmitCall(typeof(ExceptionHelpers), "UpdateStackTrace");

                // end the exception block
                if (cg.IsDynamicMethod)
                {
                    cg.Emit(OpCodes.Rethrow);
                }
                cg.EndExceptionBlock();
            }
        }
Example #4
0
        //!!! need to evaluate break/continue through a try block
        public override void Emit(CodeGen cg)
        {
            Slot choiceVar = null;

            cg.EmitPosition(start, header);

            if (yieldTargets.Count > 0)
            {
                Label startOfBlock = cg.DefineLabel();
                choiceVar = cg.GetLocalTmp(typeof(int));
                cg.EmitInt(-1);
                choiceVar.EmitSet(cg);
                cg.Emit(OpCodes.Br, startOfBlock);

                int index = 0;
                foreach (YieldTarget yt in yieldTargets)
                {
                    cg.MarkLabel(yt.topBranchTarget);
                    cg.EmitInt(index++);
                    choiceVar.EmitSet(cg);
                    cg.Emit(OpCodes.Br, startOfBlock);
                }

                cg.MarkLabel(startOfBlock);
            }

            Label afterCatch = new Label();
            Label afterElse  = cg.DefineLabel();

            cg.PushTryBlock();
            cg.BeginExceptionBlock();

            if (yieldTargets.Count > 0)
            {
                int index = 0;
                foreach (YieldTarget yt in yieldTargets)
                {
                    choiceVar.EmitGet(cg);
                    cg.EmitInt(index);
                    cg.Emit(OpCodes.Beq, yt.tryBranchTarget);
                    index++;
                }
                cg.FreeLocalTmp(choiceVar);
            }

            body.Emit(cg);
            if (yieldInExcept)
            {
                afterCatch = cg.DefineLabel();
                cg.Emit(OpCodes.Leave, afterCatch);
            }
            cg.BeginCatchBlock(typeof(Exception));
            // Extract state from the carrier exception
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ExtractException");
            Slot pyExc  = cg.GetLocalTmp(typeof(object));
            Slot tmpExc = cg.GetLocalTmp(typeof(object));

            pyExc.EmitSet(cg);
            if (yieldInExcept)
            {
                cg.EndExceptionBlock();
                cg.PopTargets();
            }

            foreach (TryStmtHandler handler in handlers)
            {
                cg.EmitPosition(handler.start, handler.header);
                Label next = cg.DefineLabel();
                if (handler.test != null)
                {
                    pyExc.EmitGet(cg);
                    handler.test.Emit(cg);
                    cg.EmitCall(typeof(Ops), "CheckException");
                    if (handler.target != null)
                    {
                        tmpExc.EmitSet(cg);
                        tmpExc.EmitGet(cg);
                    }
                    cg.EmitPythonNone();
                    cg.Emit(OpCodes.Ceq);
                    cg.Emit(OpCodes.Brtrue, next);
                }

                if (handler.target != null)
                {
                    tmpExc.EmitGet(cg);
                    handler.target.EmitSet(cg);
                }

                cg.PushExceptionBlock(Targets.TargetBlockType.Catch, null);

                handler.body.Emit(cg);
                cg.EmitCallerContext();
                cg.EmitCall(typeof(Ops), "ClearException");

                cg.PopTargets();

                if (yieldInExcept)
                {
                    cg.Emit(OpCodes.Br, afterElse);
                }
                else
                {
                    cg.Emit(OpCodes.Leave, afterElse);
                }
                cg.MarkLabel(next);
            }

            cg.FreeLocalTmp(tmpExc);
            if (yieldInExcept)
            {
                pyExc.EmitGet(cg);
                cg.Emit(OpCodes.Throw);
                cg.MarkLabel(afterCatch);
            }
            else
            {
                cg.Emit(OpCodes.Rethrow);
                cg.EndExceptionBlock();
                cg.PopTargets();
            }

            if (elseStmt != null)
            {
                elseStmt.Emit(cg);
            }
            cg.MarkLabel(afterElse);

            cg.FreeLocalTmp(pyExc);

            yieldTargets.Clear();
        }
Example #5
0
        private void EmitSimpleTry(CodeGen cg, TryFlowResult flow)
        {
            //
            // Initialize the flow control flag
            //
            Slot flowControlFlag = null;

            if (flow.Any)
            {
                Debug.Assert(_finally != null);

                flowControlFlag = cg.GetLocalTmp(typeof(int));
                cg.EmitInt(CodeGen.FinallyExitsNormally);
                flowControlFlag.EmitSet(cg);

                //  If there is a control flow in finally, emit outer:
                //  try {
                //      // try block body and all catch handling
                //  } catch (Exception all) {
                //      saved = all;
                //  } finally {
                //      finally_body
                //      if (saved != null) {
                //          throw saved;
                //      }
                //  }

                if (HaveHandlers())
                {
                    cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
                    cg.BeginExceptionBlock();
                }
            }

            //******************************************************************
            // 1. ENTERING TRY
            //******************************************************************

            cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
            cg.BeginExceptionBlock();

            //******************************************************************
            // 2. Emit the try statement body
            //******************************************************************

            _body.Emit(cg);
            //cg.EmitSequencePointNone();

            //******************************************************************
            // 3. Emit the catch blocks
            //******************************************************************

            if (HaveHandlers())
            {
                cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);

                foreach (CatchBlock cb in _handlers)
                {
                    // Begin the strongly typed exception block
                    cg.BeginCatchBlock(cb.Test);

                    // Save the exception (if the catch block asked for it) or pop
                    EmitSaveExceptionOrPop(cg, cb);

                    //
                    // Emit the catch block body
                    //
                    cb.Body.Emit(cg);
                }

                cg.PopTargets(TargetBlockType.Catch);
            }

            //******************************************************************
            // 4. Emit the finally block
            //******************************************************************

            if (_finally != null)
            {
                Slot rethrow = null;
                if (flow.Any)
                {
                    // If there is a control flow in finally, end the catch
                    // statement and emit the catch-all and finally clause
                    // with rethrow at the end.

                    if (HaveHandlers())
                    {
                        cg.EndExceptionBlock();
                        cg.PopTargets(TargetBlockType.Try);
                    }

                    cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);
                    cg.BeginCatchBlock(typeof(Exception));

                    rethrow = cg.GetLocalTmp(typeof(Exception));
                    rethrow.EmitSet(cg);

                    cg.PopTargets(TargetBlockType.Catch);
                }

                cg.PushExceptionBlock(TargetBlockType.Finally, flowControlFlag);
                cg.BeginFinallyBlock();

                //
                // Emit the finally block body
                //
                _finally.Emit(cg);

                if (flow.Any)
                {
                    Debug.Assert(rethrow != null);
                    Label noRethrow = cg.DefineLabel();

                    rethrow.EmitGet(cg);
                    cg.EmitNull();
                    cg.Emit(OpCodes.Beq, noRethrow);
                    rethrow.EmitGet(cg);
                    cg.Emit(OpCodes.Throw);
                    cg.MarkLabel(noRethrow);
                }

                cg.EndExceptionBlock();
                cg.PopTargets(TargetBlockType.Finally);
            }
            else
            {
                cg.EndExceptionBlock();
            }

            cg.PopTargets(TargetBlockType.Try);

            //
            // Emit the flow control for finally, if there was any.
            //
            EmitFinallyFlowControl(cg, flow, flowControlFlag);

            cg.FreeLocalTmp(flowControlFlag);
        }
Example #6
0
        private void EmitGeneratorTry(CodeGen cg, TryFlowResult flow)
        {
            //
            // Initialize the flow control flag
            //
            Slot flowControlFlag = null;

            if (flow.Any)
            {
                flowControlFlag = cg.GetLocalTmp(typeof(int));
                cg.EmitInt(CodeGen.FinallyExitsNormally);
                flowControlFlag.EmitSet(cg);
            }

            Slot exception = null;

            if (_finally != null)
            {
                exception = cg.GetTemporarySlot(typeof(Exception));
                cg.EmitNull();
                exception.EmitSet(cg);
            }

            //******************************************************************
            // Entering the try block
            //******************************************************************

            if (_target != null)
            {
                cg.MarkLabel(_target.EnsureLabel(cg));
            }

            //******************************************************************
            // If we have a 'finally', transform it into try..catch..finally
            // and rethrow
            //******************************************************************
            Label endFinallyBlock = new Label();

            if (_finally != null)
            {
                cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
                cg.BeginExceptionBlock();
                endFinallyBlock = cg.DefineLabel();

                //**************************************************************
                // If there is a yield in any catch, that catch will be hoisted
                // and we need to dispatch to it from here
                //**************************************************************
                if (_yieldInCatch)
                {
                    EmitYieldDispatch(_catchYields, cg);
                }

                if (YieldInBlock(_finallyYields))
                {
                    foreach (YieldTarget yt in _finallyYields)
                    {
                        cg.GotoRouter.EmitGet(cg);
                        cg.EmitInt(yt.Index);
                        cg.Emit(OpCodes.Beq, endFinallyBlock);
                    }
                }
            }

            //******************************************************************
            // If we have a 'catch', start a try block to handle all the catches
            //******************************************************************

            Label endCatchBlock = new Label();

            if (HaveHandlers())
            {
                cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
                endCatchBlock = cg.BeginExceptionBlock();
            }

            //******************************************************************
            // Emit the try block body
            //******************************************************************

            // First, emit the dispatch within the try block
            EmitYieldDispatch(_tryYields, cg);

            // Then, emit the actual body
            _body.Emit(cg);
            //cg.EmitSequencePointNone();

            //******************************************************************
            // Emit the catch blocks
            //******************************************************************

            if (HaveHandlers())
            {
                List <CatchRecord> catches = new List <CatchRecord>();
                cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);

                foreach (CatchBlock cb in _handlers)
                {
                    cg.BeginCatchBlock(cb.Test);

                    if (cb.Yield)
                    {
                        // The catch block body contains yield, therefore
                        // delay the body emit till after the try block.
                        Slot slot = cg.GetLocalTmp(cb.Test);
                        slot.EmitSet(cg);
                        catches.Add(new CatchRecord(slot, cb));
                    }
                    else
                    {
                        // Save the exception (if the catch block asked for it) or pop
                        EmitSaveExceptionOrPop(cg, cb);
                        // Emit the body right now, since it doesn't contain yield
                        cb.Body.Emit(cg);
                    }
                }

                cg.PopTargets(TargetBlockType.Catch);
                cg.EndExceptionBlock();
                cg.PopTargets(TargetBlockType.Try);

                //******************************************************************
                // Emit the postponed catch block bodies (with yield in them)
                //******************************************************************
                foreach (CatchRecord cr in catches)
                {
                    Label next = cg.DefineLabel();
                    cr.Slot.EmitGet(cg);
                    cg.EmitNull();
                    cg.Emit(OpCodes.Beq, next);

                    if (cr.Block.Slot != null)
                    {
                        cr.Block.Slot.EmitSet(cg, cr.Slot);
                    }

                    cg.FreeLocalTmp(cr.Slot);
                    cr.Block.Body.Emit(cg);
                    cg.MarkLabel(next);
                    //cg.EmitSequencePointNone();
                }
            }

            //******************************************************************
            // Emit the finally body
            //******************************************************************

            if (_finally != null)
            {
                cg.MarkLabel(endFinallyBlock);
                cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);
                cg.BeginCatchBlock(typeof(Exception));
                exception.EmitSet(cg);

                cg.PopTargets(TargetBlockType.Catch);

                cg.PushExceptionBlock(TargetBlockType.Finally, flowControlFlag);
                cg.BeginFinallyBlock();

                Label noExit = cg.DefineLabel();
                cg.GotoRouter.EmitGet(cg);
                cg.EmitInt(CodeGen.GotoRouterYielding);
                cg.Emit(OpCodes.Bne_Un_S, noExit);
                cg.Emit(OpCodes.Endfinally);
                cg.MarkLabel(noExit);

                EmitYieldDispatch(_finallyYields, cg);

                // Emit the finally body

                _finally.Emit(cg);

                // Rethrow the exception, if any

                Label noThrow = cg.DefineLabel();
                exception.EmitGet(cg);
                cg.EmitNull();
                cg.Emit(OpCodes.Beq, noThrow);
                exception.EmitGet(cg);
                cg.Emit(OpCodes.Throw);
                cg.MarkLabel(noThrow);
                cg.FreeLocalTmp(exception);

                cg.EndExceptionBlock();
                cg.PopTargets(TargetBlockType.Finally);
                cg.PopTargets(TargetBlockType.Try);

                //
                // Emit the flow control for finally, if there was any.
                //
                EmitFinallyFlowControl(cg, flow, flowControlFlag);

                //cg.EmitSequencePointNone();
            }

            // Clear the target labels

            ClearLabels(_tryYields);
            ClearLabels(_catchYields);

            if (_target != null)
            {
                _target.Clear();
            }
        }
        private void EmitWithCatchBlock(CodeGen cg, Slot exc, Slot exit)
        {
            cg.BeginCatchBlock(typeof(Exception));
            // Extract state from the carrier exception
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ExtractException",
                new Type[] { typeof(Exception), typeof(ICallerContext) });
            cg.Emit(OpCodes.Pop);

            // except body
            cg.PushExceptionBlock(Targets.TargetBlockType.Catch, null, null);
            cg.EmitConstantBoxed(false);
            exc.EmitSet(cg);

            cg.EmitCallerContext();
            exit.EmitGet(cg);
            cg.EmitObjectArray(new Expression[0]);
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ExtractSysExcInfo");
            cg.EmitCall(typeof(Ops), "CallWithArgsTupleAndContext", new Type[] { typeof(ICallerContext), typeof(object), typeof(object[]), typeof(object) });

            Label afterRaise = cg.DefineLabel();

            cg.EmitTestTrue();
            cg.Emit(OpCodes.Brtrue, afterRaise);
            cg.EmitCall(typeof(Ops), "Raise", new Type[0]); //, new Type[] { typeof(object), typeof(SymbolId) });
            cg.MarkLabel(afterRaise);
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ClearException", new Type[] { typeof(ICallerContext) });
            cg.PopTargets();
        }
        // codegen algorithm for unified try-catch-else-finally
        //    isTryYielded = false
        //    isCatchYielded = false
        //    isFinallyYielded = false
        //    isElseYielded = false
        //    Set up the labels for Try Yield Targets
        //    Set up the labels for Catch Yield Targets
        //    Set up the labels for Else Yield Targets
        //    Set up the labels for Finally Yield Targets
        //    returnVar = false
        //    isElseBlock = false
        //TRY:
        //    if isCatchYielded :
        //        rethow  storedException
        //    if finallyYielded :
        //        goto endOfTry
        //    if isElseYielded :
        //        goto beginElseBlock
        //    if isTryYielded:
        //        isTryYielded = false
        //        goto desired_label_in_TRY-BODY
        //    TRY-BODY
        //  beginElseBlock: # Note we are still under TRY
        //    isElseBlock = true
        //    if isElseYielded :
        //        isElseYielded  = false
        //        goto desired_label_in_ELSE-BODY
        //    ELSE-BODY
        //  endOfTry:
        //EXCEPT: # catches any exception
        //    if isElseBlock:
        //        rethrow
        //    pyExc = ExtractException()
        //    storedException = ExtractSysExcInfo()
        //    if pyExc == handler[0].Test :
        //        if isCatchYielded :
        //            isCatchYielded  = false
        //            goto desired_label_in_HANDLER-BODY
        //        HANDLER-BODY
        //        ClearException()
        //        Leave afterFinally
        //    elif pyExc == handler[1].Test :
        //        if isCatchYielded :
        //            isCatchYielded  = false
        //            goto desired_label_in_HANDLER-BODY
        //        HANDLER-BODY
        //        ClearException()
        //        Leave afterFinally
        //    .
        //    .
        //    .
        //    Rethrow
        //FINALLY:
        //    if (isTryYielded  or isCatchYielded  or isElseYielded ):
        //        goto endOfFinally
        //    if isFinallyYielded :
        //        isFinallyYielded  = false
        //        goto desired_label_in_FINALLY-BODY
        //    FINALLY-BODY
        //  endOfFinally:
        // #try-cathch-finally ends here
        // afterFinally:
        //    if not returnVar :
        //      goto noReturn
        //    if (finally may yield ):
        //          return 1
        //    else
        //          return appropriate_return_value
        //  noReturn:
        internal override void Emit(CodeGen cg)
        {
            // environmental slots
            Slot isTryYielded = null;
            Slot isCatchYielded = null;
            Slot isFinallyYielded = null;
            Slot isElseYielded = null;
            Slot storedException = null;

            // local slots
            Slot tryChoiceVar = null;
            Slot catchChoiceVar = null;
            Slot elseChoiceVar = null;
            Slot finallyChoiceVar = null;

            Slot flowControlVar = cg.GetLocalTmp(typeof(int));
            Slot isElseBlock = null;

            cg.EmitPosition(Start, header);

            if (IsBlockYieldable(tryYieldTargets)) {
                tryChoiceVar = cg.GetLocalTmp(typeof(int));
                isTryYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isTryYielded.EmitSet(cg);
            }

            if (IsBlockYieldable(catchYieldTargets)) {
                catchChoiceVar = cg.GetLocalTmp(typeof(int));
                storedException = cg.Names.GetTempSlot("exc", typeof(object));
                isCatchYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isCatchYielded.EmitSet(cg);
            }

            if (IsBlockYieldable(finallyYieldTargets)) {
                finallyChoiceVar = cg.GetLocalTmp(typeof(int));
                isFinallyYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isFinallyYielded.EmitSet(cg);
            }

            if (IsBlockYieldable(elseYieldTargets)) {
                elseChoiceVar = cg.GetLocalTmp(typeof(int));
                isElseYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isElseYielded.EmitSet(cg);
            }

            if (elseStmt != null) {
                isElseBlock = cg.GetLocalTmp(typeof(bool));
                cg.EmitInt(0);
                isElseBlock.EmitSet(cg);
            }

            Slot exception = null;
            bool foundLoopControl;
            bool returnInFinally = ControlFlowFinder.FindControlFlow(FinallyStatement, out foundLoopControl);

            if (IsBlockYieldable(finallyYieldTargets)) {
                exception = cg.Names.GetTempSlot("exception", typeof(Exception));
                cg.Emit(OpCodes.Ldnull);
                exception.EmitSet(cg);
            } else if (returnInFinally) {
                exception = cg.GetLocalTmp(typeof(Exception));
                cg.Emit(OpCodes.Ldnull);
                exception.EmitSet(cg);
            }

            EmitTopYieldTargetLabels(tryYieldTargets, tryChoiceVar, cg);
            EmitTopYieldTargetLabels(catchYieldTargets, catchChoiceVar, cg);
            EmitTopYieldTargetLabels(elseYieldTargets, elseChoiceVar, cg);
            EmitTopYieldTargetLabels(finallyYieldTargets, finallyChoiceVar, cg);

            cg.EmitInt(CodeGen.FinallyExitsNormally);
            flowControlVar.EmitSet(cg);

            Label afterFinally = cg.DefineLabel();

            cg.PushExceptionBlock(Targets.TargetBlockType.Try, flowControlVar, isTryYielded);
            cg.BeginExceptionBlock();

            // if catch yielded, rethow the storedException to be handled by Catch block
            if (IsBlockYieldable(catchYieldTargets)) {
                Label testFinally = cg.DefineLabel();
                isCatchYielded.EmitGet(cg);
                cg.EmitUnbox(typeof(bool));
                cg.Emit(OpCodes.Brfalse, testFinally);
                storedException.EmitGet(cg);
                cg.EmitCall(typeof(Ops), "Raise", new Type[] { typeof(object) });
                cg.MarkLabel(testFinally);
            }

            // if Finally yielded, Branch to the end of Try block
            Label endOfTry = cg.DefineLabel();
            EmitOnYieldBranchToLabel(finallyYieldTargets, isFinallyYielded, endOfTry, cg);

            Label beginElseBlock = cg.DefineLabel();
            if (IsBlockYieldable(elseYieldTargets)) {
                // isElseYielded ?
                Debug.Assert(isElseYielded != null);
                isElseYielded.EmitGet(cg);
                cg.EmitUnbox(typeof(bool));
                cg.Emit(OpCodes.Brtrue, beginElseBlock);
            }

            EmitYieldDispatch(tryYieldTargets, isTryYielded, tryChoiceVar, cg);

            // if finally block presents, but no exception handler, we add try-fault
            // to update traceback; otherwise, we update the traceback inside exception handler.
            if (finallyStmt != null && handlers == null) {
                Slot dummySlot = cg.GetLocalTmp(typeof(object));
                cg.EmitTraceBackTryBlockStart(dummySlot);

                body.Emit(cg);

                cg.FreeLocalTmp(dummySlot);
                cg.EmitTraceBackFaultBlock();
            } else {
                body.Emit(cg);
            }

            if (elseStmt != null) {
                if (IsBlockYieldable(elseYieldTargets)) {
                    cg.MarkLabel(beginElseBlock);
                }

                cg.PopTargets(Targets.TargetBlockType.Try);
                cg.PushExceptionBlock(Targets.TargetBlockType.Else, flowControlVar, isElseYielded);

                cg.EmitInt(1);
                isElseBlock.EmitSet(cg);

                EmitYieldDispatch(elseYieldTargets, isElseYielded, elseChoiceVar, cg);

                elseStmt.Emit(cg);
                cg.PopTargets(Targets.TargetBlockType.Else);
                cg.PushExceptionBlock(Targets.TargetBlockType.Try, flowControlVar, isTryYielded);

            }

            cg.MarkLabel(endOfTry);

            // get the exception if there is a yield / return  in finally
            if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                cg.BeginCatchBlock(typeof(Exception));
                exception.EmitSet(cg);
            }

            if (handlers != null) {
                cg.PushExceptionBlock(Targets.TargetBlockType.Catch, flowControlVar, isCatchYielded);
                if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                    exception.EmitGet(cg);
                } else {
                    cg.BeginCatchBlock(typeof(Exception));
                }

                // if in Catch block due to exception in else block -> just rethrow
                if (elseStmt != null) {
                    Label beginCatchBlock = cg.DefineLabel();
                    isElseBlock.EmitGet(cg);
                    cg.Emit(OpCodes.Brfalse, beginCatchBlock);
                    cg.Emit(OpCodes.Rethrow);
                    cg.MarkLabel(beginCatchBlock);
                }

                cg.EmitCallUpdateTraceBack();

                // Extract state from the carrier exception
                cg.EmitCallerContext();
                cg.EmitCall(typeof(Ops), "ExtractException",
                    new Type[] { typeof(Exception), typeof(ICallerContext) });
                Slot pyExc = cg.GetLocalTmp(typeof(object));
                Slot tmpExc = cg.GetLocalTmp(typeof(object));
                pyExc.EmitSet(cg);

                if (IsBlockYieldable(catchYieldTargets)) {
                    cg.EmitCallerContext();
                    cg.EmitCall(typeof(Ops), "ExtractSysExcInfo");
                    storedException.EmitSet(cg);
                }

                foreach (TryStatementHandler handler in handlers) {
                    cg.EmitPosition(handler.Start, handler.Header);
                    Label next = cg.DefineLabel();
                    if (handler.Test != null) {
                        pyExc.EmitGet(cg);
                        handler.Test.Emit(cg);
                        cg.EmitCall(typeof(Ops), "CheckException");
                        if (handler.Target != null) {
                            tmpExc.EmitSet(cg);
                            tmpExc.EmitGet(cg);
                        }
                        cg.EmitPythonNone();
                        cg.Emit(OpCodes.Ceq);
                        cg.Emit(OpCodes.Brtrue, next);
                    }

                    if (handler.Target != null) {
                        tmpExc.EmitGet(cg);
                        handler.Target.EmitSet(cg);
                    }

                    if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                        cg.Emit(OpCodes.Ldnull);
                        exception.EmitSet(cg);
                    }

                    EmitYieldDispatch(catchYieldTargets, isCatchYielded, catchChoiceVar, cg);
                    handler.Body.Emit(cg);

                    cg.EmitCallerContext();
                    cg.EmitCall(typeof(Ops), "ClearException", new Type[] { typeof(ICallerContext) });
                    cg.EmitSetTraceBackUpdateStatus(false);

                    cg.Emit(OpCodes.Leave, afterFinally);
                    cg.MarkLabel(next);

                }

                cg.FreeLocalTmp(tmpExc);
                cg.FreeLocalTmp(pyExc);

                cg.Emit(OpCodes.Rethrow);
                cg.PopTargets(Targets.TargetBlockType.Catch);
            }

            if (finallyStmt != null) {
                cg.PushExceptionBlock(Targets.TargetBlockType.Finally, flowControlVar, isFinallyYielded);
                cg.BeginFinallyBlock();

                Label endOfFinally = cg.DefineLabel();

                // if try yielded
                EmitOnYieldBranchToLabel(tryYieldTargets, isTryYielded, endOfFinally, cg);
                // if catch yielded
                EmitOnYieldBranchToLabel(catchYieldTargets, isCatchYielded, endOfFinally, cg);
                //if else yielded
                EmitOnYieldBranchToLabel(elseYieldTargets, isElseYielded, endOfFinally, cg);

                EmitYieldDispatch(finallyYieldTargets, isFinallyYielded, finallyChoiceVar, cg);
                finallyStmt.Emit(cg);

                if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                    Label nothrow = cg.DefineLabel();
                    exception.EmitGet(cg);
                    cg.Emit(OpCodes.Dup);
                    cg.Emit(OpCodes.Brfalse_S, nothrow);
                    cg.Emit(OpCodes.Throw);
                    cg.MarkLabel(nothrow);
                    cg.Emit(OpCodes.Pop);
                }

                cg.MarkLabel(endOfFinally);
                cg.EndExceptionBlock();
                cg.PopTargets(Targets.TargetBlockType.Finally);
            } else {
                cg.EndExceptionBlock();
            }
            cg.PopTargets(Targets.TargetBlockType.Try);

            cg.MarkLabel(afterFinally);
            Label noReturn = cg.DefineLabel();
            flowControlVar.EmitGet(cg);
            cg.EmitInt(CodeGen.BranchForReturn);
            cg.Emit(OpCodes.Bne_Un, noReturn);

            if (cg.IsGenerator()) {
                // return true from the generator method
                cg.Emit(OpCodes.Ldc_I4_1);
                cg.EmitReturn();
            } else if (returnInFinally) {
                // return the actual value
                cg.EmitReturnValue();
                cg.EmitReturn();
            }

            cg.MarkLabel(noReturn);

            if (foundLoopControl) {
                noReturn = cg.DefineLabel();
                flowControlVar.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForBreak);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitBreak();
                cg.MarkLabel(noReturn);

                noReturn = cg.DefineLabel();
                flowControlVar.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForContinue);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitContinue();
                cg.MarkLabel(noReturn);
            }

            // clean up
            if (IsBlockYieldable(tryYieldTargets)) {
                cg.FreeLocalTmp(tryChoiceVar);
                tryYieldTargets.Clear();
            }
            if (IsBlockYieldable(catchYieldTargets)) {
                cg.FreeLocalTmp(catchChoiceVar);
                catchYieldTargets.Clear();
            }
            if (IsBlockYieldable(finallyYieldTargets)) {
                cg.FreeLocalTmp(finallyChoiceVar);
                finallyYieldTargets.Clear();
            }
            if (IsBlockYieldable(elseYieldTargets)) {
                cg.FreeLocalTmp(elseChoiceVar);
                elseYieldTargets.Clear();
            }
            if (elseStmt != null) {
                cg.FreeLocalTmp(isElseBlock);
            }

            #if DEBUG
            cg.EmitInt(-1);
            flowControlVar.EmitSet(cg);
            #endif

            cg.FreeLocalTmp(flowControlVar);
        }
Example #9
0
        private void EmitGenerator(CodeGen ncg)
        {
            YieldTarget[] targets = YieldLabelBuilder.BuildYieldTargets(this, ncg);

            Label[] jumpTable = new Label[yieldCount];
            for (int i = 0; i < yieldCount; i++) jumpTable[i] = targets[i].TopBranchTarget;
            ncg.yieldLabels = jumpTable;

            // Generator will ofcourse yield, but we are not interested in the isBlockYielded value
            // hence push a dummySlot to pass the Assertion.

            Slot dummySlot = ncg.GetLocalTmp(typeof(object));
            ncg.PushTryBlock(dummySlot);
            ncg.BeginExceptionBlock();

            ncg.Emit(OpCodes.Ldarg_0);
            ncg.EmitFieldGet(typeof(Generator), "location");
            ncg.Emit(OpCodes.Switch, jumpTable);

            // fall-through on first pass
            // yield statements will insert the needed labels after their returns
            Body.Emit(ncg);
            //free the dummySlot
            ncg.FreeLocalTmp(dummySlot);
            // fall-through is almost always possible in generators, so this
            // is almost always needed
            ncg.EmitReturnInGenerator(null);

            // special handling for StopIteration thrown in body
            ncg.BeginCatchBlock(typeof(StopIterationException));
            ncg.EndExceptionBlock();
            ncg.EmitReturnInGenerator(null);
            ncg.PopTargets();

            ncg.Finish();
        }
Example #10
0
        private void EmitSimpleTry(CodeGen cg, TryFlowResult flow)
        {
            //
            // Initialize the flow control flag
            //
            Slot flowControlFlag = null;
            if (flow.Any) {
                Debug.Assert(_finally != null);

                flowControlFlag = cg.GetLocalTmp(typeof(int));
                cg.EmitInt(CodeGen.FinallyExitsNormally);
                flowControlFlag.EmitSet(cg);

                //  If there is a control flow in finally, emit outer:
                //  try {
                //      // try block body and all catch handling
                //  } catch (Exception all) {
                //      saved = all;
                //  } finally {
                //      finally_body
                //      if (saved != null) {
                //          throw saved;
                //      }
                //  }

                if (HaveHandlers()) {
                    cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
                    cg.BeginExceptionBlock();
                }
            }

            //******************************************************************
            // 1. ENTERING TRY
            //******************************************************************

            cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
            cg.BeginExceptionBlock();

            //******************************************************************
            // 2. Emit the try statement body
            //******************************************************************

            _body.Emit(cg);
            //cg.EmitSequencePointNone();

            //******************************************************************
            // 3. Emit the catch blocks
            //******************************************************************

            if (HaveHandlers()) {
                cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);

                foreach (CatchBlock cb in _handlers) {
                    // Begin the strongly typed exception block
                    cg.BeginCatchBlock(cb.Test);

                    // Save the exception (if the catch block asked for it) or pop
                    EmitSaveExceptionOrPop(cg, cb);

                    //
                    // Emit the catch block body
                    //
                    cb.Body.Emit(cg);
                }

                cg.PopTargets(TargetBlockType.Catch);
            }

            //******************************************************************
            // 4. Emit the finally block
            //******************************************************************

            if (_finally != null) {
                Slot rethrow = null;
                if (flow.Any) {
                    // If there is a control flow in finally, end the catch
                    // statement and emit the catch-all and finally clause
                    // with rethrow at the end.

                    if (HaveHandlers()) {
                        cg.EndExceptionBlock();
                        cg.PopTargets(TargetBlockType.Try);
                    }

                    cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);
                    cg.BeginCatchBlock(typeof(Exception));

                    rethrow = cg.GetLocalTmp(typeof(Exception));
                    rethrow.EmitSet(cg);

                    cg.PopTargets(TargetBlockType.Catch);
                }

                cg.PushExceptionBlock(TargetBlockType.Finally, flowControlFlag);
                cg.BeginFinallyBlock();

                //
                // Emit the finally block body
                //
                _finally.Emit(cg);

                if (flow.Any) {
                    Debug.Assert(rethrow != null);
                    Label noRethrow = cg.DefineLabel();

                    rethrow.EmitGet(cg);
                    cg.EmitNull();
                    cg.Emit(OpCodes.Beq, noRethrow);
                    rethrow.EmitGet(cg);
                    cg.Emit(OpCodes.Throw);
                    cg.MarkLabel(noRethrow);
                }

                cg.EndExceptionBlock();
                cg.PopTargets(TargetBlockType.Finally);
            } else {
                cg.EndExceptionBlock();
            }

            cg.PopTargets(TargetBlockType.Try);

            //
            // Emit the flow control for finally, if there was any.
            //
            EmitFinallyFlowControl(cg, flow, flowControlFlag);

            cg.FreeLocalTmp(flowControlFlag);
        }
Example #11
0
        private void EmitGeneratorTry(CodeGen cg, TryFlowResult flow)
        {
            //
            // Initialize the flow control flag
            //
            Slot flowControlFlag = null;

            if (flow.Any) {
                flowControlFlag = cg.GetLocalTmp(typeof(int));
                cg.EmitInt(CodeGen.FinallyExitsNormally);
                flowControlFlag.EmitSet(cg);
            }

            Slot exception = null;
            if (_finally != null) {
                exception = cg.GetTemporarySlot(typeof(Exception));
                cg.EmitNull();
                exception.EmitSet(cg);
            }

            //******************************************************************
            // Entering the try block
            //******************************************************************

            if (_target != null) {
                cg.MarkLabel(_target.EnsureLabel(cg));
            }

            //******************************************************************
            // If we have a 'finally', transform it into try..catch..finally
            // and rethrow
            //******************************************************************
            Label endFinallyBlock = new Label();
            if (_finally != null) {
                cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
                cg.BeginExceptionBlock();
                endFinallyBlock = cg.DefineLabel();

                //**************************************************************
                // If there is a yield in any catch, that catch will be hoisted
                // and we need to dispatch to it from here
                //**************************************************************
                if (_yieldInCatch) {
                    EmitYieldDispatch(_catchYields, cg);
                }

                if (YieldInBlock(_finallyYields)) {
                    foreach (YieldTarget yt in _finallyYields) {
                        cg.GotoRouter.EmitGet(cg);
                        cg.EmitInt(yt.Index);
                        cg.Emit(OpCodes.Beq, endFinallyBlock);
                    }
                }
            }

            //******************************************************************
            // If we have a 'catch', start a try block to handle all the catches
            //******************************************************************

            Label endCatchBlock = new Label();
            if (HaveHandlers()) {
                cg.PushExceptionBlock(TargetBlockType.Try, flowControlFlag);
                endCatchBlock = cg.BeginExceptionBlock();
            }

            //******************************************************************
            // Emit the try block body
            //******************************************************************

            // First, emit the dispatch within the try block
            EmitYieldDispatch(_tryYields, cg);

            // Then, emit the actual body
            _body.Emit(cg);
            //cg.EmitSequencePointNone();

            //******************************************************************
            // Emit the catch blocks
            //******************************************************************

            if (HaveHandlers()) {
                List<CatchRecord> catches = new List<CatchRecord>();
                cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);

                foreach (CatchBlock cb in _handlers) {
                    cg.BeginCatchBlock(cb.Test);

                    if (cb.Yield) {
                        // The catch block body contains yield, therefore
                        // delay the body emit till after the try block.
                        Slot slot = cg.GetLocalTmp(cb.Test);
                        slot.EmitSet(cg);
                        catches.Add(new CatchRecord(slot, cb));
                    } else {
                        // Save the exception (if the catch block asked for it) or pop
                        EmitSaveExceptionOrPop(cg, cb);
                        // Emit the body right now, since it doesn't contain yield
                        cb.Body.Emit(cg);
                    }
                }

                cg.PopTargets(TargetBlockType.Catch);
                cg.EndExceptionBlock();
                cg.PopTargets(TargetBlockType.Try);

                //******************************************************************
                // Emit the postponed catch block bodies (with yield in them)
                //******************************************************************
                foreach (CatchRecord cr in catches) {
                    Label next = cg.DefineLabel();
                    cr.Slot.EmitGet(cg);
                    cg.EmitNull();
                    cg.Emit(OpCodes.Beq, next);

                    if (cr.Block.Slot != null) {
                        cr.Block.Slot.EmitSet(cg, cr.Slot);
                    }

                    cg.FreeLocalTmp(cr.Slot);
                    cr.Block.Body.Emit(cg);
                    cg.MarkLabel(next);
                    //cg.EmitSequencePointNone();
                }
            }

            //******************************************************************
            // Emit the finally body
            //******************************************************************

            if (_finally != null) {
                cg.MarkLabel(endFinallyBlock);
                cg.PushExceptionBlock(TargetBlockType.Catch, flowControlFlag);
                cg.BeginCatchBlock(typeof(Exception));
                exception.EmitSet(cg);

                cg.PopTargets(TargetBlockType.Catch);

                cg.PushExceptionBlock(TargetBlockType.Finally, flowControlFlag);
                cg.BeginFinallyBlock();

                Label noExit = cg.DefineLabel();
                cg.GotoRouter.EmitGet(cg);
                cg.EmitInt(CodeGen.GotoRouterYielding);
                cg.Emit(OpCodes.Bne_Un_S, noExit);
                cg.Emit(OpCodes.Endfinally);
                cg.MarkLabel(noExit);

                EmitYieldDispatch(_finallyYields, cg);

                // Emit the finally body

                _finally.Emit(cg);

                // Rethrow the exception, if any

                Label noThrow = cg.DefineLabel();
                exception.EmitGet(cg);
                cg.EmitNull();
                cg.Emit(OpCodes.Beq, noThrow);
                exception.EmitGet(cg);
                cg.Emit(OpCodes.Throw);
                cg.MarkLabel(noThrow);
                cg.FreeLocalTmp(exception);

                cg.EndExceptionBlock();
                cg.PopTargets(TargetBlockType.Finally);
                cg.PopTargets(TargetBlockType.Try);

                //
                // Emit the flow control for finally, if there was any.
                //
                EmitFinallyFlowControl(cg, flow, flowControlFlag);

                //cg.EmitSequencePointNone();
            }

            // Clear the target labels

            ClearLabels(_tryYields);
            ClearLabels(_catchYields);

            if (_target != null) {
                _target.Clear();
            }
        }