📄 codeiterator.java
字号:
/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */package javassist.bytecode;/** * An iterator for editing a code attribute. * * <p>If there are multiple <code>CodeIterator</code>s referring to the * same <code>Code_attribute</code>, then inserting a gap by one * <code>CodeIterator</code> will break the other * <code>CodeIterator</code>. * * <p>This iterator does not provide <code>remove()</code>. * If a piece of code in a <code>Code_attribute</code> is unnecessary, * it should be overwritten with <code>NOP</code>. * * @see CodeAttribute#iterator() */public class CodeIterator implements Opcode { protected CodeAttribute codeAttr; protected byte[] bytecode; protected int endPos; protected int currentPos; protected CodeIterator(CodeAttribute ca) { codeAttr = ca; bytecode = ca.getCode(); begin(); } /** * Moves to the first instruction. */ public void begin() { currentPos = 0; endPos = getCodeLength(); } /** * Moves to the given index. * * <p>The index of the next instruction is set to the given index. * The successive call to <code>next()</code> * returns the index that has been given to <code>move()</code>. * * <p>Note that the index is into the byte array returned by * <code>get().getCode()</code>. * * @see CodeAttribute#getCode() */ public void move(int index) { currentPos = index; } /** * Returns a Code attribute read with this iterator. */ public CodeAttribute get() { return codeAttr; } /** * Returns <code>code_length</code> of <code>Code_attribute</code>. */ public int getCodeLength() { return bytecode.length; } /** * Returns the unsigned 8bit value at the given index. */ public int byteAt(int index) { return bytecode[index] & 0xff; } /** * Writes an 8bit value at the given index. */ public void writeByte(int value, int index) { bytecode[index] = (byte)value; } /** * Returns the unsigned 16bit value at the given index. */ public int u16bitAt(int index) { return ByteArray.readU16bit(bytecode, index); } /** * Returns the signed 16bit value at the given index. */ public int s16bitAt(int index) { return ByteArray.readS16bit(bytecode, index); } /** * Writes a 16 bit integer at the index. */ public void write16bit(int value, int index) { ByteArray.write16bit(value, bytecode, index); } /** * Returns the signed 32bit value at the given index. */ public int s32bitAt(int index) { return ByteArray.read32bit(bytecode, index); } /** * Writes a 32bit integer at the index. */ public void write32bit(int value, int index) { ByteArray.write32bit(value, bytecode, index); } /** * Writes a byte array at the index. * * @param code may be a zero-length array. */ public void write(byte[] code, int index) { int len = code.length; for (int j = 0; j < len; ++j) bytecode[index++] = code[j]; } /** * Returns true if there is more instructions. */ public boolean hasNext() { return currentPos < endPos; } /** * Returns the index of the next instruction * (not the operand following the current opcode). * * <p>Note that the index is into the byte array returned by * <code>get().getCode()</code>. * * @see CodeAttribute#getCode() * @see CodeIterator#byteAt(int) */ public int next() throws BadBytecode { int pos = currentPos; currentPos = nextOpcode(bytecode, pos); return pos; } /** * Obtains the value that the next call * to <code>next()</code> will return. * * <p>This method is side-effects free. * Successive calls to <code>lookAhead()</code> return the * same value until <code>next()</code> is called. */ public int lookAhead() { return currentPos; } /** * Moves to the instruction for * either <code>super()</code> or <code>this()</code>. * * <p>This method skips all the instructions for computing arguments * to <code>super()</code> or <code>this()</code>, which should be * placed at the beginning of a constructor body. * * <p>This method returns the index of INVOKESPECIAL instruction * executing <code>super()</code> or <code>this()</code>. * A successive call to <code>next()</code> returns the * index of the next instruction following that INVOKESPECIAL. * * <p>This method works only for a constructor. * * @return the index of the INVOKESPECIAL instruction, or -1 * if a constructor invocation is not found. */ public int skipConstructor() throws BadBytecode { return skipSuperConstructor0(-1); } /** * Moves to the instruction for <code>super()</code>. * * <p>This method skips all the instructions for computing arguments to * <code>super()</code>, which should be * placed at the beginning of a constructor body. * * <p>This method returns the index of INVOKESPECIAL instruction * executing <code>super()</code>. * A successive call to <code>next()</code> returns the * index of the next instruction following that INVOKESPECIAL. * * <p>This method works only for a constructor. * * @return the index of the INVOKESPECIAL instruction, or -1 * if a super constructor invocation is not found * but <code>this()</code> is found. */ public int skipSuperConstructor() throws BadBytecode { return skipSuperConstructor0(0); } /** * Moves to the instruction for <code>this()</code>. * * <p>This method skips all the instructions for computing arguments to * <code>this()</code>, which should be * placed at the beginning of a constructor body. * * <p>This method returns the index of INVOKESPECIAL instruction * executing <code>this()</code>. * A successive call to <code>next()</code> returns the * index of the next instruction following that INVOKESPECIAL. * * <p>This method works only for a constructor. * * @return the index of the INVOKESPECIAL instruction, or -1 * if a explicit constructor invocation is not found * but <code>super()</code> is found. */ public int skipThisConstructor() throws BadBytecode { return skipSuperConstructor0(1); } /* skipSuper 1: this(), 0: super(), -1: both. */ private int skipSuperConstructor0(int skipThis) throws BadBytecode { begin(); ConstPool cp = codeAttr.getConstPool(); String thisClassName = codeAttr.getDeclaringClass(); int nested = 0; while (hasNext()) { int index = next(); int c = byteAt(index); if (c == NEW) ++nested; else if (c == INVOKESPECIAL) { int mref = ByteArray.readU16bit(bytecode, index + 1); if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit)) if (--nested < 0) { if (skipThis < 0) return index; String cname = cp.getMethodrefClassName(mref); if (cname.equals(thisClassName) == (skipThis > 0)) return index; else break; } } } begin(); return -1; } /** * Inserts the given bytecode sequence * before the next instruction that would be returned by * <code>next()</code> (not before the instruction returned * by tha last call to <code>next()</code>). * Branch offsets and the exception table are also updated. * * <p>If the next instruction is at the beginning of a block statement, * then the bytecode is inserted within that block. * * <p>An extra gap may be inserted at the end of the inserted * bytecode sequence for adjusting alignment if the code attribute * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. * * @param code inserted bytecode sequence. * @return the index indicating the first byte of the * inserted byte sequence. */ public int insert(byte[] code) throws BadBytecode { int pos = currentPos; insert0(currentPos, code, false); return pos; } /** * Inserts the given bytecode sequence * before the instruction at the given index <code>pos</code>. * Branch offsets and the exception table are also updated. * * <p>If the instruction at the given index is at the beginning * of a block statement, * then the bytecode is inserted within that block. * * <p>An extra gap may be inserted at the end of the inserted * bytecode sequence for adjusting alignment if the code attribute * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. * * @param pos the index at which a byte sequence is inserted. * @param code inserted bytecode sequence. */ public void insert(int pos, byte[] code) throws BadBytecode { insert0(pos, code, false); } /** * Inserts the given bytecode sequence exclusively * before the next instruction that would be returned by * <code>next()</code> (not before the instruction returned * by tha last call to <code>next()</code>). * Branch offsets and the exception table are also updated. * * <p>If the next instruction is at the beginning of a block statement, * then the bytecode is excluded from that block. * * <p>An extra gap may be inserted at the end of the inserted * bytecode sequence for adjusting alignment if the code attribute * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. * * @param code inserted bytecode sequence. * @return the index indicating the first byte of the * inserted byte sequence. */ public int insertEx(byte[] code) throws BadBytecode { int pos = currentPos; insert0(currentPos, code, true); return pos; } /** * Inserts the given bytecode sequence exclusively * before the instruction at the given index <code>pos</code>. * Branch offsets and the exception table are also updated. * * <p>If the instruction at the given index is at the beginning * of a block statement, * then the bytecode is excluded from that block. * * <p>An extra gap may be inserted at the end of the inserted * bytecode sequence for adjusting alignment if the code attribute * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. * * @param pos the index at which a byte sequence is inserted. * @param code inserted bytecode sequence. */ public void insertEx(int pos, byte[] code) throws BadBytecode { insert0(pos, code, true); } private void insert0(int pos, byte[] code, boolean exclusive) throws BadBytecode { int len = code.length; if (len <= 0) return; insertGapCore(pos, len, exclusive); // currentPos will change. for (int j = 0; j < len; ++j) bytecode[pos++] = code[j]; } /** * Inserts a gap * before the next instruction that would be returned by * <code>next()</code> (not before the instruction returned * by tha last call to <code>next()</code>). * Branch offsets and the exception table are also updated. * The inserted gap is filled with NOP. The gap length may be * extended to a multiple of 4. * * <p>If the next instruction is at the beginning of a block statement, * then the gap is inserted within that block. * * @param length gap length * @return the index indicating the first byte of the inserted gap. */ public int insertGap(int length) throws BadBytecode { int pos = currentPos; insertGapCore(currentPos, length, false); return pos; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -