Ejemplo n.º 1
0
        /// <summary>
        /// If the finally statement contains break, continue, return or yield, we need to
        /// handle the control flow statement after we exit out of finally via OpCodes.Endfinally.
        /// </summary>
        private static void EmitFinallyFlowControl(CodeGen cg, TryFlowResult flow, Slot flag)
        {
            if (flow.Return || flow.Yield)
            {
                Debug.Assert(flag != null);

                Label noReturn = cg.DefineLabel();

                flag.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 (flow.Any)
                {
                    // return the actual value
                    cg.EmitReturnValue();
                    cg.EmitReturn();
                }
                cg.MarkLabel(noReturn);
            }

            // Only emit break handling if it is actually needed
            if (flow.Break)
            {
                Debug.Assert(flag != null);

                Label noReturn = cg.DefineLabel();
                flag.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForBreak);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitBreak();
                cg.MarkLabel(noReturn);
            }

            // Only emit continue handling if it if actually needed
            if (flow.Continue)
            {
                Debug.Assert(flag != null);

                Label noReturn = cg.DefineLabel();
                flag.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForContinue);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitContinue();
                cg.MarkLabel(noReturn);
            }
        }
Ejemplo n.º 2
0
        public override void Emit(CodeGen cg)
        {
            // Codegen is affected by presence/absence of loop control statements
            // (break/continue) or return/yield statement in finally clause
            TryFlowResult flow = TryFlowAnalyzer.Analyze(FinallyStatement);

            //cg.EmitPosition(Start, _header);

            // If there's a yield anywhere, go for a complex codegen
            if (YieldInBlock(_tryYields) || _yieldInCatch || YieldInBlock(_finallyYields))
            {
                EmitGeneratorTry(cg, flow);
            }
            else
            {
                EmitSimpleTry(cg, flow);
            }
        }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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();
            }
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 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();
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// If the finally statement contains break, continue, return or yield, we need to
        /// handle the control flow statement after we exit out of finally via OpCodes.Endfinally.
        /// </summary>
        private static void EmitFinallyFlowControl(CodeGen cg, TryFlowResult flow, Slot flag)
        {
            if (flow.Return || flow.Yield) {
                Debug.Assert(flag != null);

                Label noReturn = cg.DefineLabel();

                flag.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 (flow.Any) {
                    // return the actual value
                    cg.EmitReturnValue();
                    cg.EmitReturn();
                }
                cg.MarkLabel(noReturn);
            }

            // Only emit break handling if it is actually needed
            if (flow.Break) {
                Debug.Assert(flag != null);

                Label noReturn = cg.DefineLabel();
                flag.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForBreak);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitBreak();
                cg.MarkLabel(noReturn);
            }

            // Only emit continue handling if it if actually needed
            if (flow.Continue) {
                Debug.Assert(flag != null);

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