📄 codeattrinfoeditor.java
字号:
/* $Id: CodeAttrInfoEditor.java,v 1.9 2004/10/10 20:56:58 eric Exp $ * * ProGuard -- shrinking, optimization, and obfuscation of Java class files. * * Copyright (c) 2002-2004 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package proguard.classfile.editor;import proguard.classfile.*;import proguard.classfile.attribute.*;import proguard.classfile.attribute.annotation.*;import proguard.classfile.instruction.*;import proguard.classfile.visitor.*;/** * This AttrInfoVisitor accumulates specified changes to code, and then applies * these accumulated changes to the code attributes that it visits. * * @author Eric Lafortune */public class CodeAttrInfoEditor implements AttrInfoVisitor, InstructionVisitor, ExceptionInfoVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor{ private int codeLength; private boolean modified; /*private*/public Instruction[] preInsertions; /*private*/public Instruction[] postInsertions; private boolean[] deleted; private int[] instructionOffsetMap; private StackSizeUpdater stackSizeUpdater; /** * Creates a new CodeAttrInfoEditor. * @param codeLength an estimate of the maximum length of all the code that * will be edited. */ public CodeAttrInfoEditor(int codeLength) { this.codeLength = codeLength; preInsertions = new Instruction[codeLength]; postInsertions = new Instruction[codeLength]; deleted = new boolean[codeLength]; stackSizeUpdater = new StackSizeUpdater(codeLength); } /** * Resets the accumulated code changes. * @param codeLength the length of the code that will be edited next. */ public void reset(int codeLength) { this.codeLength = codeLength; // Try to reuse the previous arrays. if (preInsertions.length < codeLength) { preInsertions = new Instruction[codeLength]; postInsertions = new Instruction[codeLength]; deleted = new boolean[codeLength]; } else { for (int index = 0; index < codeLength; index++) { preInsertions[index] = null; postInsertions[index] = null; deleted[index] = false; } } modified = false; } /** * Remembers to replace the instruction at the given offset by the given * instruction. * @param instructionOffset the offset of the instruction to be replaced. * @param instruction the new instruction. */ public void replaceInstruction(int instructionOffset, Instruction instruction) { deleteInstruction(instructionOffset); insertBeforeInstruction(instructionOffset, instruction); } /** * Remembers to replace the instruction at the given offset by the given * instruction. * @param instructionOffset the offset of the instruction to be replaced. * @param instruction the new instruction. */ public void replaceInstruction2(int instructionOffset, Instruction instruction) { deleteInstruction(instructionOffset); insertAfterInstruction(instructionOffset, instruction); } /** * Remembers to place the given instruction right before the instruction * at the given offset. * @param instructionOffset the offset of the instruction. * @param instruction the new instruction. */ public void insertBeforeInstruction(int instructionOffset, Instruction instruction) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } preInsertions[instructionOffset] = instruction; modified = true; } /** * Remembers to place the given instruction right after the instruction * at the given offset. * @param instructionOffset the offset of the instruction. * @param instruction the new instruction. */ public void insertAfterInstruction(int instructionOffset, Instruction instruction) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } postInsertions[instructionOffset] = instruction; modified = true; } /** * Remembers to delete the instruction at the given offset. * @param instructionOffset the offset of the instruction to be deleted. */ public void deleteInstruction(int instructionOffset) { if (instructionOffset < 0 || instructionOffset >= codeLength) { throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]"); } deleted[instructionOffset] = true; modified = true; } /** * Returns whether the instruction at the given offset has been modified * in any way. */ public boolean isModified(int instructionOffset) { return preInsertions[instructionOffset] != null || postInsertions[instructionOffset] != null || deleted[instructionOffset]; } /** * Returns whether any instruction has been modified in any way. */ public boolean isModified() { return modified; } // Implementations for AttrInfoVisitor. public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {} public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {} public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {} public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {} public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {} public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {} public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {} public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {} public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {} public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {} public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {} public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {} public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {} public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {} public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {} public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) { // Avoid doing any work if nothing is changing anyway. if (!modified) { return; } // Move and remap the instructions. codeAttrInfo.u4codeLength = moveInstructions(classFile, methodInfo, codeAttrInfo); // Remap the exception table. codeAttrInfo.exceptionsAccept(classFile, methodInfo, this); // Remap the line number table and the local variable table. codeAttrInfo.attributesAccept(classFile, methodInfo, this); // Remove exceptions with empty code blocks. codeAttrInfo.u2exceptionTableLength = removeEmptyExceptions(codeAttrInfo.exceptionTable, codeAttrInfo.u2exceptionTableLength); // Update maximum stack size. stackSizeUpdater.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo); } // Implementations for LineNumberInfoVisitor. public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) { // Remap all line number table entries. lineNumberTableAttrInfo.lineNumbersAccept(classFile, methodInfo, codeAttrInfo, this); // Remove line numbers with empty code blocks. lineNumberTableAttrInfo.u2lineNumberTableLength = removeEmptyLineNumbers(lineNumberTableAttrInfo.lineNumberTable, lineNumberTableAttrInfo.u2lineNumberTableLength, codeAttrInfo.u4codeLength); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) { // Remap all local variable table entries. localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this); // Remove local variables with empty code blocks. localVariableTableAttrInfo.u2localVariableTableLength = removeEmptyLocalVariables(localVariableTableAttrInfo.localVariableTable, localVariableTableAttrInfo.u2localVariableTableLength); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) { // Remap all local variable table entries. localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this); // Remove local variables with empty code blocks. localVariableTypeTableAttrInfo.u2localVariableTypeTableLength = removeEmptyLocalVariableTypes(localVariableTypeTableAttrInfo.localVariableTypeTable, localVariableTypeTableAttrInfo.u2localVariableTypeTableLength); } // Implementations for InstructionVisitor. public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {} public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {} public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {} public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) { // Adjust the branch offset. branchInstruction.branchOffset = remapBranchOffset(offset, branchInstruction.branchOffset); } public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) { // Adjust the default jump offset. tableSwitchInstruction.defaultOffset = remapBranchOffset(offset, tableSwitchInstruction.defaultOffset); // Adjust the jump offsets. remapJumpOffsets(offset, tableSwitchInstruction.jumpOffsets, tableSwitchInstruction.highCase - tableSwitchInstruction.lowCase + 1); } public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { // Adjust the default jump offset. lookUpSwitchInstruction.defaultOffset = remapBranchOffset(offset, lookUpSwitchInstruction.defaultOffset); // Adjust the jump offsets. remapJumpOffsets(offset, lookUpSwitchInstruction.jumpOffsets, lookUpSwitchInstruction.jumpOffsetCount);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -