📄 branchtargetfinder.java
字号:
codeAttribute.instructionsAccept(clazz, method, this); // Mark branch targets in the exception table. codeAttribute.exceptionsAccept(clazz, method, this); // Fill out the subroutine flags and ends, working backward. boolean isSubroutine = false; boolean isSubroutineReturning = false; int subroutineEnd = codeLength; for (int index = codeLength - 1; index >= 0; index--) { if (isInstruction(index)) { // Did we hit a marked subroutine instruction? if (isSubroutine(index)) { // Remember that we're inside a subroutine. isSubroutine = true; // Remember if the subroutine is returning. if (isSubroutineReturning(index)) { isSubroutineReturning = true; } // Have we reached the start of the subroutine? if (isSubroutineStart(index)) { // Mark all subroutine instructions. int flags = isSubroutineReturning ? SUBROUTINE | SUBROUTINE_RETURNING : SUBROUTINE; for (int subroutineIndex = index; subroutineIndex < subroutineEnd; subroutineIndex++) { if (isInstruction(subroutineIndex)) { // Set the subroutine flags. instructionMarks[subroutineIndex] |= flags; // Fill out the subroutine start and end. subroutineStarts[subroutineIndex] = index; subroutineEnds[subroutineIndex] = subroutineEnd; } } // Reset the subroutine flags. isSubroutine = false; isSubroutineReturning = false; } } // Are we not inside a subroutine? if (!isSubroutine) { // Reset the potential subroutine end. subroutineEnd = index; } } } // Fill out the unreachable flags. boolean unreachable = false; for (int index = 0; index < codeLength; index++) { if (isInstruction(index)) { // Should we stop or start marking unreachable code? if (isBranchTarget(index) || isExceptionHandler(index)) { unreachable = false; } else if (isAfterBranch(index)) { unreachable = true; } if (unreachable) { // Set the unreachable flag. instructionMarks[index] |= UNREACHABLE; } } } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; // Check if this is the first instruction of a subroutine. checkSubroutineStart(offset); byte opcode = simpleInstruction.opcode; if (opcode == InstructionConstants.OP_IRETURN || opcode == InstructionConstants.OP_LRETURN || opcode == InstructionConstants.OP_FRETURN || opcode == InstructionConstants.OP_DRETURN || opcode == InstructionConstants.OP_ARETURN || opcode == InstructionConstants.OP_ATHROW) { // Mark the branch origin. markBranchOrigin(offset); // Mark the next instruction. markAfterBranchOrigin(offset + simpleInstruction.length(offset)); } } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; // Check if this is the first instruction of a subroutine. checkSubroutineStart(offset); // Check if the instruction is a 'new' instruction. if (constantInstruction.opcode == InstructionConstants.OP_NEW) { // Push the 'new' instruction offset on the stack. recentCreationOffsets[recentCreationOffsetIndex++] = offset; } else { // Check if the instruction is an initializer invocation. isInitializer = false; clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); if (isInitializer) { // Pop the 'new' instruction offset from the stack. int recentCreationOffset = recentCreationOffsets[--recentCreationOffsetIndex]; // Fill it out in the creation offsets. creationOffsets[offset] = recentCreationOffset; // Fill out the initialization offsets. if (recentCreationOffset == AT_METHOD_ENTRY) { superInitializationOffset = offset; } else { initializationOffsets[recentCreationOffset] = offset; } } } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Mark the instruction. instructionMarks[offset] |= INSTRUCTION; // Check if this is the first instruction of a subroutine. checkSubroutineStart(offset); if (variableInstruction.opcode == InstructionConstants.OP_RET) { // Mark the branch origin. markBranchOrigin(offset); // Mark the regular subroutine return. instructionMarks[offset] |= SUBROUTINE | SUBROUTINE_RETURNING; // Mark the next instruction. markAfterBranchOrigin(offset + variableInstruction.length(offset)); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { // Mark the branch origin. markBranchOrigin(offset); // Check if this is the first instruction of a subroutine. checkSubroutineStart(offset); // Mark the branch target. markBranchTarget(offset + branchInstruction.branchOffset); byte opcode = branchInstruction.opcode; if (opcode == InstructionConstants.OP_JSR || opcode == InstructionConstants.OP_JSR_W) { // Mark the subroutine invocation. instructionMarks[offset] |= SUBROUTINE_INVOCATION; // Mark the subroutine start. instructionMarks[offset + branchInstruction.branchOffset] |= SUBROUTINE | SUBROUTINE_START; } else if (opcode == InstructionConstants.OP_GOTO || opcode == InstructionConstants.OP_GOTO_W) { // Mark the next instruction. markAfterBranchOrigin(offset + branchInstruction.length(offset)); } } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { // Mark the branch origin. markBranchOrigin(offset); // Check if this is the first instruction of a subroutine. checkSubroutineStart(offset); // Mark the branch targets of the default jump offset. markBranchTarget(offset + tableSwitchInstruction.defaultOffset); // Mark the branch targets of the jump offsets. markBranchTargets(offset, tableSwitchInstruction.jumpOffsets, tableSwitchInstruction.highCase - tableSwitchInstruction.lowCase + 1); // Mark the next instruction. markAfterBranchOrigin(offset + tableSwitchInstruction.length(offset)); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { // Mark the branch origin. markBranchOrigin(offset); // Check if this is the first instruction of a subroutine. checkSubroutineStart(offset); // Mark the branch targets of the default jump offset. markBranchTarget(offset + lookUpSwitchInstruction.defaultOffset); // Mark the branch targets of the jump offsets. markBranchTargets(offset, lookUpSwitchInstruction.jumpOffsets, lookUpSwitchInstruction.jumpOffsetCount); // Mark the next instruction. markAfterBranchOrigin(offset + lookUpSwitchInstruction.length(offset)); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { isInitializer = methodrefConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); } // Implementations for ExceptionInfoVisitor. public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) { // Remap the code offsets. Note that the branch target array also has // an entry for the first offset after the code, for u2endPC. instructionMarks[exceptionInfo.u2startPC] |= EXCEPTION_START; instructionMarks[exceptionInfo.u2endPC] |= EXCEPTION_END; instructionMarks[exceptionInfo.u2handlerPC] |= EXCEPTION_HANDLER; } // Small utility methods. /** * Marks the branch targets of the given jump offsets for the instruction * at the given offset. */ private void markBranchTargets(int offset, int[] jumpOffsets, int length) { for (int index = 0; index < length; index++) { markBranchTarget(offset + jumpOffsets[index]); } } /** * Marks the branch origin at the given offset. */ private void markBranchOrigin(int offset) { instructionMarks[offset] |= INSTRUCTION | BRANCH_ORIGIN; // Remember the minimum offset of the end of the current subroutine. if (minimumSubroutineEnd < offset) { minimumSubroutineEnd = offset; instructionMarks[offset] |= SUBROUTINE; } } /** * Marks the branch target at the given offset. */ private void markBranchTarget(int offset) { instructionMarks[offset] |= BRANCH_TARGET; // Remember the minimum offset of the end of the current subroutine. if (minimumSubroutineEnd < offset) { minimumSubroutineEnd = offset; instructionMarks[offset] |= SUBROUTINE; } } /** * Marks the instruction at the given offset, after a branch. */ private void markAfterBranchOrigin(int nextOffset) { instructionMarks[nextOffset] |= AFTER_BRANCH; // Check if this is a backward branch that marks the end of a subroutine. if (minimumSubroutineEnd < nextOffset && !isSubroutine(nextOffset)) { minimumSubroutineEnd = Integer.MAX_VALUE; } } /** * Checks if the specified instruction is a subroutine end. */ private void checkSubroutineStart(int offset) { // Start looking for a subroutine end if this is a subroutine start. if (isSubroutineStart(offset)) { minimumSubroutineEnd = offset; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -