📄 generatoradapter.java
字号:
/**
* Generates the instructions to cast a numerical value from one type to
* another.
*
* @param from the type of the top stack value
* @param to the type into which this value must be cast.
*/
public void cast(final Type from,
final Type to) {
if ( from != to ) {
if ( from == Type.DOUBLE_TYPE ) {
if ( to == Type.FLOAT_TYPE ) {
this.mv.visitInsn( Opcodes.D2F );
} else if ( to == Type.LONG_TYPE ) {
this.mv.visitInsn( Opcodes.D2L );
} else {
this.mv.visitInsn( Opcodes.D2I );
cast( Type.INT_TYPE,
to );
}
} else if ( from == Type.FLOAT_TYPE ) {
if ( to == Type.DOUBLE_TYPE ) {
this.mv.visitInsn( Opcodes.F2D );
} else if ( to == Type.LONG_TYPE ) {
this.mv.visitInsn( Opcodes.F2L );
} else {
this.mv.visitInsn( Opcodes.F2I );
cast( Type.INT_TYPE,
to );
}
} else if ( from == Type.LONG_TYPE ) {
if ( to == Type.DOUBLE_TYPE ) {
this.mv.visitInsn( Opcodes.L2D );
} else if ( to == Type.FLOAT_TYPE ) {
this.mv.visitInsn( Opcodes.L2F );
} else {
this.mv.visitInsn( Opcodes.L2I );
cast( Type.INT_TYPE,
to );
}
} else {
if ( to == Type.BYTE_TYPE ) {
this.mv.visitInsn( Opcodes.I2B );
} else if ( to == Type.CHAR_TYPE ) {
this.mv.visitInsn( Opcodes.I2C );
} else if ( to == Type.DOUBLE_TYPE ) {
this.mv.visitInsn( Opcodes.I2D );
} else if ( to == Type.FLOAT_TYPE ) {
this.mv.visitInsn( Opcodes.I2F );
} else if ( to == Type.LONG_TYPE ) {
this.mv.visitInsn( Opcodes.I2L );
} else if ( to == Type.SHORT_TYPE ) {
this.mv.visitInsn( Opcodes.I2S );
}
}
}
}
// ------------------------------------------------------------------------
// Instructions to do boxing and unboxing operations
// ------------------------------------------------------------------------
/**
* Generates the instructions to box the top stack value. This value is
* replaced by its boxed equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void box(final Type type) {
if ( type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY ) {
return;
}
if ( type == Type.VOID_TYPE ) {
push( (String) null );
} else {
Type boxed = type;
switch ( type.getSort() ) {
case Type.BYTE :
boxed = GeneratorAdapter.BYTE_TYPE;
break;
case Type.BOOLEAN :
boxed = GeneratorAdapter.BOOLEAN_TYPE;
break;
case Type.SHORT :
boxed = GeneratorAdapter.SHORT_TYPE;
break;
case Type.CHAR :
boxed = GeneratorAdapter.CHARACTER_TYPE;
break;
case Type.INT :
boxed = GeneratorAdapter.INTEGER_TYPE;
break;
case Type.FLOAT :
boxed = GeneratorAdapter.FLOAT_TYPE;
break;
case Type.LONG :
boxed = GeneratorAdapter.LONG_TYPE;
break;
case Type.DOUBLE :
boxed = GeneratorAdapter.DOUBLE_TYPE;
break;
}
newInstance( boxed );
if ( type.getSize() == 2 ) {
// Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
dupX2();
dupX2();
pop();
} else {
// p -> po -> opo -> oop -> o
dupX1();
swap();
}
invokeConstructor( boxed,
new Method( "<init>",
Type.VOID_TYPE,
new Type[]{type} ) );
}
}
/**
* Generates the instructions to unbox the top stack value. This value is
* replaced by its unboxed equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void unbox(final Type type) {
Type t = GeneratorAdapter.NUMBER_TYPE;
Method sig = null;
switch ( type.getSort() ) {
case Type.VOID :
return;
case Type.CHAR :
t = GeneratorAdapter.CHARACTER_TYPE;
sig = GeneratorAdapter.CHAR_VALUE;
break;
case Type.BOOLEAN :
t = GeneratorAdapter.BOOLEAN_TYPE;
sig = GeneratorAdapter.BOOLEAN_VALUE;
break;
case Type.DOUBLE :
sig = GeneratorAdapter.DOUBLE_VALUE;
break;
case Type.FLOAT :
sig = GeneratorAdapter.FLOAT_VALUE;
break;
case Type.LONG :
sig = GeneratorAdapter.LONG_VALUE;
break;
case Type.INT :
case Type.SHORT :
case Type.BYTE :
sig = GeneratorAdapter.INT_VALUE;
}
if ( sig == null ) {
checkCast( type );
} else {
checkCast( t );
invokeVirtual( t,
sig );
}
}
// ------------------------------------------------------------------------
// Instructions to jump to other instructions
// ------------------------------------------------------------------------
/**
* Creates a new {@link Label}.
*
* @return a new {@link Label}.
*/
public Label newLabel() {
return new Label();
}
/**
* Marks the current code position with the given label.
*
* @param label a label.
*/
public void mark(final Label label) {
this.mv.visitLabel( label );
}
/**
* Marks the current code position with a new label.
*
* @return the label that was created to mark the current code position.
*/
public Label mark() {
final Label label = new Label();
this.mv.visitLabel( label );
return label;
}
/**
* Generates the instructions to jump to a label based on the comparison of
* the top two stack values.
*
* @param type the type of the top two stack values.
* @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
* LE.
* @param label where to jump if the comparison result is <tt>true</tt>.
*/
public void ifCmp(final Type type,
final int mode,
final Label label) {
int intOp = -1;
int jumpMode = mode;
switch ( mode ) {
case GE :
jumpMode = GeneratorAdapter.LT;
break;
case LE :
jumpMode = GeneratorAdapter.GT;
break;
}
switch ( type.getSort() ) {
case Type.LONG :
this.mv.visitInsn( Opcodes.LCMP );
break;
case Type.DOUBLE :
this.mv.visitInsn( Opcodes.DCMPG );
break;
case Type.FLOAT :
this.mv.visitInsn( Opcodes.FCMPG );
break;
case Type.ARRAY :
case Type.OBJECT :
switch ( mode ) {
case EQ :
this.mv.visitJumpInsn( Opcodes.IF_ACMPEQ,
label );
return;
case NE :
this.mv.visitJumpInsn( Opcodes.IF_ACMPNE,
label );
return;
}
throw new IllegalArgumentException( "Bad comparison for type " + type );
default :
switch ( mode ) {
case EQ :
intOp = Opcodes.IF_ICMPEQ;
break;
case NE :
intOp = Opcodes.IF_ICMPNE;
break;
case GE :
intOp = Opcodes.IF_ICMPGE;
break;
case LT :
intOp = Opcodes.IF_ICMPLT;
break;
case LE :
intOp = Opcodes.IF_ICMPLE;
break;
case GT :
intOp = Opcodes.IF_ICMPGT;
break;
}
this.mv.visitJumpInsn( intOp,
label );
return;
}
this.mv.visitJumpInsn( jumpMode,
label );
}
/**
* Generates the instructions to jump to a label based on the comparison of
* the top two integer stack values.
*
* @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
* LE.
* @param label where to jump if the comparison result is <tt>true</tt>.
*/
public void ifICmp(final int mode,
final Label label) {
ifCmp( Type.INT_TYPE,
mode,
label );
}
/**
* Generates the instructions to jump to a label based on the comparison of
* the top integer stack value with zero.
*
* @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
* LE.
* @param label where to jump if the comparison result is <tt>true</tt>.
*/
public void ifZCmp(final int mode,
final Label label) {
this.mv.visitJumpInsn( mode,
label );
}
/**
* Generates the instruction to jump to the given label if the top stack
* value is null.
*
* @param label where to jump if the condition is <tt>true</tt>.
*/
public void ifNull(final Label label) {
this.mv.visitJumpInsn( Opcodes.IFNULL,
label );
}
/**
* Generates the instruction to jump to the given label if the top stack
* value is not null.
*
* @param label where to jump if the condition is <tt>true</tt>.
*/
public void ifNonNull(final Label label) {
this.mv.visitJumpInsn( Opcodes.IFNONNULL,
label );
}
/**
* Generates the instruction to jump to the given label.
*
* @param label where to jump if the condition is <tt>true</tt>.
*/
public void goTo(final Label label) {
this.mv.visitJumpInsn( Opcodes.GOTO,
label );
}
/**
* Generates a RET instruction.
*
* @param local a local variable identifier, as returned by {@link #newLocal
* newLocal}.
*/
public void ret(final int local) {
this.mv.visitVarInsn( Opcodes.RET,
local );
}
/**
* Generates the instructions for a switch statement.
*
* @param keys the switch case keys.
* @param generator a generator to generate the code for the switch cases.
*/
public void tableSwitch(final int[] keys,
final TableSwitchGenerator generator) {
float density;
if ( keys.length == 0 ) {
density = 0;
} else {
density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1);
}
tableSwitch( keys,
generator,
density >= 0.5f );
}
/**
* Generates the instructions for a switch statement.
*
* @param keys the switch case keys.
* @param generator a generator to generate the code for the switch cases.
* @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or
* <tt>false</tt> to use a LOOKUPSWITCH instruction.
*/
public void tableSwitch(final int[] keys,
final TableSwitchGenerator generator,
final boolean useTable) {
for ( int i = 1; i < keys.length; ++i ) {
if ( keys[i] < keys[i - 1] ) {
throw new IllegalArgumentException( "keys must be sorted ascending" );
}
}
final Label def = newLabel();
final Label end = newLabel();
if ( keys.length > 0 ) {
final int len = keys.length;
final int min = keys[0];
final int max = keys[len - 1];
final int range = max - min + 1;
if ( useTable ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -