/// <summary>
        /// Create code for given catch block
        /// </summary>
        public override RLRange Visit(AstTryCatchBlock.CatchBlock node, AstNode parent)
        {
            // Allocate exception register
            var r     = frame.AllocateTemp(node.ExceptionType.GetReference(targetPackage));
            var first = this.Add(node.SourceLocation, RCode.Move_exception, r);
            var last  = first;

            currentExceptionRegister.Push(r);

            // Store exception in exception variable (if any)
            if (node.ExceptionVariable != null)
            {
                var rVar = frame.GetArgument(node.ExceptionVariable);
                this.Add(node.SourceLocation, RCode.Move_object, rVar, r);
            }

            // Generate code for actual catch block.
            var result = Visit((AstBlock)node, parent);

            if (result != null)
            {
                last = result.Last;
            }

            currentExceptionRegister.Pop();

            // Combine result
            return(new RLRange(first, last, null));
        }
Beispiel #2
0
        List<AstNode> ConvertToAst(List<ByteCode> body, HashSet<ExceptionHandler> ehs)
        {
            var ast = new List<AstNode>();

            while (ehs.Any())
            {
                var tryCatchBlock = new AstTryCatchBlock(null);

                // Find the first and widest scope
                var tryStart = ehs.Min(eh => eh.TryStart.Offset);
                var tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
                var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();

                // Remember that any part of the body migt have been removed due to unreachability

                // Cut all instructions up to the try block
                {
                    var tryStartIdx = 0;
                    while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart) tryStartIdx++;
                    ast.AddRange(ConvertToAst(CollectionExtensions.CutRange(body, 0, tryStartIdx)));
                }

                // Cut the try block
                {
                    var nestedEHs = new HashSet<ExceptionHandler>(
                        ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)));
                    ehs.ExceptWith(nestedEHs);
                    var tryEndIdx = 0;
                    while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd) tryEndIdx++;
                    var converted = ConvertToAst(CollectionExtensions.CutRange(body, 0, tryEndIdx), nestedEHs);
                    tryCatchBlock.TryBlock = new AstBlock(converted.Select(x => x.SourceLocation).FirstOrDefault(), converted);
                }

                // Cut all handlers
                tryCatchBlock.CatchBlocks.Clear();
                foreach (var eh in handlers)
                {
                    var handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset;
                    var startIdx = 0;
                    while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset) startIdx++;
                    var endIdx = 0;
                    while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset) endIdx++;
                    var nestedEHs = new HashSet<ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset)));
                    ehs.ExceptWith(nestedEHs);
                    var handlerAst = ConvertToAst(CollectionExtensions.CutRange(body, startIdx, endIdx - startIdx), nestedEHs);
                    if (eh.HandlerType == ExceptionHandlerType.Catch)
                    {
                        var catchType = eh.CatchType.IsSystemObject() ? module.TypeSystem.Exception : XBuilder.AsTypeReference(module, eh.CatchType);
                        var catchBlock = new AstTryCatchBlock.CatchBlock(handlerAst.Select(x => x.SourceLocation).FirstOrDefault(), tryCatchBlock)
                        {
                            ExceptionType = catchType,
                            Body = handlerAst
                        };
                        // Handle the automatically pushed exception on the stack
                        var ldexception = ldexceptions[eh];
                        if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0)
                        {
                            // Exception is not used
                            catchBlock.ExceptionVariable = null;
                        }
                        else if (ldexception.StoreTo.Count == 1)
                        {
                            var first = catchBlock.Body[0] as AstExpression;
                            if (first != null &&
                                first.Code == AstCode.Pop &&
                                first.Arguments[0].Code == AstCode.Ldloc &&
                                first.Arguments[0].Operand == ldexception.StoreTo[0])
                            {
                                // The exception is just poped - optimize it all away;
                                if (context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks)
                                    catchBlock.ExceptionVariable = new AstGeneratedVariable("ex_" + eh.HandlerStart.Offset.ToString("X2"), null);
                                else
                                    catchBlock.ExceptionVariable = null;
                                catchBlock.Body.RemoveAt(0);
                            }
                            else
                            {
                                catchBlock.ExceptionVariable = ldexception.StoreTo[0];
                            }
                        }
                        else
                        {
                            var exTemp = new AstGeneratedVariable("ex_" + eh.HandlerStart.Offset.ToString("X2"), null);
                            catchBlock.ExceptionVariable = exTemp;
                            foreach (var storeTo in ldexception.StoreTo)
                            {
                                catchBlock.Body.Insert(0, new AstExpression(catchBlock.SourceLocation, AstCode.Stloc, storeTo, new AstExpression(catchBlock.SourceLocation, AstCode.Ldloc, exTemp)));
                            }
                        }
                        tryCatchBlock.CatchBlocks.Add(catchBlock);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Finally)
                    {
                        tryCatchBlock.FinallyBlock = new AstBlock(handlerAst);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Fault)
                    {
                        tryCatchBlock.FaultBlock = new AstBlock(handlerAst);
                    }
                    else
                    {
                        // TODO: ExceptionHandlerType.Filter
                    }
                }

                ehs.ExceptWith(handlers);

                ast.Add(tryCatchBlock);
            }

            // Add whatever is left
            ast.AddRange(ConvertToAst(body));

            return ast;
        }
Beispiel #3
0
 public virtual TReturn Visit(AstTryCatchBlock.CatchBlock node, TData data)
 {
     return(Visit((AstBlock)node, data));
 }
Beispiel #4
0
        /// <summary>
        /// Convert the given set of bytecodes to an Ast node list.
        /// Split exception handlers into Ast try/catch blocks.
        /// </summary>
        private List<AstNode> ConvertToAst(List<ByteCode> body, HashSet<ExceptionHandler> ehs, List<ByteCodeBlock> blockStarts, int nestingLevel, Dictionary<int, ByteCode> offset2ByteCode)
        {
            var ast = new List<AstNode>();

            // Split body in blocks

            while (ehs.Any())
            {
                var tryCatchBlock = new AstTryCatchBlock(null);

                // Find the first and widest scope
                var tryStart = ehs.Min(eh => eh.StartPc);
                var tryEnd = ehs.Where(eh => eh.StartPc == tryStart).Max(eh => eh.EndPc);
                var handlers = ehs.Where(eh => (eh.StartPc == tryStart) && (eh.EndPc == tryEnd)).OrderBy(eh => eh.HandlerPc).ToList();

                // Remember that any part of the body migt have been removed due to unreachability

                // Cut all instructions up to the try block
                {
                    var tryStartIdx = 0;
                    while ((tryStartIdx < body.Count) && (body[tryStartIdx].Offset < tryStart))
                    {
                        tryStartIdx++;
                    }
                    if (tryStartIdx > 0)
                    {
                        ast.AddRange(ConvertRangeToAst(body.CutRange(0, tryStartIdx)));
                        // Make sure the block before the try block ends with an unconditional control flow
                        AddUnconditionalBranchToNext(ast, body, 0);
                    }
                }

                // Cut the try block
                {
                    var nestedEHs = new HashSet<ExceptionHandler>(
                        ehs.Where(eh => ((tryStart <= eh.StartPc) && (eh.EndPc < tryEnd)) || ((tryStart < eh.StartPc) && (eh.EndPc <= tryEnd))));
                    ehs.ExceptWith(nestedEHs);
                    var tryEndIdx = 0;
                    while ((tryEndIdx < body.Count) && (body[tryEndIdx].Offset < tryEnd))
                    {
                        tryEndIdx++;
                    }
                    var converted = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs, blockStarts, nestingLevel + 1, offset2ByteCode);
                    tryCatchBlock.TryBlock = new AstBlock(converted.Select(x => x.SourceLocation).FirstOrDefault(), converted);
                    // Make sure the try block ends with an unconditional control flow
                    AddUnconditionalBranchToNext(tryCatchBlock.TryBlock.Body, body, 0);
                }

                // Cut all handlers
                tryCatchBlock.CatchBlocks.Clear();
                foreach (var iterator in handlers)
                {
                    var eh = iterator;
                    var handler = offset2ByteCode[eh.HandlerPc]; // body.First(x => x.Offset == eh.HandlerPc);
                    var catchType = eh.IsCatchAll ? typeSystem.Object : AsTypeReference(eh.CatchType, XTypeUsageFlags.CatchType);
                    var catchBlock = new AstTryCatchBlock.CatchBlock(handler.SourceLocation, tryCatchBlock)
                    {
                        ExceptionType = catchType,
                        Body = new List<AstNode>()
                    };

                    // Create catch "body" (actually a jump to the handler)
                    // Handle the automatically pushed exception on the stack
                    var ldexception = ldexceptions[eh];
                    catchBlock.Body.Add(new AstExpression(handler.SourceLocation, AstCode.Br, handler.Label(true)));
                    if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0)
                    {
                        // Exception is not used
                        catchBlock.ExceptionVariable = null;
                    }
                    else if (ldexception.StoreTo.Count == 1)
                    {
                        /*var first = catchBlock.Body.FirstOrDefault() as AstExpression;
                        if (first != null &&
                            first.Code == AstCode.Pop &&
                            first.Arguments[0].Code == AstCode.Ldloc &&
                            first.Arguments[0].Operand == ldexception.StoreTo[0])
                        {
                            // The exception is just poped - optimize it all away;
                            catchBlock.ExceptionVariable = new AstGeneratedVariable("ex_" + eh.HandlerPc.ToString("X2"));
                            catchBlock.Body.RemoveAt(0);
                        }
                        else*/
                        {
                            catchBlock.ExceptionVariable = ldexception.StoreTo[0];
                        }
                    }
                    else
                    {
                        var exTemp = new AstGeneratedVariable("ex_" + eh.HandlerPc.ToString("X2"), null);
                        catchBlock.ExceptionVariable = exTemp;
                        foreach (var storeTo in ldexception.StoreTo)
                        {
                            catchBlock.Body.Insert(0, new AstExpression(catchBlock.SourceLocation, AstCode.Stloc, storeTo, new AstExpression(catchBlock.SourceLocation, AstCode.Ldloc, exTemp)));
                        }
                    }
                    tryCatchBlock.CatchBlocks.Add(catchBlock);
                }

                ehs.ExceptWith(handlers);

                ast.Add(tryCatchBlock);
            }

            // Add whatever is left
            ast.AddRange(ConvertRangeToAst(body));

            return ast;
        }
Beispiel #5
0
        /// <summary>
        /// Convert the given set of bytecodes to an Ast node list.
        /// Split exception handlers into Ast try/catch blocks.
        /// </summary>
        private List <AstNode> ConvertToAst(List <ByteCode> body, HashSet <ExceptionHandler> ehs, List <ByteCodeBlock> blockStarts, int nestingLevel, Dictionary <int, ByteCode> offset2ByteCode)
        {
            var ast = new List <AstNode>();

            // Split body in blocks

            while (ehs.Any())
            {
                var tryCatchBlock = new AstTryCatchBlock(null);

                // Find the first and widest scope
                var tryStart = ehs.Min(eh => eh.StartPc);
                var tryEnd   = ehs.Where(eh => eh.StartPc == tryStart).Max(eh => eh.EndPc);
                var handlers = ehs.Where(eh => (eh.StartPc == tryStart) && (eh.EndPc == tryEnd)).OrderBy(eh => eh.HandlerPc).ToList();

                // Remember that any part of the body migt have been removed due to unreachability

                // Cut all instructions up to the try block
                {
                    var tryStartIdx = 0;
                    while ((tryStartIdx < body.Count) && (body[tryStartIdx].Offset < tryStart))
                    {
                        tryStartIdx++;
                    }
                    if (tryStartIdx > 0)
                    {
                        ast.AddRange(ConvertRangeToAst(body.CutRange(0, tryStartIdx)));
                        // Make sure the block before the try block ends with an unconditional control flow
                        AddUnconditionalBranchToNext(ast, body, 0);
                    }
                }

                // Cut the try block
                {
                    var nestedEHs = new HashSet <ExceptionHandler>(
                        ehs.Where(eh => ((tryStart <= eh.StartPc) && (eh.EndPc < tryEnd)) || ((tryStart < eh.StartPc) && (eh.EndPc <= tryEnd))));
                    ehs.ExceptWith(nestedEHs);
                    var tryEndIdx = 0;
                    while ((tryEndIdx < body.Count) && (body[tryEndIdx].Offset < tryEnd))
                    {
                        tryEndIdx++;
                    }
                    var converted = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs, blockStarts, nestingLevel + 1, offset2ByteCode);
                    tryCatchBlock.TryBlock = new AstBlock(converted.Select(x => x.SourceLocation).FirstOrDefault(), converted);
                    // Make sure the try block ends with an unconditional control flow
                    AddUnconditionalBranchToNext(tryCatchBlock.TryBlock.Body, body, 0);
                }

                // Cut all handlers
                tryCatchBlock.CatchBlocks.Clear();
                foreach (var iterator in handlers)
                {
                    var eh         = iterator;
                    var handler    = offset2ByteCode[eh.HandlerPc]; // body.First(x => x.Offset == eh.HandlerPc);
                    var catchType  = eh.IsCatchAll ? typeSystem.Object : AsTypeReference(eh.CatchType, XTypeUsageFlags.CatchType);
                    var catchBlock = new AstTryCatchBlock.CatchBlock(handler.SourceLocation, tryCatchBlock)
                    {
                        ExceptionType = catchType,
                        Body          = new List <AstNode>()
                    };

                    // Create catch "body" (actually a jump to the handler)
                    // Handle the automatically pushed exception on the stack
                    var ldexception = ldexceptions[eh];
                    catchBlock.Body.Add(new AstExpression(handler.SourceLocation, AstCode.Br, handler.Label(true)));
                    if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0)
                    {
                        // Exception is not used
                        catchBlock.ExceptionVariable = null;
                    }
                    else if (ldexception.StoreTo.Count == 1)
                    {
                        /*var first = catchBlock.Body.FirstOrDefault() as AstExpression;
                         * if (first != null &&
                         *  first.Code == AstCode.Pop &&
                         *  first.Arguments[0].Code == AstCode.Ldloc &&
                         *  first.Arguments[0].Operand == ldexception.StoreTo[0])
                         * {
                         *  // The exception is just poped - optimize it all away;
                         *  catchBlock.ExceptionVariable = new AstGeneratedVariable("ex_" + eh.HandlerPc.ToString("X2"));
                         *  catchBlock.Body.RemoveAt(0);
                         * }
                         * else*/
                        {
                            catchBlock.ExceptionVariable = ldexception.StoreTo[0];
                        }
                    }
                    else
                    {
                        var exTemp = new AstGeneratedVariable("ex_" + eh.HandlerPc.ToString("X2"), null);
                        catchBlock.ExceptionVariable = exTemp;
                        foreach (var storeTo in ldexception.StoreTo)
                        {
                            catchBlock.Body.Insert(0, new AstExpression(catchBlock.SourceLocation, AstCode.Stloc, storeTo, new AstExpression(catchBlock.SourceLocation, AstCode.Ldloc, exTemp)));
                        }
                    }
                    tryCatchBlock.CatchBlocks.Add(catchBlock);
                }

                ehs.ExceptWith(handlers);

                ast.Add(tryCatchBlock);
            }

            // Add whatever is left
            ast.AddRange(ConvertRangeToAst(body));

            return(ast);
        }
Beispiel #6
0
        List <AstNode> ConvertToAst(List <ByteCode> body, HashSet <ExceptionHandler> ehs)
        {
            var ast = new List <AstNode>();

            while (ehs.Any())
            {
                var tryCatchBlock = new AstTryCatchBlock(null);

                // Find the first and widest scope
                var tryStart = ehs.Min(eh => eh.TryStart.Offset);
                var tryEnd   = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
                var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();

                // Remember that any part of the body migt have been removed due to unreachability

                // Cut all instructions up to the try block
                {
                    var tryStartIdx = 0;
                    while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart)
                    {
                        tryStartIdx++;
                    }
                    ast.AddRange(ConvertToAst(CollectionExtensions.CutRange(body, 0, tryStartIdx)));
                }

                // Cut the try block
                {
                    var nestedEHs = new HashSet <ExceptionHandler>(
                        ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)));
                    ehs.ExceptWith(nestedEHs);
                    var tryEndIdx = 0;
                    while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd)
                    {
                        tryEndIdx++;
                    }
                    var converted = ConvertToAst(CollectionExtensions.CutRange(body, 0, tryEndIdx), nestedEHs);
                    tryCatchBlock.TryBlock = new AstBlock(converted.Select(x => x.SourceLocation).FirstOrDefault(), converted);
                }

                // Cut all handlers
                tryCatchBlock.CatchBlocks.Clear();
                foreach (var eh in handlers)
                {
                    var handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset;
                    var startIdx         = 0;
                    while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset)
                    {
                        startIdx++;
                    }
                    var endIdx = 0;
                    while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset)
                    {
                        endIdx++;
                    }
                    var nestedEHs = new HashSet <ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset)));
                    ehs.ExceptWith(nestedEHs);
                    var handlerAst = ConvertToAst(CollectionExtensions.CutRange(body, startIdx, endIdx - startIdx), nestedEHs);
                    if (eh.HandlerType == ExceptionHandlerType.Catch)
                    {
                        var catchType  = eh.CatchType.IsSystemObject() ? module.TypeSystem.Exception : XBuilder.AsTypeReference(module, eh.CatchType);
                        var catchBlock = new AstTryCatchBlock.CatchBlock(handlerAst.Select(x => x.SourceLocation).FirstOrDefault(), tryCatchBlock)
                        {
                            ExceptionType = catchType,
                            Body          = handlerAst
                        };
                        // Handle the automatically pushed exception on the stack
                        var ldexception = ldexceptions[eh];
                        if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0)
                        {
                            // Exception is not used
                            catchBlock.ExceptionVariable = null;
                        }
                        else if (ldexception.StoreTo.Count == 1)
                        {
                            var first = catchBlock.Body[0] as AstExpression;
                            if (first != null &&
                                first.Code == AstCode.Pop &&
                                first.Arguments[0].Code == AstCode.Ldloc &&
                                first.Arguments[0].Operand == ldexception.StoreTo[0])
                            {
                                // The exception is just poped - optimize it all away;
                                if (context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks)
                                {
                                    catchBlock.ExceptionVariable = new AstGeneratedVariable("ex_" + eh.HandlerStart.Offset.ToString("X2"), null);
                                }
                                else
                                {
                                    catchBlock.ExceptionVariable = null;
                                }
                                catchBlock.Body.RemoveAt(0);
                            }
                            else
                            {
                                catchBlock.ExceptionVariable = ldexception.StoreTo[0];
                            }
                        }
                        else
                        {
                            var exTemp = new AstGeneratedVariable("ex_" + eh.HandlerStart.Offset.ToString("X2"), null);
                            catchBlock.ExceptionVariable = exTemp;
                            foreach (var storeTo in ldexception.StoreTo)
                            {
                                catchBlock.Body.Insert(0, new AstExpression(catchBlock.SourceLocation, AstCode.Stloc, storeTo, new AstExpression(catchBlock.SourceLocation, AstCode.Ldloc, exTemp)));
                            }
                        }
                        tryCatchBlock.CatchBlocks.Add(catchBlock);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Finally)
                    {
                        tryCatchBlock.FinallyBlock = new AstBlock(handlerAst);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Fault)
                    {
                        tryCatchBlock.FaultBlock = new AstBlock(handlerAst);
                    }
                    else
                    {
                        // TODO: ExceptionHandlerType.Filter
                    }
                }

                ehs.ExceptWith(handlers);

                ast.Add(tryCatchBlock);
            }

            // Add whatever is left
            ast.AddRange(ConvertToAst(body));

            return(ast);
        }
 /// <summary>
 /// Is the given catch block a catch all?
 /// </summary>
 public static bool IsCatchAll(this AstTryCatchBlock.CatchBlock catchBlock)
 {
     return(catchBlock.ExceptionType.IsSystemObject());
 }