📄 methodwriter.java
字号:
// adds the instruction to the bytecode of the method
if ( opcode == Opcodes.SIPUSH ) {
this.code.put12( opcode,
operand );
} else { // BIPUSH or NEWARRAY
this.code.put11( opcode,
operand );
}
}
public void visitVarInsn(final int opcode,
final int var) {
if ( this.computeMaxs ) {
// updates current and max stack sizes
if ( opcode == Opcodes.RET ) {
// no stack change, but end of current block (no successor)
if ( this.currentBlock != null ) {
this.currentBlock.maxStackSize = this.maxStackSize;
this.currentBlock = null;
}
} else { // xLOAD or xSTORE
final int size = this.stackSize + MethodWriter.SIZE[opcode];
if ( size > this.maxStackSize ) {
this.maxStackSize = size;
}
this.stackSize = size;
}
// updates max locals
int n;
if ( opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE ) {
n = var + 2;
} else {
n = var + 1;
}
if ( n > this.maxLocals ) {
this.maxLocals = n;
}
}
// adds the instruction to the bytecode of the method
if ( var < 4 && opcode != Opcodes.RET ) {
int opt;
if ( opcode < Opcodes.ISTORE ) {
/* ILOAD_0 */
opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
} else {
/* ISTORE_0 */
opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
}
this.code.putByte( opt );
} else if ( var >= 256 ) {
this.code.putByte( 196 /* WIDE */).put12( opcode,
var );
} else {
this.code.put11( opcode,
var );
}
}
public void visitTypeInsn(final int opcode,
final String desc) {
if ( this.computeMaxs && opcode == Opcodes.NEW ) {
// updates current and max stack sizes only if opcode == NEW
// (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
final int size = this.stackSize + 1;
if ( size > this.maxStackSize ) {
this.maxStackSize = size;
}
this.stackSize = size;
}
// adds the instruction to the bytecode of the method
this.code.put12( opcode,
this.cw.newClass( desc ) );
}
public void visitFieldInsn(final int opcode,
final String owner,
final String name,
final String desc) {
if ( this.computeMaxs ) {
int size;
// computes the stack size variation
final char c = desc.charAt( 0 );
switch ( opcode ) {
case Opcodes.GETSTATIC :
size = this.stackSize + (c == 'D' || c == 'J' ? 2 : 1);
break;
case Opcodes.PUTSTATIC :
size = this.stackSize + (c == 'D' || c == 'J' ? -2 : -1);
break;
case Opcodes.GETFIELD :
size = this.stackSize + (c == 'D' || c == 'J' ? 1 : 0);
break;
// case Constants.PUTFIELD:
default :
size = this.stackSize + (c == 'D' || c == 'J' ? -3 : -2);
break;
}
// updates current and max stack sizes
if ( size > this.maxStackSize ) {
this.maxStackSize = size;
}
this.stackSize = size;
}
// adds the instruction to the bytecode of the method
this.code.put12( opcode,
this.cw.newField( owner,
name,
desc ) );
}
public void visitMethodInsn(final int opcode,
final String owner,
final String name,
final String desc) {
final boolean itf = opcode == Opcodes.INVOKEINTERFACE;
final Item i = this.cw.newMethodItem( owner,
name,
desc,
itf );
int argSize = i.intVal;
if ( this.computeMaxs ) {
/*
* computes the stack size variation. In order not to recompute
* several times this variation for the same Item, we use the intVal
* field of this item to store this variation, once it has been
* computed. More precisely this intVal field stores the sizes of
* the arguments and of the return value corresponding to desc.
*/
if ( argSize == 0 ) {
// the above sizes have not been computed yet, so we compute
// them...
argSize = getArgumentsAndReturnSizes( desc );
// ... and we save them in order not to recompute them in the
// future
i.intVal = argSize;
}
int size;
if ( opcode == Opcodes.INVOKESTATIC ) {
size = this.stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
} else {
size = this.stackSize - (argSize >> 2) + (argSize & 0x03);
}
// updates current and max stack sizes
if ( size > this.maxStackSize ) {
this.maxStackSize = size;
}
this.stackSize = size;
}
// adds the instruction to the bytecode of the method
if ( itf ) {
if ( !this.computeMaxs ) {
if ( argSize == 0 ) {
argSize = getArgumentsAndReturnSizes( desc );
i.intVal = argSize;
}
}
this.code.put12( Opcodes.INVOKEINTERFACE,
i.index ).put11( argSize >> 2,
0 );
} else {
this.code.put12( opcode,
i.index );
}
}
public void visitJumpInsn(final int opcode,
final Label label) {
if ( this.computeMaxs ) {
if ( opcode == Opcodes.GOTO ) {
// no stack change, but end of current block (with one new
// successor)
if ( this.currentBlock != null ) {
this.currentBlock.maxStackSize = this.maxStackSize;
addSuccessor( this.stackSize,
label );
this.currentBlock = null;
}
} else if ( opcode == Opcodes.JSR ) {
if ( this.currentBlock != null ) {
addSuccessor( this.stackSize + 1,
label );
}
} else {
// updates current stack size (max stack size unchanged because
// stack size variation always negative in this case)
this.stackSize += MethodWriter.SIZE[opcode];
if ( this.currentBlock != null ) {
addSuccessor( this.stackSize,
label );
}
}
}
// adds the instruction to the bytecode of the method
if ( label.resolved && label.position - this.code.length < Short.MIN_VALUE ) {
/*
* case of a backward jump with an offset < -32768. In this case we
* automatically replace 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 == Opcodes.GOTO ) {
this.code.putByte( 200 ); // GOTO_W
} else if ( opcode == Opcodes.JSR ) {
this.code.putByte( 201 ); // JSR_W
} else {
this.code.putByte( opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1 );
this.code.putShort( 8 ); // jump offset
this.code.putByte( 200 ); // GOTO_W
}
label.put( this,
this.code,
this.code.length - 1,
true );
} else {
/*
* case of a backward jump with an offset >= -32768, or of a forward
* jump with, of course, an unknown offset. In these cases we store
* the offset in 2 bytes (which will be increased in
* resizeInstructions, if needed).
*/
this.code.putByte( opcode );
label.put( this,
this.code,
this.code.length - 1,
false );
}
}
public void visitLabel(final Label label) {
if ( this.computeMaxs ) {
if ( this.currentBlock != null ) {
// ends current block (with one new successor)
this.currentBlock.maxStackSize = this.maxStackSize;
addSuccessor( this.stackSize,
label );
}
// begins a new current block,
// resets the relative current and max stack sizes
this.currentBlock = label;
this.stackSize = 0;
this.maxStackSize = 0;
}
// resolves previous forward references to label, if any
this.resize |= label.resolve( this,
this.code.length,
this.code.data );
}
public void visitLdcInsn(final Object cst) {
final Item i = this.cw.newConstItem( cst );
if ( this.computeMaxs ) {
int size;
// computes the stack size variation
if ( i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE ) {
size = this.stackSize + 2;
} else {
size = this.stackSize + 1;
}
// updates current and max stack sizes
if ( size > this.maxStackSize ) {
this.maxStackSize = size;
}
this.stackSize = size;
}
// adds the instruction to the bytecode of the method
final int index = i.index;
if ( i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE ) {
this.code.put12( 20 /* LDC2_W */,
index );
} else if ( index >= 256 ) {
this.code.put12( 19 /* LDC_W */,
index );
} else {
this.code.put11( Opcodes.LDC,
index );
}
}
public void visitIincInsn(final int var,
final int increment) {
if ( this.computeMaxs ) {
// updates max locals only (no stack change)
final int n = var + 1;
if ( n > this.maxLocals ) {
this.maxLocals = n;
}
}
// adds the instruction to the bytecode of the method
if ( (var > 255) || (increment > 127) || (increment < -128) ) {
this.code.putByte( 196 /* WIDE */).put12( Opcodes.IINC,
var ).putShort( increment );
} else {
this.code.putByte( Opcodes.IINC ).put11( var,
increment );
}
}
public void visitTableSwitchInsn(final int min,
final int max,
final Label dflt,
final Label labels[]) {
if ( this.computeMaxs ) {
// updates current stack size (max stack size unchanged)
--this.stackSize;
// ends current block (with many new successors)
if ( this.currentBlock != null ) {
this.currentBlock.maxStackSize = this.maxStackSize;
addSuccessor( this.stackSize,
dflt );
for ( int i = 0; i < labels.length; ++i ) {
addSuccessor( this.stackSize,
labels[i] );
}
this.currentBlock = null;
}
}
// adds the instruction to the bytecode of the method
final int source = this.code.length;
this.code.putByte( Opcodes.TABLESWITCH );
while ( this.code.length % 4 != 0 ) {
this.code.putByte( 0 );
}
dflt.put( this,
this.code,
source,
true );
this.code.putInt( min ).putInt( max );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -