/// <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); } }
/// <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; } }