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); }
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(); }
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); }
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(); } }