📄 codewriter.java
字号:
do { if (state == 3) { state = 2; } u = 0; while (u < b.length) { int opcode = b[u] & 0xFF; // opcode of current instruction int insert = 0; // bytes to be added after this instruction switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: u += 1; break; case ClassWriter.LABEL_INSN: if (opcode > 201) { // converts temporary opcodes 202 to 217 (inclusive), 218 and 219 // to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL opcode = opcode < 218 ? opcode - 49 : opcode - 20; label = u + readUnsignedShort(b, u + 1); } else { label = u + readShort(b, u + 1); } newOffset = getNewOffset(allIndexes, allSizes, u, label); if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) { if (!resize[u]) { if (opcode == Constants.GOTO || opcode == Constants.JSR) { // two additional bytes will be required to replace this // GOTO or JSR instruction with a GOTO_W or a JSR_W insert = 2; } else { // five additional bytes will be required to replace this // IFxxx <l> instruction with IFNOTxxx <l'> GOTO_W <l>, where // IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for // IFEQ) and where <l'> designates the instruction just after // the GOTO_W. insert = 5; } resize[u] = true; } } u += 3; break; case ClassWriter.LABELW_INSN: u += 5; break; case ClassWriter.TABL_INSN: if (state == 1) { // true number of bytes to be added (or removed) from this // instruction = (future number of padding bytes - current number // of padding byte) - previously over estimated variation = // = ((3 - newOffset%4) - (3 - u%4)) - u%4 // = (-newOffset%4 + u%4) - u%4 // = -(newOffset & 3) newOffset = getNewOffset(allIndexes, allSizes, 0, u); insert = -(newOffset & 3); } else if (!resize[u]) { // over estimation of the number of bytes to be added to this // instruction = 3 - current number of padding bytes = 3 - (3 - // u%4) = u%4 = u & 3 insert = u & 3; resize[u] = true; } // skips instruction u = u + 4 - (u & 3); u += 4*(readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; break; case ClassWriter.LOOK_INSN: if (state == 1) { // like TABL_INSN newOffset = getNewOffset(allIndexes, allSizes, 0, u); insert = -(newOffset & 3); } else if (!resize[u]) { // like TABL_INSN insert = u & 3; resize[u] = true; } // skips instruction u = u + 4 - (u & 3); u += 8*readInt(b, u + 4) + 8; break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Constants.IINC) { u += 6; } else { u += 4; } break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: u += 2; break; case ClassWriter.SHORT_INSN: case ClassWriter.LDCW_INSN: case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: u += 3; break; case ClassWriter.ITFMETH_INSN: u += 5; break; // case ClassWriter.MANA_INSN: default: u += 4; break; } if (insert != 0) { // adds a new (u, insert) entry in the allIndexes and allSizes arrays int[] newIndexes = new int[allIndexes.length + 1]; int[] newSizes = new int[allSizes.length + 1]; System.arraycopy(allIndexes, 0, newIndexes, 0, allIndexes.length); System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); newIndexes[allIndexes.length] = u; newSizes[allSizes.length] = insert; allIndexes = newIndexes; allSizes = newSizes; if (insert > 0) { state = 3; } } } if (state < 3) { --state; } } while (state != 0); // 2nd step: // copies the bytecode of the method into a new bytevector, updates the // offsets, and inserts (or removes) bytes as requested. ByteVector newCode = new ByteVector(code.length); u = 0; while (u < code.length) { for (i = allIndexes.length - 1; i >= 0; --i) { if (allIndexes[i] == u) { if (i < len) { if (sizes[i] > 0) { newCode.putByteArray(null, 0, sizes[i]); } else { newCode.length += sizes[i]; } indexes[i] = newCode.length; } } } int opcode = b[u] & 0xFF; switch (ClassWriter.TYPE[opcode]) { case ClassWriter.NOARG_INSN: case ClassWriter.IMPLVAR_INSN: newCode.put1(opcode); u += 1; break; case ClassWriter.LABEL_INSN: if (opcode > 201) { // changes temporary opcodes 202 to 217 (inclusive), 218 and 219 // to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL opcode = opcode < 218 ? opcode - 49 : opcode - 20; label = u + readUnsignedShort(b, u + 1); } else { label = u + readShort(b, u + 1); } newOffset = getNewOffset(allIndexes, allSizes, u, label); if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) { // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx <l> with // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode // of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the // instruction just after the GOTO_W. if (opcode == Constants.GOTO) { newCode.put1(200); // GOTO_W } else if (opcode == Constants.JSR) { newCode.put1(201); // JSR_W } else { newCode.put1(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); newCode.put2(8); // jump offset newCode.put1(200); // GOTO_W newOffset -= 3; // newOffset now computed from start of GOTO_W } newCode.put4(newOffset); } else { newCode.put1(opcode); newCode.put2(newOffset); } u += 3; break; case ClassWriter.LABELW_INSN: label = u + readInt(b, u + 1); newOffset = getNewOffset(allIndexes, allSizes, u, label); newCode.put1(opcode); newCode.put4(newOffset); u += 5; break; case ClassWriter.TABL_INSN: // skips 0 to 3 padding bytes v = u; u = u + 4 - (v & 3); // reads and copies instruction int source = newCode.length; newCode.put1(Constants.TABLESWITCH); while (newCode.length % 4 != 0) { newCode.put1(0); } label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); j = readInt(b, u); u += 4; newCode.put4(j); j = readInt(b, u) - j + 1; u += 4; newCode.put4(readInt(b, u - 4)); for ( ; j > 0; --j) { label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); } break; case ClassWriter.LOOK_INSN: // skips 0 to 3 padding bytes v = u; u = u + 4 - (v & 3); // reads and copies instruction source = newCode.length; newCode.put1(Constants.LOOKUPSWITCH); while (newCode.length % 4 != 0) { newCode.put1(0); } label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); j = readInt(b, u); u += 4; newCode.put4(j); for ( ; j > 0; --j) { newCode.put4(readInt(b, u)); u += 4; label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.put4(newOffset); } break; case ClassWriter.WIDE_INSN: opcode = b[u + 1] & 0xFF; if (opcode == Constants.IINC) { newCode.putByteArray(b, u, 6); u += 6; } else { newCode.putByteArray(b, u, 4); u += 4; } break; case ClassWriter.VAR_INSN: case ClassWriter.SBYTE_INSN: case ClassWriter.LDC_INSN: newCode.putByteArray(b, u, 2); u += 2; break; case ClassWriter.SHORT_INSN: case ClassWriter.LDCW_INSN: case ClassWriter.FIELDORMETH_INSN: case ClassWriter.TYPE_INSN: case ClassWriter.IINC_INSN: newCode.putByteArray(b, u, 3); u += 3; break; case ClassWriter.ITFMETH_INSN: newCode.putByteArray(b, u, 5); u += 5; break; // case MANA_INSN: default: newCode.putByteArray(b, u, 4); u += 4; break; } } // updates the instructions addresses in the // catch, local var and line number tables if (catchTable != null) { b = catchTable.data; u = 0; while (u < catchTable.length) { writeShort(b, u, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u))); writeShort(b, u + 2, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u + 2))); writeShort(b, u + 4, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u + 4))); u += 8; } } if (localVar != null) { b = localVar.data; u = 0; while (u < localVar.length) { label = readUnsignedShort(b, u); newOffset = getNewOffset(allIndexes, allSizes, 0, label); writeShort(b, u, newOffset); label += readUnsignedShort(b, u + 2); newOffset = getNewOffset(allIndexes, allSizes, 0, label) - newOffset; writeShort(b, u, newOffset); u += 10; } } if (lineNumber != null) { b = lineNumber.data; u = 0; while (u < lineNumber.length) { writeShort(b, u, getNewOffset( allIndexes, allSizes, 0, readUnsignedShort(b, u))); u += 4; } } // replaces old bytecodes with new ones code = newCode; // returns the positions of the resized instructions return indexes; } /** * Reads an unsigned short value in the given byte array. * * @param b a byte array. * @param index the start index of the value to be read. * @return the read value. */ static int readUnsignedShort (final byte[] b, final int index) { return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); } /** * Reads a signed short value in the given byte array. * * @param b a byte array. * @param index the start index of the value to be read. * @return the read value. */ static short readShort (final byte[] b, final int index) { return (short)(((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); } /** * Reads a signed int value in the given byte array. * * @param b a byte array. * @param index the start index of the value to be read. * @return the read value. */ static int readInt (final byte[] b, final int index) { return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); } /** * Writes a short value in the given byte array. * * @param b a byte array. * @param index where the first byte of the short value must be written. * @param s the value to be written in the given byte array. */ static void writeShort (final byte[] b, final int index, final int s) { b[index] = (byte)(s >>> 8); b[index + 1] = (byte)s; } /** * Computes the future value of a bytecode offset. * <p> * Note: it is possible to have several entries for the same instruction * in the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) * and (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). * * @param indexes current positions of the instructions to be resized. Each * instruction must be designated by the index of its <i>last</i> byte, * plus one (or, in other words, by the index of the <i>first</i> byte of * the <i>next</i> instruction). * @param sizes the number of bytes to be <i>added</i> to the above * instructions. More precisely, for each i < <tt>len</tt>, * <tt>sizes</tt>[i] bytes will be added at the end of the instruction * designated by <tt>indexes</tt>[i] or, if <tt>sizes</tt>[i] is * negative, the <i>last</i> |<tt>sizes[i]</tt>| bytes of the instruction * will be removed (the instruction size <i>must not</i> become negative * or null). * @param begin index of the first byte of the source instruction. * @param end index of the first byte of the target instruction. * @return the future value of the given bytecode offset. */ static int getNewOffset ( final int[] indexes, final int[] sizes, final int begin, final int end) { int offset = end - begin; for (int i = 0; i < indexes.length; ++i) { if (begin < indexes[i] && indexes[i] <= end) { // forward jump offset += sizes[i]; } else if (end < indexes[i] && indexes[i] <= begin) { // backward jump offset -= sizes[i]; } } return offset; } /** * Returns the current size of the bytecode of this method. This size just * includes the size of the bytecode instructions: it does not include the * size of the Exceptions, LocalVariableTable, LineNumberTable, Synthetic * and Deprecated attributes, if present. * * @return the current size of the bytecode of this method. */ protected int getCodeSize () { return code.length; } /** * Returns the current bytecode of this method. This bytecode only contains * the instructions: it does not include the Exceptions, LocalVariableTable, * LineNumberTable, Synthetic and Deprecated attributes, if present. * * @return the current bytecode of this method. The bytecode is contained * between the index 0 (inclusive) and the index {@link #getCodeSize * getCodeSize} (exclusive). */ protected byte[] getCode () { return code.data; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -