コード例 #1
0
        private void TryCatchSetTargetRegister(FinallyBlockState finallyBlock, bool needTargetRegister)
        {
            var localTargets = finallyBlock.Targets.Where(t => t.State == finallyBlock);

            if (needTargetRegister)
            {
                finallyBlock.TargetRegister = Frame.AllocateTemp(PrimitiveType.Int);
                var setToZero = new Instruction(RCode.Const, 0, new [] { finallyBlock.TargetRegister });
                instructions.Insert(finallyBlock.FirstInstruction.Index, setToZero);

                foreach (var t in localTargets)
                {
                    if (t.SetTarget.Code != RCode.Nop)
                    {
                        t.SetTarget.Registers.Add(finallyBlock.TargetRegister);
                    }
                }
            }
            else
            {
                foreach (var t in localTargets)
                {
                    t.SetTarget.ConvertToNop();
                }
            }
        }
コード例 #2
0
 public FinallyBlockState(FinallyBlockState outerBlock, int depth, AstCompilerVisitor compiler, Instruction first, Instruction last)
 {
     _compiler           = compiler;
     NonException        = new Instruction();
     AfterExceptionCheck = new Instruction();
     FirstInstruction    = first;
     LastInstruction     = last;
     Depth             = depth;
     OuterFinallyBlock = outerBlock;
 }
コード例 #3
0
        private Instruction TryCatchGotoEnd(FinallyBlockState state, Instruction last)
        {
            if (state.HasFinally)
            {
                var rlrange = state.BranchToFinally_FallOut(AstNode.NoSource, last, new List <RLRange>());
                return(rlrange.Last);
            }

            // goto end
            return(this.Add(AstNode.NoSource, RCode.Goto, last));
        }
コード例 #4
0
 public FinallyBlockState(FinallyBlockState outerBlock, int depth)
 {
     Depth             = depth;
     OuterFinallyBlock = outerBlock;
 }
コード例 #5
0
        /// <summary>
        /// return the first emitted instruction
        /// </summary>
        private Instruction TryCatchEmitTargetInstruction(FinallyTarget target, ref int insIdx, FinallyBlockState outerFinallyBlock)
        {
            bool emitReturn = outerFinallyBlock == null && target.IsReturn;

            bool chainToOuterBlock = outerFinallyBlock != null && target.IsReturn;

            if (target.IsLeave && outerFinallyBlock != null)
            {
                // check if the leave leaves the outer finally block as well.
                if (target.Destination.Index < outerFinallyBlock.FirstInstruction.Index ||
                    target.Destination.Index > outerFinallyBlock.LastInstruction.Index)
                {
                    chainToOuterBlock = true;
                }
            }

            if (emitReturn)
            {
                Instruction ret;
                if (currentMethod.ReturnsVoid)
                {
                    ret = new Instruction(RCode.Return_void);
                }
                else
                {
                    var retCode = currentMethod.ReturnsDexWide
                        ? RCode.Return_wide
                        : currentMethod.ReturnsDexValue
                            ? RCode.Return
                            : RCode.Return_object;
                    ret = new Instruction(retCode, finallyState.ReturnValueRegister);
                }
                instructions.Insert(insIdx++, ret);
                return(ret);
            }
            else if (chainToOuterBlock)
            {
                Debug.Assert(outerFinallyBlock != null);
                int id = target.SetTarget.Code == RCode.Nop ? 0 : (int)target.SetTarget.Operand;

                RLRange range;
                if (target.IsReturn)
                {
                    range = outerFinallyBlock.BranchToFinally_Ret(ref insIdx);
                }
                else // IsLeave
                {
                    range = outerFinallyBlock.BranchToFinally_Leave(target.Destination, ref insIdx);
                }

                // This is a little bit hackish. We need to set the operand in the setTarget instruction.
                if (id == 0)
                {
                    range.First.ConvertToNop();
                }
                else
                {
                    range.First.Operand = id;
                }

                return(range.First);
            }
            else
            {
                // goto
                var insGoto = new Instruction(RCode.Goto, target.Destination);
                instructions.Insert(insIdx++, insGoto);
                return(insGoto);
            }
        }
コード例 #6
0
        /// <summary>
        /// Create try/catch/finally/fault block
        /// </summary>
        public override RLRange Visit(AstTryCatchBlock node, AstNode parent)
        {
            var handler = new ExceptionHandler();

            //if (node.FaultBlock != null)
            //{
            //    Debugger.Break();
            //}

            // Setup instruction before/after my node.
            var first = new Instruction()
            {
                SequencePoint = node.SourceLocation
            };
            var last = new Instruction(RCode.Nop);

            FinallyBlockState finState      = null;
            FinallyBlockState outerFinState = tryCatchStack.FirstOrDefault(f => f.HasFinally);

            if (tryCatchStack.Count == 0)
            {
                finallyState.FinallyStacks.Add(new List <FinallyBlockState>());
            }

            if (node.FinallyBlock != null)
            {
                // store finaly state
                finState = new FinallyBlockState(outerFinState, tryCatchStack.Count, this, first, last);

                finState.FinallyExceptionRegister = frame.AllocateTemp(new ClassReference("java.lang.Throwable")).Register;
                // clear the variable to make sure it isn't stale from a previous loop.
                // make sure this is outside the try block for edge case exceptions.
                this.Add(node.SourceLocation, RCode.Const, 0, finState.FinallyExceptionRegister);

                tryCatchStack.Push(finState);
                finallyState.FinallyStacks.Last().Add(finState);
            }
            else
            {
                finState = new FinallyBlockState(outerFinState, tryCatchStack.Count);
                tryCatchStack.Push(finState);
            }

            instructions.Add(first);
            // Emit try block
            handler.TryStart = first;
            node.TryBlock.AcceptOrDefault(this, node);
            handler.TryEnd = TryCatchGotoEnd(finState, last);

            var catchesStart = this.Add(AstNode.NoSource, RCode.Nop);

            // Emit "normal" catch blocks
            foreach (var catchBlock in node.CatchBlocks.Where(x => !x.IsCatchAll()))
            {
                var c = new Catch {
                    Type = catchBlock.ExceptionType.GetReference(targetPackage)
                };
                handler.Catches.Add(c);
                var catchStart = this.Add(catchBlock.SourceLocation, RCode.Nop);
                catchBlock.Accept(this, node);
                c.Instruction = catchStart;

                TryCatchGotoEnd(finState, last);
            }

            // Emit "catch all" (if any)
            var catchAllBlock = node.CatchBlocks.SingleOrDefault(x => x.IsCatchAll());

            if (catchAllBlock != null)
            {
                var catchStart = this.Add(catchAllBlock.SourceLocation, RCode.Nop);
                catchAllBlock.Accept(this, node);
                handler.CatchAll = catchStart;

                TryCatchGotoEnd(finState, last);
            }

            var catchesEnd = this.Add(AstNode.NoSource, RCode.Nop);

            // clear try/catch/finally stack: we don't want to cover ourselves!
            tryCatchStack.Pop();

            // Emit finally code
            if (node.FinallyBlock != null)
            {
                // preparation.
                var finallyStart = this.Add(node.FinallyBlock.SourceLocation, RCode.Move_exception,
                                            finState.FinallyExceptionRegister);
                instructions.Add(finState.NonException);

                // the original handler
                node.FinallyBlock.Accept(this, node);

                // prepare the routing
                this.Add(AstNode.NoSource, RCode.If_eqz, finState.AfterExceptionCheck, finState.FinallyExceptionRegister);
                this.Add(AstNode.NoSource, RCode.Throw, finState.FinallyExceptionRegister);
                instructions.Add(finState.AfterExceptionCheck);

                // Set up exception handlers.
                if (catchAllBlock == null)
                {
                    // we need to cover the try block.
                    handler.CatchAll = finallyStart;
                }

                if (node.CatchBlocks.Any())
                {
                    // we need to cover the catch blocks
                    var finallyHandler = new ExceptionHandler
                    {
                        TryStart = catchesStart,
                        TryEnd   = catchesEnd,
                        CatchAll = finallyStart
                    };
                    body.Exceptions.Add(finallyHandler);
                }
            }

            // Add end
            instructions.Add(last);

            // Record catch/catch-all handler
            if ((handler.CatchAll != null) || handler.Catches.Any())
            {
                body.Exceptions.Add(handler);
            }

            return(new RLRange(first, last, null));
        }
コード例 #7
0
 public FinallyBlockState(FinallyBlockState outerBlock, int depth, AstCompilerVisitor compiler, Instruction first, Instruction last)
 {
     _compiler = compiler;
     NonException = new Instruction();
     AfterExceptionCheck = new Instruction();
     FirstInstruction = first;
     LastInstruction = last;
     Depth = depth;
     OuterFinallyBlock = outerBlock;
 }
コード例 #8
0
 public FinallyBlockState(FinallyBlockState outerBlock, int depth)
 {
     Depth = depth;
     OuterFinallyBlock = outerBlock;
 }
コード例 #9
0
        private void TryCatchSetTargetRegister(FinallyBlockState finallyBlock, bool needTargetRegister)
        {
            var localTargets = finallyBlock.Targets.Where(t => t.State == finallyBlock);

            if (needTargetRegister)
            {
                finallyBlock.TargetRegister = Frame.AllocateTemp(PrimitiveType.Int);
                var setToZero = new Instruction(RCode.Const, 0, new []{ finallyBlock.TargetRegister});
                instructions.Insert(finallyBlock.FirstInstruction.Index, setToZero);
                
                foreach (var t in localTargets)
                {
                    if (t.SetTarget.Code != RCode.Nop)
                        t.SetTarget.Registers.Add(finallyBlock.TargetRegister);
                }
            }
            else
            {
                foreach (var t in localTargets)
                    t.SetTarget.ConvertToNop();
            }
        }
コード例 #10
0
        /// <summary>
        /// return the first emitted instruction
        /// </summary>
        private Instruction TryCatchEmitTargetInstruction(FinallyTarget target, ref int insIdx, FinallyBlockState outerFinallyBlock)
        {
            bool emitReturn = outerFinallyBlock == null && target.IsReturn;

            bool chainToOuterBlock = outerFinallyBlock != null && target.IsReturn;

            if (target.IsLeave && outerFinallyBlock != null)
            {
                // check if the leave leaves the outer finally block as well.
                if (target.Destination.Index < outerFinallyBlock.FirstInstruction.Index
                 || target.Destination.Index > outerFinallyBlock.LastInstruction.Index)
                {
                    chainToOuterBlock = true;
                }
            }

            if (emitReturn)
            {
                Instruction ret;
                if (currentMethod.ReturnsVoid)
                {
                    ret = new Instruction(RCode.Return_void);
                }
                else
                {
                    var retCode = currentMethod.ReturnsDexWide
                        ? RCode.Return_wide
                        : currentMethod.ReturnsDexValue
                            ? RCode.Return
                            : RCode.Return_object;
                    ret = new Instruction(retCode, finallyState.ReturnValueRegister);
                }
                instructions.Insert(insIdx++, ret);
                return ret;
            }
            else if (chainToOuterBlock)
            {
                Debug.Assert(outerFinallyBlock != null);
                int id = target.SetTarget.Code == RCode.Nop ? 0 : (int)target.SetTarget.Operand;

                RLRange range;
                if (target.IsReturn)
                    range = outerFinallyBlock.BranchToFinally_Ret(ref insIdx);
                else // IsLeave
                    range = outerFinallyBlock.BranchToFinally_Leave(target.Destination, ref insIdx);

                // This is a little bit hackish. We need to set the operand in the setTarget instruction.
                if (id == 0) range.First.ConvertToNop();
                else range.First.Operand = id;

                return range.First;
            }
            else
            {
                // goto
                var insGoto = new Instruction(RCode.Goto, target.Destination);
                instructions.Insert(insIdx++, insGoto);
                return insGoto;
            }
        }
コード例 #11
0
        /// <summary>
        /// Create try/catch/finally/fault block
        /// </summary>
        public override RLRange Visit(AstTryCatchBlock node, AstNode parent)
        {
            var handler = new ExceptionHandler();

            //if (node.FaultBlock != null)
            //{
            //    Debugger.Break();
            //}

            // Setup instruction before/after my node.
            var first = new Instruction() { SequencePoint = node.SourceLocation};
            var last = new Instruction(RCode.Nop);

            FinallyBlockState finState = null;
            FinallyBlockState outerFinState = tryCatchStack.FirstOrDefault(f => f.HasFinally);

            if (tryCatchStack.Count == 0)
                finallyState.FinallyStacks.Add(new List<FinallyBlockState>());

            if (node.FinallyBlock != null)
            {
                // store finaly state
                finState = new FinallyBlockState(outerFinState, tryCatchStack.Count, this, first, last);

                finState.FinallyExceptionRegister = frame.AllocateTemp(new ClassReference("java.lang.Throwable")).Register;
                // clear the variable to make sure it isn't stale from a previous loop.
                // make sure this is outside the try block for edge case exceptions.
                this.Add(node.SourceLocation, RCode.Const, 0, finState.FinallyExceptionRegister);

                tryCatchStack.Push(finState);
                finallyState.FinallyStacks.Last().Add(finState);
            }
            else
            {
                finState = new FinallyBlockState(outerFinState, tryCatchStack.Count);
                tryCatchStack.Push(finState);
            }

            instructions.Add(first);
            // Emit try block
            handler.TryStart = first;
            node.TryBlock.AcceptOrDefault(this, node);
            handler.TryEnd = TryCatchGotoEnd(finState, last);

            var catchesStart = this.Add(AstNode.NoSource, RCode.Nop);

            // Emit "normal" catch blocks
            foreach (var catchBlock in node.CatchBlocks.Where(x => !x.IsCatchAll()))
            {
                var c = new Catch { Type = catchBlock.ExceptionType.GetReference(targetPackage) };
                handler.Catches.Add(c);
                var catchStart = this.Add(catchBlock.SourceLocation, RCode.Nop);
                catchBlock.Accept(this, node);
                c.Instruction = catchStart;

                TryCatchGotoEnd(finState, last);
            }

            // Emit "catch all" (if any)
            var catchAllBlock = node.CatchBlocks.SingleOrDefault(x => x.IsCatchAll());
            if (catchAllBlock != null)
            {
                var catchStart = this.Add(catchAllBlock.SourceLocation, RCode.Nop);
                catchAllBlock.Accept(this, node);
                handler.CatchAll = catchStart;

                TryCatchGotoEnd(finState, last);
            }

            var catchesEnd = this.Add(AstNode.NoSource, RCode.Nop);

            // clear try/catch/finally stack: we don't want to cover ourselves!
            tryCatchStack.Pop();

            // Emit finally code
            if (node.FinallyBlock != null)
            {
                // preparation.
                var finallyStart = this.Add(node.FinallyBlock.SourceLocation, RCode.Move_exception,
                                            finState.FinallyExceptionRegister);
                instructions.Add(finState.NonException);

                // the original handler
                node.FinallyBlock.Accept(this, node);

                // prepare the routing
                this.Add(AstNode.NoSource, RCode.If_eqz, finState.AfterExceptionCheck, finState.FinallyExceptionRegister);
                this.Add(AstNode.NoSource, RCode.Throw, finState.FinallyExceptionRegister);
                instructions.Add(finState.AfterExceptionCheck);

                // Set up exception handlers.
                if (catchAllBlock == null)
                {
                    // we need to cover the try block.
                    handler.CatchAll = finallyStart;
                }

                if (node.CatchBlocks.Any())
                {
                    // we need to cover the catch blocks
                    var finallyHandler = new ExceptionHandler
                    {
                        TryStart = catchesStart,
                        TryEnd = catchesEnd,
                        CatchAll = finallyStart
                    };
                    body.Exceptions.Add(finallyHandler);
                }
            }

            // Add end
            instructions.Add(last);

            // Record catch/catch-all handler
            if ((handler.CatchAll != null) || handler.Catches.Any())
            {
                body.Exceptions.Add(handler);
            }

            return new RLRange(first, last, null);
        }
コード例 #12
0
        private Instruction TryCatchGotoEnd(FinallyBlockState state, Instruction last)
        {
            if (state.HasFinally)
            {
                var rlrange = state.BranchToFinally_FallOut(AstNode.NoSource, last, new List<RLRange>());
                return rlrange.Last;
            }

            // goto end 
            return this.Add(AstNode.NoSource, RCode.Goto, last);    
        }