📄 codewriter.java
字号:
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.putByte(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 (resize[u]) {
// 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.putByte(200); // GOTO_W
} else if (opcode == Constants.JSR) {
newCode.putByte(201); // JSR_W
} else {
newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1);
newCode.putShort(8); // jump offset
newCode.putByte(200); // GOTO_W
newOffset -= 3; // newOffset now computed from start of GOTO_W
}
newCode.putInt(newOffset);
} else {
newCode.putByte(opcode);
newCode.putShort(newOffset);
}
u += 3;
break;
case ClassWriter.LABELW_INSN:
label = u + readInt(b, u + 1);
newOffset = getNewOffset(allIndexes, allSizes, u, label);
newCode.putByte(opcode);
newCode.putInt(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
newCode.putByte(Constants.TABLESWITCH);
while (newCode.length % 4 != 0) {
newCode.putByte(0);
}
label = v + readInt(b, u); u += 4;
newOffset = getNewOffset(allIndexes, allSizes, v, label);
newCode.putInt(newOffset);
j = readInt(b, u); u += 4;
newCode.putInt(j);
j = readInt(b, u) - j + 1; u += 4;
newCode.putInt(readInt(b, u - 4));
for ( ; j > 0; --j) {
label = v + readInt(b, u); u += 4;
newOffset = getNewOffset(allIndexes, allSizes, v, label);
newCode.putInt(newOffset);
}
break;
case ClassWriter.LOOK_INSN:
// skips 0 to 3 padding bytes
v = u;
u = u + 4 - (v & 3);
// reads and copies instruction
newCode.putByte(Constants.LOOKUPSWITCH);
while (newCode.length % 4 != 0) {
newCode.putByte(0);
}
label = v + readInt(b, u); u += 4;
newOffset = getNewOffset(allIndexes, allSizes, v, label);
newCode.putInt(newOffset);
j = readInt(b, u); u += 4;
newCode.putInt(j);
for ( ; j > 0; --j) {
newCode.putInt(readInt(b, u)); u += 4;
label = v + readInt(b, u); u += 4;
newOffset = getNewOffset(allIndexes, allSizes, v, label);
newCode.putInt(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 + 2, 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;
}
}
// updates the labels of the other attributes
while (cattrs != null) {
Label[] labels = cattrs.getLabels();
if (labels != null) {
for (i = labels.length - 1; i >= 0; --i) {
if (!labels[i].resized) {
labels[i].position =
getNewOffset(allIndexes, allSizes, 0, labels[i].position);
labels[i].resized = true;
}
}
}
}
// 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.
*/
public 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).
*/
public byte[] getCode () {
return code.data;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -