📄 instructionwriter.java
字号:
/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu) * * This library 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 library 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; 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.instruction.*;import proguard.classfile.instruction.visitor.InstructionVisitor;import proguard.classfile.attribute.visitor.AttributeVisitor;import proguard.classfile.attribute.CodeAttribute;import proguard.classfile.*;import proguard.classfile.util.SimplifiedVisitor;/** * This InstructionVisitor writes out the instructions that it visits, * collecting instructions that have to be widened. As an AttributeVisitor, * it then applies the collected changes. The process will be repeated * recursively, if necessary. * * @author Eric Lafortune */public class InstructionWriterextends SimplifiedVisitorimplements InstructionVisitor, AttributeVisitor{ private int codeLength; private CodeAttributeEditor codeAttributeEditor; /** * 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; // The code attribute editor has to be created lazily. if (codeAttributeEditor != null) { codeAttributeEditor.reset(codeLength); } } // Implementations for InstructionVisitor. public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) { // Try to write out the instruction. // Simple instructions should always fit. simpleInstruction.write(codeAttribute, offset); } public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { try { // Try to write out the instruction. constantInstruction.write(codeAttribute, offset); } catch (IllegalArgumentException exception) { // Create a new constant instruction that will fit. Instruction replacementInstruction = new ConstantInstruction().copy(constantInstruction).shrink(); replaceInstruction(offset, replacementInstruction); // Write out a dummy constant instruction for now. constantInstruction.constantIndex = 0; constantInstruction.constant = 0; constantInstruction.write(codeAttribute, offset); } } public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) { try { // Try to write out the instruction. variableInstruction.write(codeAttribute, offset); } catch (IllegalArgumentException exception) { // Create a new variable instruction that will fit. Instruction replacementInstruction = new VariableInstruction(variableInstruction.opcode, variableInstruction.variableIndex, variableInstruction.constant); replaceInstruction(offset, replacementInstruction); // Write out a dummy variable instruction for now. variableInstruction.variableIndex = 0; variableInstruction.constant = 0; variableInstruction.write(codeAttribute, offset); } } public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) { try { // Try to write out the instruction. branchInstruction.write(codeAttribute, offset); } catch (IllegalArgumentException exception) { // Create a new unconditional branch that will fit. Instruction replacementInstruction = new BranchInstruction(InstructionConstants.OP_GOTO_W, branchInstruction.branchOffset); // Create a new instruction that will fit. switch (branchInstruction.opcode) { default: { // Create a new branch instruction that will fit. replacementInstruction = new BranchInstruction().copy(branchInstruction).shrink(); break; } // Some special cases, for which a wide branch doesn't exist. case InstructionConstants.OP_IFEQ: case InstructionConstants.OP_IFNE: case InstructionConstants.OP_IFLT: case InstructionConstants.OP_IFGE: case InstructionConstants.OP_IFGT: case InstructionConstants.OP_IFLE: case InstructionConstants.OP_IFICMPEQ: case InstructionConstants.OP_IFICMPNE: case InstructionConstants.OP_IFICMPLT: case InstructionConstants.OP_IFICMPGE: case InstructionConstants.OP_IFICMPGT: case InstructionConstants.OP_IFICMPLE: case InstructionConstants.OP_IFACMPEQ: case InstructionConstants.OP_IFACMPNE: { // Insert the complementary conditional branch. Instruction complementaryConditionalBranch = new BranchInstruction((byte)(((branchInstruction.opcode+1) ^ 1) - 1), (1+2) + (1+4)); insertBeforeInstruction(offset, complementaryConditionalBranch); // Create a new unconditional branch that will fit. break; } case InstructionConstants.OP_IFNULL: case InstructionConstants.OP_IFNONNULL: { // Insert the complementary conditional branch. Instruction complementaryConditionalBranch = new BranchInstruction((byte)(branchInstruction.opcode ^ 1), (1+2) + (1+4)); insertBeforeInstruction(offset, complementaryConditionalBranch); // Create a new unconditional branch that will fit. break; } } replaceInstruction(offset, replacementInstruction); // Write out a dummy branch instruction for now. branchInstruction.branchOffset = 0; branchInstruction.write(codeAttribute, offset); } } public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) { // Try to write out the instruction. // Table switch instructions should always fit. tableSwitchInstruction.write(codeAttribute, offset); } public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) { // Try to write out the instruction. // Table switch instructions should always fit. lookUpSwitchInstruction.write(codeAttribute, offset); } // Implementations for AttributeVisitor. public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Avoid doing any work if nothing is changing anyway. if (codeAttributeEditor != null) { // Apply the collected expansions. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); // Clear the modifications for the next run. codeAttributeEditor = null; } } // Small utility methods. /** * Remembers to place the given instruction right before the instruction * at the given offset. */ private void insertBeforeInstruction(int instructionOffset, Instruction instruction) { ensureCodeAttributeEditor(); // Replace the instruction. codeAttributeEditor.insertBeforeInstruction(instructionOffset, instruction); } /** * Remembers to replace the instruction at the given offset by the given * instruction. */ private void replaceInstruction(int instructionOffset, Instruction instruction) { ensureCodeAttributeEditor(); // Replace the instruction. codeAttributeEditor.replaceInstruction(instructionOffset, instruction); } /** * Remembers to place the given instruction right after the instruction * at the given offset. */ private void insertAfterInstruction(int instructionOffset, Instruction instruction) { ensureCodeAttributeEditor(); // Replace the instruction. codeAttributeEditor.insertAfterInstruction(instructionOffset, instruction); } /** * Makes sure there is a code attribute editor for the given code attribute. */ private void ensureCodeAttributeEditor() { if (codeAttributeEditor == null) { codeAttributeEditor = new CodeAttributeEditor(); codeAttributeEditor.reset(codeLength); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -