📄 codeiterator.java
字号:
/** * Inserts a gap in front of the instruction at the given * index <code>pos</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 instruction at the given index is at the beginning * of a block statement, * then the gap is inserted within that block. * * @param pos the index at which a gap is inserted. * @param length gap length. * @return the length of the inserted gap. * It might be bigger than <code>length</code>. */ public int insertGap(int pos, int length) throws BadBytecode { return insertGapCore(pos, length, false); } /** * Inserts an exclusive 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 excluded from that block. * * @param length gap length * @return the index indicating the first byte of the inserted gap. */ public int insertExGap(int length) throws BadBytecode { int pos = currentPos; insertGapCore(currentPos, length, true); return pos; } /** * Inserts an exclusive gap in front of the instruction at the given * index <code>pos</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 instruction at the given index is at the beginning * of a block statement, * then the gap is excluded from that block. * * @param pos the index at which a gap is inserted. * @param length gap length. * @return the length of the inserted gap. * It might be bigger than <code>length</code>. */ public int insertExGap(int pos, int length) throws BadBytecode { return insertGapCore(pos, length, true); } /** * @return the length of the really inserted gap. */ private int insertGapCore(int pos, int length, boolean exclusive) throws BadBytecode { if (length <= 0) return 0; int cur = currentPos; byte[] c = insertGap(bytecode, pos, length, exclusive, get().getExceptionTable(), codeAttr); int length2 = c.length - bytecode.length; if (cur >= pos) currentPos = cur + length2; codeAttr.setCode(c); bytecode = c; endPos = getCodeLength(); updateCursors(pos, length2); return length2; } /** * Is called when a gap is inserted. The default implementation is empty. * A subclass can override this method so that cursors will be updated. * * @param pos the position where a gap is inserted. * @param length the length of the gap. */ protected void updateCursors(int pos, int length) { // empty } /** * Copies and inserts the entries in the given exception table * at the beginning of the exception table in the code attribute * edited by this object. * * @param offset the value added to the code positions included * in the entries. */ public void insert(ExceptionTable et, int offset) { codeAttr.getExceptionTable().add(0, et, offset); } /** * Appends the given bytecode sequence at the end. * * @param code the bytecode appended. * @return the position of the first byte of the appended bytecode. */ public int append(byte[] code) { int size = getCodeLength(); int len = code.length; if (len <= 0) return size; appendGap(len); byte[] dest = bytecode; for (int i = 0; i < len; ++i) dest[i + size] = code[i]; return size; } /** * Appends a gap at the end of the bytecode sequence. * * @param gapLength gap length */ public void appendGap(int gapLength) { byte[] code = bytecode; int codeLength = code.length; byte[] newcode = new byte[codeLength + gapLength]; int i; for (i = 0; i < codeLength; ++i) newcode[i] = code[i]; for (i = codeLength; i < codeLength + gapLength; ++i) newcode[i] = NOP; codeAttr.setCode(newcode); bytecode = newcode; endPos = getCodeLength(); } /** * Copies and appends the entries in the given exception table * at the end of the exception table in the code attribute * edited by this object. * * @param offset the value added to the code positions included * in the entries. */ public void append(ExceptionTable et, int offset) { ExceptionTable table = codeAttr.getExceptionTable(); table.add(table.size(), et, offset); } /* opcodeLegth is used for implementing nextOpcode(). */ private static final int opcodeLength[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 5, 0, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3, 5, 5 }; // 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE /** * Calculates the index of the next opcode. */ static int nextOpcode(byte[] code, int index) throws BadBytecode { int opcode; try { opcode = code[index] & 0xff; } catch (IndexOutOfBoundsException e) { throw new BadBytecode("invalid opcode address"); } try { int len = opcodeLength[opcode]; if (len > 0) return index + len; else if (opcode == WIDE) if (code[index + 1] == (byte)IINC) // WIDE IINC return index + 6; else return index + 4; // WIDE ... else { int index2 = (index & ~3) + 8; if (opcode == LOOKUPSWITCH) { int npairs = ByteArray.read32bit(code, index2); return index2 + npairs * 8 + 4; } else if (opcode == TABLESWITCH) { int low = ByteArray.read32bit(code, index2); int high = ByteArray.read32bit(code, index2 + 4); return index2 + (high - low + 1) * 4 + 8; } // else // throw new BadBytecode(opcode); } } catch (IndexOutOfBoundsException e) { } // opcode is UNUSED or an IndexOutOfBoundsException was thrown. throw new BadBytecode(opcode); } // methods for implementing insertGap(). /* If "where" is the beginning of a block statement, then the inserted * gap is also included in the block statement. * "where" must indicate the first byte of an opcode. * The inserted gap is filled with NOP. gapLength may be extended to * a multiple of 4. */ static byte[] insertGap(byte[] code, int where, int gapLength, boolean exclusive, ExceptionTable etable, CodeAttribute ca) throws BadBytecode { if (gapLength <= 0) return code; try { return insertGap0(code, where, gapLength, exclusive, etable, ca); } catch (AlignmentException e) { try { return insertGap0(code, where, (gapLength + 3) & ~3, exclusive, etable, ca); } catch (AlignmentException e2) { throw new RuntimeException("fatal error?"); } } } private static byte[] insertGap0(byte[] code, int where, int gapLength, boolean exclusive, ExceptionTable etable, CodeAttribute ca) throws BadBytecode, AlignmentException { int codeLength = code.length; byte[] newcode = new byte[codeLength + gapLength]; insertGap2(code, where, gapLength, codeLength, newcode, exclusive); etable.shiftPc(where, gapLength, exclusive); LineNumberAttribute na = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); if (na != null) na.shiftPc(where, gapLength, exclusive); LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute( LocalVariableAttribute.tag); if (va != null) va.shiftPc(where, gapLength, exclusive); LocalVariableAttribute vta = (LocalVariableAttribute)ca.getAttribute( LocalVariableAttribute.typeTag); if (vta != null) vta.shiftPc(where, gapLength, exclusive); return newcode; } private static void insertGap2(byte[] code, int where, int gapLength, int endPos, byte[] newcode, boolean exclusive) throws BadBytecode, AlignmentException { int nextPos; int i = 0; int j = 0; for (; i < endPos; i = nextPos) { if (i == where) { int j2 = j + gapLength; while (j < j2) newcode[j++] = NOP; } nextPos = nextOpcode(code, i); int inst = code[i] & 0xff; // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr if ((153 <= inst && inst <= 168) || inst == IFNULL || inst == IFNONNULL) { /* 2bytes *signed* offset */ int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff); offset = newOffset(i, offset, where, gapLength, exclusive); newcode[j] = code[i]; ByteArray.write16bit(offset, newcode, j + 1); j += 3; } else if (inst == GOTO_W || inst == JSR_W) { /* 4bytes offset */ int offset = ByteArray.read32bit(code, i + 1); offset = newOffset(i, offset, where, gapLength, exclusive); newcode[j++] = code[i]; ByteArray.write32bit(offset, newcode, j); j += 4; } else if (inst == TABLESWITCH) { if (i != j && (gapLength & 3) != 0) throw new AlignmentException(); int i0 = i; int i2 = (i & ~3) + 4; // 0-3 byte padding while (i0 < i2) newcode[j++] = code[i0++]; int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2), where, gapLength, exclusive); ByteArray.write32bit(defaultbyte, newcode, j); int lowbyte = ByteArray.read32bit(code, i2 + 4); ByteArray.write32bit(lowbyte, newcode, j + 4); int highbyte = ByteArray.read32bit(code, i2 + 8); ByteArray.write32bit(highbyte, newcode, j + 8); j += 12; i0 = i2 + 12; i2 = i0 + (highbyte - lowbyte + 1) * 4; while (i0 < i2) { int offset = newOffset(i, ByteArray.read32bit(code, i0), where, gapLength, exclusive); ByteArray.write32bit(offset, newcode, j); j += 4; i0 += 4; } } else if (inst == LOOKUPSWITCH) { if (i != j && (gapLength & 3) != 0) throw new AlignmentException(); int i0 = i; int i2 = (i & ~3) + 4; // 0-3 byte padding while (i0 < i2) newcode[j++] = code[i0++]; int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2), where, gapLength, exclusive); ByteArray.write32bit(defaultbyte, newcode, j); int npairs = ByteArray.read32bit(code, i2 + 4); ByteArray.write32bit(npairs, newcode, j + 4); j += 8; i0 = i2 + 8; i2 = i0 + npairs * 8; while (i0 < i2) { ByteArray.copy32bit(code, i0, newcode, j); int offset = newOffset(i, ByteArray.read32bit(code, i0 + 4), where, gapLength, exclusive); ByteArray.write32bit(offset, newcode, j + 4); j += 8; i0 += 8; } } else while (i < nextPos) newcode[j++] = code[i++]; } } private static int newOffset(int i, int offset, int where, int gapLength, boolean exclusive) { int target = i + offset; if (i < where) { if (where < target || (exclusive && where == target)) offset += gapLength; } else if (target < where || (!exclusive && where == target)) offset -= gapLength; return offset; }}class AlignmentException extends Exception {}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -