📄 codeattributeeditor.java
字号:
// Remove local variables with empty code blocks. localVariableTypeTableAttribute.u2localVariableTypeTableLength = removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, localVariableTypeTableAttribute.u2localVariableTypeTableLength, codeAttribute.u2maxLocals); } /** * Checks if it is possible to modifies the given code without having to * update any offsets. * @param codeAttribute the code to be changed. * @return the new code length. */ private boolean canPerformSimpleReplacements(CodeAttribute codeAttribute) { if (!simple) { return false; } byte[] code = codeAttribute.code; int codeLength = codeAttribute.u4codeLength; // Go over all replacement instructions. for (int offset = 0; offset < codeLength; offset++) { // Check if the replacement instruction, if any, has a different // length than the original instruction. Instruction replacementInstruction = replacements[offset]; if (replacementInstruction != null && replacementInstruction.length(offset) != InstructionFactory.create(code, offset).length(offset)) { return false; } } return true; } /** * Modifies the given code without updating any offsets. * @param codeAttribute the code to be changed. */ private void performSimpleReplacements(CodeAttribute codeAttribute) { int codeLength = codeAttribute.u4codeLength; // Go over all replacement instructions. for (int offset = 0; offset < codeLength; offset++) { // Overwrite the original instruction with the replacement // instruction if any. Instruction replacementInstruction = replacements[offset]; if (replacementInstruction != null) { replacementInstruction.write(codeAttribute, offset); } } } /** * Modifies the given code based on the previously specified changes. * @param clazz the class file of the code to be changed. * @param method the method of the code to be changed. * @param codeAttribute the code to be changed. * @return the new code length. */ private int updateInstructions(Clazz clazz, Method method, CodeAttribute codeAttribute) { byte[] oldCode = codeAttribute.code; int oldLength = codeAttribute.u4codeLength; // Make sure there is a sufficiently large instruction offset map. if (instructionOffsetMap == null || instructionOffsetMap.length < oldLength + 1) { instructionOffsetMap = new int[oldLength + 1]; } // Fill out the instruction offset map. int newLength = mapInstructions(oldCode, oldLength); // Create a new code array if necessary. if (lengthIncreased) { codeAttribute.code = new byte[newLength]; } // Prepare for possible widening of instructions. instructionWriter.reset(newLength); // Move the instructions into the new code array. moveInstructions(clazz, method, codeAttribute, oldCode, oldLength); // We can return the new length. return newLength; } /** * Fills out the instruction offset map for the given code block. * @param oldCode the instructions to be moved. * @param oldLength the code length. * @return the new code length. */ private int mapInstructions(byte[] oldCode, int oldLength) { // Start mapping instructions at the beginning. newOffset = 0; lengthIncreased = false; int oldOffset = 0; do { // Get the next instruction. Instruction instruction = InstructionFactory.create(oldCode, oldOffset); // Compute the mapping of the instruction. mapInstruction(oldOffset, instruction); oldOffset += instruction.length(oldOffset); if (newOffset > oldOffset) { lengthIncreased = true; } } while (oldOffset < oldLength); // Also add an entry for the first offset after the code. instructionOffsetMap[oldOffset] = newOffset; return newOffset; } /** * Fills out the instruction offset map for the given instruction. * @param oldOffset the instruction's old offset. * @param instruction the instruction to be moved. */ private void mapInstruction(int oldOffset, Instruction instruction) { instructionOffsetMap[oldOffset] = newOffset; // Account for the pre-inserted instruction, if any. Instruction preInstruction = preInsertions[oldOffset]; if (preInstruction != null) { newOffset += preInstruction.length(newOffset); } // Account for the replacement instruction, or for the current // instruction, if it shouldn't be deleted. Instruction replacementInstruction = replacements[oldOffset]; if (replacementInstruction != null) { newOffset += replacementInstruction.length(newOffset); } else if (!deleted[oldOffset]) { // Note that the instruction's length may change at its new offset, // e.g. if it is a switch instruction. newOffset += instruction.length(newOffset); } // Account for the post-inserted instruction, if any. Instruction postInstruction = postInsertions[oldOffset]; if (postInstruction != null) { newOffset += postInstruction.length(newOffset); } } /** * Moves the given code block to the new offsets. * @param clazz the class file of the code to be changed. * @param method the method of the code to be changed. * @param codeAttribute the code to be changed. * @param oldCode the original code to be moved. * @param oldLength the original code length. */ private void moveInstructions(Clazz clazz, Method method, CodeAttribute codeAttribute, byte[] oldCode, int oldLength) { // Start writing instructions at the beginning. newOffset = 0; int oldOffset = 0; do { // Get the next instruction. Instruction instruction = InstructionFactory.create(oldCode, oldOffset); // Move the instruction to its new offset. moveInstruction(clazz, method, codeAttribute, oldOffset, instruction); oldOffset += instruction.length(oldOffset); } while (oldOffset < oldLength); } /** * Moves the given instruction to its new offset. * @param clazz the class file of the code to be changed. * @param method the method of the code to be changed. * @param codeAttribute the code to be changed. * @param oldOffset the original instruction offset. * @param instruction the original instruction. */ private void moveInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int oldOffset, Instruction instruction) { // Remap and insert the pre-inserted instruction, if any. Instruction preInstruction = preInsertions[oldOffset]; if (preInstruction != null) { // Remap the instruction. preInstruction.accept(clazz, method, codeAttribute, oldOffset, this); newOffset += preInstruction.length(newOffset); } // Remap and insert the replacement instruction, or the current // instruction, if it shouldn't be deleted. Instruction replacementInstruction = replacements[oldOffset]; if (replacementInstruction != null) { // Remap the instruction. replacementInstruction.accept(clazz, method, codeAttribute, oldOffset, this); newOffset += replacementInstruction.length(newOffset); } else if (!deleted[oldOffset]) { // Remap the instruction. instruction.accept(clazz, method, codeAttribute, oldOffset, this); newOffset += instruction.length(newOffset); } // Remap and insert the post-inserted instruction, if any. Instruction postInstruction = postInsertions[oldOffset]; if (postInstruction != null) { // Remap the instruction. postInstruction.accept(clazz, method, codeAttribute, oldOffset, this); newOffset += postInstruction.length(newOffset); } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Write out the instruction. instructionWriter.visitSimpleInstruction(clazz, method, codeAttribute, newOffset, simpleInstruction); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { // Write out the instruction. instructionWriter.visitConstantInstruction(clazz, method, codeAttribute, newOffset, constantInstruction); } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { // Write out the instruction. instructionWriter.visitVariableInstruction(clazz, method, codeAttribute,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -