private RLRange BranchToFinally(FinallyTarget target, IEnumerable <RLRange> prefix, ISourceLocation seqp, ref int insIdx)
            {
                Debug.Assert(this.HasFinally);

                Targets.Add(target);

                var setTarget = new Instruction(RCode.Const)
                {
                    SequencePoint = seqp
                };                                                                     // operand and register are set later

                _compiler.instructions.Insert(insIdx++, setTarget);
                var branch = new Instruction(RCode.Goto, NonException)
                {
                    SequencePoint = seqp
                };

                _compiler.instructions.Insert(insIdx++, branch);

                target.SetTarget   = setTarget;
                target.GotoFinally = branch;
                target.State       = this;

                return(new RLRange(prefix, setTarget, branch, null));
            }
            public RLRange BranchToFinally_Leave(Instruction insTarget, ref int insIdx)
            {
                var target = new FinallyTarget {
                    IsLeave = true, Destination = insTarget
                };

                return(BranchToFinally(target, null, AstNode.NoSource, ref insIdx));
            }
            public RLRange BranchToFinally_Ret(ref int insIdx)
            {
                var target = new FinallyTarget {
                    IsReturn = true
                };

                return(BranchToFinally(target, null, AstNode.NoSource, ref insIdx));
            }
            public RLRange BranchToFinally_Ret(ISourceLocation sourceLocation, List <RLRange> args)
            {
                int insIdx = _compiler.instructions.Count;
                var target = new FinallyTarget {
                    IsReturn = true
                };

                return(BranchToFinally(target, args, sourceLocation, ref insIdx));
            }
            public RLRange BranchToFinally_FallOut(ISourceLocation sourceLocation, Instruction insTarget, List <RLRange> args)
            {
                int insIdx = _compiler.instructions.Count;
                var target = new FinallyTarget {
                    Destination = insTarget, IsFallOut = true
                };

                return(BranchToFinally(target, args, sourceLocation, ref insIdx));
            }
            public RLRange BranchToFinally_Leave(ISourceLocation sourceLocation, AstLabel labelTarget, List <RLRange> args)
            {
                int insIdx = _compiler.instructions.Count;
                var target = new FinallyTarget {
                    IsLeave = true
                };

                _compiler.labelManager.AddResolveAction(labelTarget, ins => target.Destination = ins);
                return(BranchToFinally(target, args, sourceLocation, ref insIdx));
            }
 protected bool Equals(FinallyTarget other)
 {
     return((IsReturn && other.IsReturn) ||
            (IsFallOut && other.IsFallOut) ||
            Equals(Destination, other.Destination));
 }
 protected bool Equals(FinallyTarget other)
 {
     return (IsReturn && other.IsReturn)
         || (IsFallOut && other.IsFallOut)
         || Equals(Destination, other.Destination);
 }
        /// <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);
            }
        }
 public RLRange BranchToFinally_Ret(ref int insIdx)
 {
     var target = new FinallyTarget { IsReturn = true };
     return BranchToFinally(target, null, AstNode.NoSource, ref insIdx);
 }
 public RLRange BranchToFinally_Leave(Instruction insTarget, ref int insIdx)
 {
     var target = new FinallyTarget { IsLeave = true, Destination = insTarget};
     return BranchToFinally(target, null, AstNode.NoSource, ref insIdx);
 }
 public RLRange BranchToFinally_Ret(ISourceLocation sourceLocation, List<RLRange> args)
 {
     int insIdx = _compiler.instructions.Count;
     var target = new FinallyTarget {IsReturn = true};
     return BranchToFinally(target, args, sourceLocation, ref insIdx);
 }
 public RLRange BranchToFinally_FallOut(ISourceLocation sourceLocation, Instruction insTarget, List<RLRange> args)
 {
     int insIdx = _compiler.instructions.Count;
     var target = new FinallyTarget {Destination = insTarget, IsFallOut = true};
     return BranchToFinally(target, args, sourceLocation, ref insIdx);
 }
 public RLRange BranchToFinally_Leave(ISourceLocation sourceLocation, AstLabel labelTarget, List<RLRange> args)
 {
     int insIdx = _compiler.instructions.Count;
     var target = new FinallyTarget {IsLeave = true };
     _compiler.labelManager.AddResolveAction(labelTarget, ins=> target.Destination = ins);
     return BranchToFinally(target, args, sourceLocation, ref insIdx);
 }
            private RLRange BranchToFinally(FinallyTarget target, IEnumerable<RLRange> prefix, ISourceLocation seqp, ref int insIdx)
            {
                Debug.Assert(this.HasFinally);

                Targets.Add(target);

                var setTarget = new Instruction(RCode.Const) { SequencePoint = seqp }; // operand and register are set later
                _compiler.instructions.Insert(insIdx++, setTarget); 
                var branch = new Instruction(RCode.Goto, NonException) {SequencePoint = seqp};
                _compiler.instructions.Insert(insIdx++, branch);

                target.SetTarget = setTarget;
                target.GotoFinally = branch;
                target.State = this;

                return new RLRange(prefix, setTarget, branch, null);
            }
        /// <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;
            }
        }