Пример #1
0
        private MSAst.Expression AddFinally(MSAst.Expression /*!*/ body)
        {
            if (_finally != null)
            {
                MSAst.ParameterExpression tryThrows    = Ast.Variable(typeof(Exception), "$tryThrows");
                MSAst.ParameterExpression locException = Ast.Variable(typeof(Exception), "$localException");

                MSAst.Expression @finally = _finally;

                // lots is going on here.  We need to consider:
                //      1. Exceptions propagating out of try/except/finally.  Here we need to save the line #
                //          from the exception block and not save the # from the finally block later.
                //      2. Exceptions propagating out of the finally block.  Here we need to report the line number
                //          from the finally block and leave the existing stack traces cleared.
                //      3. Returning from the try block: Here we need to run the finally block and not update the
                //          line numbers.
                body = AstUtils.Try( // we use a fault to know when we have an exception and when control leaves normally (via
                    // either a return or the body completing successfully).
                    AstUtils.Try(
                        Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(_headerIndex))),
                        Ast.Assign(tryThrows, AstUtils.Constant(null, typeof(Exception))),
                        body,
                        AstUtils.Empty()
                        ).Catch(
                        locException,
                        Expression.Block(
                            Ast.Assign(tryThrows, locException),
                            Expression.Rethrow()
                            )
                        )
                    ).FinallyWithJumps(
                    // if we had an exception save the line # that was last executing during the try
                    AstUtils.If(
                        Expression.NotEqual(tryThrows, Expression.Default(typeof(Exception))),
                        Parent.GetSaveLineNumberExpression(tryThrows, false)
                        ),

                    // clear the frames incase thae finally throws, and allow line number
                    // updates to proceed
                    UpdateLineUpdated(false),

                    // run the finally code
                    @finally,

                    // if we took an exception in the try block we have saved the line number.  Otherwise
                    // we have no line number saved and will need to continue saving them if
                    // other exceptions are thrown.
                    AstUtils.If(
                        Expression.NotEqual(tryThrows, Expression.Default(typeof(Exception))),
                        UpdateLineUpdated(true)
                        )
                    );
                body = Ast.Block(new[] { tryThrows }, body);
            }

            return(body);
        }
Пример #2
0
        public override MSAst.Expression Reduce()
        {
            // allocated all variables here so they won't be shared w/ other
            // locals allocated during the body or except blocks.
            MSAst.ParameterExpression lineUpdated = null;
            MSAst.ParameterExpression runElse     = null;

            if (_else != null || (_handlers != null && _handlers.Length > 0))
            {
                lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_try");
                if (_else != null)
                {
                    runElse = Ast.Variable(typeof(bool), "run_else");
                }
            }

            // don't allocate locals below here...
            MSAst.Expression          body = _body;
            MSAst.Expression          @else = _else;
            MSAst.Expression          @catch, result;
            MSAst.ParameterExpression exception;

            if (_handlers != null && _handlers.Length > 0)
            {
                exception = Ast.Variable(typeof(Exception), "$exception");
                @catch    = TransformHandlers(exception);
            }
            else
            {
                exception = null;
                @catch    = null;
            }

            // We have else clause, must generate guard around it
            if (@else != null)
            {
                Debug.Assert(@catch != null);

                //  run_else = true;
                //  try {
                //      try_body
                //  } catch ( ... ) {
                //      run_else = false;
                //      catch_body
                //  }
                //  if (run_else) {
                //      else_body
                //  }
                result =
                    Ast.Block(
                        Ast.Assign(runElse, AstUtils.Constant(true)),
                        // save existing line updated, we could choose to do this only for nested exception handlers.
                        PushLineUpdated(false, lineUpdated),
                        AstUtils.Try(
                            Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                            body
                            ).Catch(exception,
                                    Ast.Assign(runElse, AstUtils.Constant(false)),
                                    @catch,
                                    // restore existing line updated after exception handler completes
                                    PopLineUpdated(lineUpdated),
                                    Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                    AstUtils.Default(body.Type)
                                    ),
                        AstUtils.IfThen(runElse,
                                        @else
                                        ),
                        AstUtils.Empty()
                        );
            }
            else if (@catch != null)            // no "else" clause
            //  try {
            //      <try body>
            //  } catch (Exception e) {
            //      ... catch handling ...
            //  }
            //
            {
                result =
                    AstUtils.Try(
                        GlobalParent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                        // save existing line updated
                        PushLineUpdated(false, lineUpdated),
                        body
                        ).Catch(exception,
                                @catch,
                                // restore existing line updated after exception handler completes
                                PopLineUpdated(lineUpdated),
                                Ast.Call(AstMethods.ExceptionHandled, Parent.LocalContext),
                                Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                AstUtils.Default(body.Type)
                                );
            }
            else
            {
                result = body;
            }

            return(Ast.Block(
                       GetVariables(lineUpdated, runElse),
                       AddFinally(result)
                       ));
        }
