Example #1
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 #2
0
        public override void Emit(CodeGen cg)
        {
            cg.EmitPosition(start, header);
            Slot  choiceVar = null;
            Slot  returnVar = null;
            Label endOfTry  = new Label();

            if (yieldTargets.Count > 0)
            {
                Label startOfBlock = cg.DefineLabel();
                choiceVar = cg.GetLocalTmp(typeof(int));
                returnVar = cg.GetLocalTmp(typeof(bool));
                cg.EmitInt(0);
                returnVar.EmitSet(cg);
                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);
            }

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

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

            body.Emit(cg);

            if (yieldTargets.Count > 0)
            {
                cg.MarkLabel(endOfTry);
            }

            cg.PopTargets();
            cg.PushFinallyBlock(returnVar);
            cg.BeginFinallyBlock();

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

            finallyStmt.Emit(cg);

            cg.EndExceptionBlock();
            cg.PopTargets();

            if (yieldTargets.Count > 0)
            {
                Label noReturn = cg.DefineLabel();
                returnVar.EmitGet(cg);
                cg.Emit(OpCodes.Brfalse_S, noReturn);
                cg.Emit(OpCodes.Ldc_I4_1);
                cg.EmitReturn();
                cg.MarkLabel(noReturn);
            }

            yieldTargets.Clear();
        }
Example #3
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 EmitWithFinallyBlock(CodeGen cg, Slot exc, Slot exit, Slot isTryYielded)
        {
            // we are certain that Finally will never yield
            cg.PushFinallyBlock(null, null);
            cg.BeginFinallyBlock();

            //finally body
            Label endOfFinally = cg.DefineLabel();

            // isTryYielded == True ?
            isTryYielded.EmitGet(cg);
            cg.EmitTestTrue();
            cg.Emit(OpCodes.Brtrue, endOfFinally);

            // exc == False ?
            exc.EmitGet(cg);
            cg.EmitTestTrue();
            cg.Emit(OpCodes.Brfalse, endOfFinally);

            //exit(None, None, None)
            cg.EmitCallerContext();
            exit.EmitGet(cg);
            cg.Emit(OpCodes.Ldnull);
            cg.Emit(OpCodes.Ldnull);
            cg.Emit(OpCodes.Ldnull);
            cg.EmitCall(typeof(Ops), "CallWithContext", new Type[] { typeof(ICallerContext), typeof(object), typeof(object), typeof(object), typeof(object) });
            cg.Emit(OpCodes.Pop);

            cg.MarkLabel(endOfFinally);
            cg.PopTargets();

            // finally end
        }
        // 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 #6
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 #7
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();
            }
        }