Пример #3
0
        private MSAst.Expression AddFinally(MSAst.Expression /*!*/ body, MSAst.ParameterExpression nestedException)
        {
            if (_finally != null)
            {
                Debug.Assert(nestedException != null);

                MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames");

                MSAst.Expression @finally = _finally;

                // lots is going on here.  We need to consider:
                //      1. Exceptions propagating out of try/except/finally.  Here we need to save the line #
                //          from the exception block and not save the # from the finally block later.
                //      2. Exceptions propagating out of the finally block.  Here we need to report the line number
                //          from the finally block and leave the existing stack traces cleared.
                //      3. Returning from the try block: Here we need to run the finally block and not update the
                //          line numbers.
                body = AstUtils.Try( // we use a fault to know when we have an exception and when control leaves normally (via
                    // either a return or the body completing successfully).
                    AstUtils.Try(
                        Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                        Ast.Assign(nestedException, AstUtils.Constant(false)),
                        body
                        ).Fault(
                        // fault
                        Ast.Assign(nestedException, AstUtils.Constant(true))
                        )
                    ).FinallyWithJumps(
                    // if we had an exception save the line # that was last executing during the try
                    AstUtils.If(
                        nestedException,
                        Parent.GetSaveLineNumberExpression(false)
                        ),

                    // clear the frames incase thae finally throws, and allow line number
                    // updates to proceed
                    UpdateLineUpdated(false),
                    Ast.Assign(
                        nestedFrames,
                        Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
                        ),

                    // run the finally code
                    @finally,

                    // if the finally exits normally restore any previous exception info
                    Ast.Call(
                        AstMethods.SetDynamicStackFrames,
                        nestedFrames
                        ),

                    // if we took an exception in the try block we have saved the line number.  Otherwise
                    // we have no line number saved and will need to continue saving them if
                    // other exceptions are thrown.
                    AstUtils.If(
                        nestedException,
                        UpdateLineUpdated(true)
                        )
                    );

                body = Ast.Block(new[] { nestedFrames }, body);
            }
            return(body);
        }
Пример #4
0
        public override MSAst.Expression Reduce()
        {
            // allocated all variables here so they won't be shared w/ other
            // locals allocated during the body or except blocks.
            MSAst.ParameterExpression?lineUpdated = null;
            MSAst.ParameterExpression?runElse     = null;
            MSAst.ParameterExpression?previousExceptionContext = null;

            Debug.Assert(Else is null || _handlers.Length > 0);

            if (_handlers.Length > 0)
            {
                lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_try");
                if (Else != null)
                {
                    runElse = Ast.Variable(typeof(bool), "run_else");
                }
            }

            // don't allocate locals below here...
            MSAst.Expression          body  = Body;
            MSAst.Expression?         @else = Else;
            MSAst.Expression?         @catch;
            MSAst.Expression          result;
            MSAst.ParameterExpression?exception;

            if (_handlers.Length > 0)
            {
                previousExceptionContext = Ast.Variable(typeof(Exception), "$previousException");
                exception = Ast.Variable(typeof(Exception), "$exception");
                @catch    = TransformHandlers(exception, previousExceptionContext);
            }
            else if (Finally != null)
            {
                exception = Ast.Variable(typeof(Exception), "$exception");
                @catch    = null;
            }
            else
            {
                exception = null;
                @catch    = null;
            }

            // We have else clause, must generate guard around it
            if (@else != null)
            {
                Debug.Assert(runElse != null);
                Debug.Assert(previousExceptionContext != null && exception != null && @catch != null);

                //  run_else = true;
                //  try {
                //      try_body
                //  } catch ( ... ) {
                //      run_else = false;
                //      catch_body
                //  }
                //  if (run_else) {
                //      else_body
                //  }
                result =
                    Ast.Block(
                        Ast.Assign(runElse, AstUtils.Constant(true)),
                        // save existing line updated, we could choose to do this only for nested exception handlers.
                        PushLineUpdated(false, lineUpdated),
                        LightExceptions.RewriteExternal(
                            AstUtils.Try(
                                Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(HeaderIndex))),
                                Ast.Assign(previousExceptionContext, Ast.Call(AstMethods.SaveCurrentException)),
                                body,
                                AstUtils.Constant(null)
                                ).Catch(exception,
                                        Ast.Assign(runElse, AstUtils.Constant(false)),
                                        @catch,
                                        // restore existing line updated after exception handler completes
                                        PopLineUpdated(lineUpdated),
                                        Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                        AstUtils.Constant(null)
                                        )
                            ),
                        AstUtils.IfThen(runElse,
                                        @else
                                        ),
                        AstUtils.Empty()
                        );
            }
            else if (@catch != null)            // no "else" clause
            //  try {
            //      <try body>
            //  } catch (Exception e) {
            //      ... catch handling ...
            //  }
            //
            {
                Debug.Assert(previousExceptionContext != null && exception != null);

                result =
                    LightExceptions.RewriteExternal(
                        AstUtils.Try(
                            GlobalParent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(HeaderIndex))),
                            // save existing line updated
                            PushLineUpdated(false, lineUpdated),
                            Ast.Assign(previousExceptionContext, Ast.Call(AstMethods.SaveCurrentException)),
                            body,
                            AstUtils.Constant(null)
                            ).Catch(exception,
                                    @catch,
                                    // restore existing line updated after exception handler completes
                                    PopLineUpdated(lineUpdated),
                                    Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                    AstUtils.Constant(null)
                                    )
                        );
            }
            else
            {
                result = body;
            }

            return(Ast.Block(
                       GetVariables(lineUpdated, runElse, previousExceptionContext),
                       AddFinally(result),
                       AstUtils.Default(typeof(void))
                       ));
        }