|
|
|
@ -27,18 +27,38 @@ import org.springframework.asm.Type; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@SuppressWarnings("fallthrough") |
|
|
|
@SuppressWarnings("fallthrough") |
|
|
|
public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SPRING PATCH BEGIN
|
|
|
|
|
|
|
|
private static final Signature BOOLEAN_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Boolean valueOf(boolean)"); |
|
|
|
|
|
|
|
private static final Signature BYTE_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Byte valueOf(byte)"); |
|
|
|
|
|
|
|
private static final Signature CHARACTER_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Character valueOf(char)"); |
|
|
|
|
|
|
|
private static final Signature DOUBLE_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Double valueOf(double)"); |
|
|
|
|
|
|
|
private static final Signature FLOAT_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Float valueOf(float)"); |
|
|
|
|
|
|
|
private static final Signature INTEGER_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Integer valueOf(int)"); |
|
|
|
|
|
|
|
private static final Signature LONG_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Long valueOf(long)"); |
|
|
|
|
|
|
|
private static final Signature SHORT_VALUE_OF = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("Short valueOf(short)"); |
|
|
|
|
|
|
|
// SPRING PATCH END
|
|
|
|
|
|
|
|
|
|
|
|
private static final Signature BOOLEAN_VALUE = |
|
|
|
private static final Signature BOOLEAN_VALUE = |
|
|
|
TypeUtils.parseSignature("boolean booleanValue()"); |
|
|
|
TypeUtils.parseSignature("boolean booleanValue()"); |
|
|
|
private static final Signature CHAR_VALUE = |
|
|
|
private static final Signature CHAR_VALUE = |
|
|
|
TypeUtils.parseSignature("char charValue()"); |
|
|
|
TypeUtils.parseSignature("char charValue()"); |
|
|
|
private static final Signature LONG_VALUE = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("long longValue()"); |
|
|
|
|
|
|
|
private static final Signature DOUBLE_VALUE = |
|
|
|
private static final Signature DOUBLE_VALUE = |
|
|
|
TypeUtils.parseSignature("double doubleValue()"); |
|
|
|
TypeUtils.parseSignature("double doubleValue()"); |
|
|
|
private static final Signature FLOAT_VALUE = |
|
|
|
private static final Signature FLOAT_VALUE = |
|
|
|
TypeUtils.parseSignature("float floatValue()"); |
|
|
|
TypeUtils.parseSignature("float floatValue()"); |
|
|
|
private static final Signature INT_VALUE = |
|
|
|
private static final Signature INT_VALUE = |
|
|
|
TypeUtils.parseSignature("int intValue()"); |
|
|
|
TypeUtils.parseSignature("int intValue()"); |
|
|
|
|
|
|
|
private static final Signature LONG_VALUE = |
|
|
|
|
|
|
|
TypeUtils.parseSignature("long longValue()"); |
|
|
|
private static final Signature CSTRUCT_NULL = |
|
|
|
private static final Signature CSTRUCT_NULL = |
|
|
|
TypeUtils.parseConstructor(""); |
|
|
|
TypeUtils.parseConstructor(""); |
|
|
|
private static final Signature CSTRUCT_STRING = |
|
|
|
private static final Signature CSTRUCT_STRING = |
|
|
|
@ -54,7 +74,6 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public static final int REM = Constants.IREM; |
|
|
|
public static final int REM = Constants.IREM; |
|
|
|
public static final int AND = Constants.IAND; |
|
|
|
public static final int AND = Constants.IAND; |
|
|
|
public static final int OR = Constants.IOR; |
|
|
|
public static final int OR = Constants.IOR; |
|
|
|
|
|
|
|
|
|
|
|
public static final int GT = Constants.IFGT; |
|
|
|
public static final int GT = Constants.IFGT; |
|
|
|
public static final int LT = Constants.IFLT; |
|
|
|
public static final int LT = Constants.IFLT; |
|
|
|
public static final int GE = Constants.IFGE; |
|
|
|
public static final int GE = Constants.IFGE; |
|
|
|
@ -63,48 +82,9 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public static final int EQ = Constants.IFEQ; |
|
|
|
public static final int EQ = Constants.IFEQ; |
|
|
|
|
|
|
|
|
|
|
|
private ClassEmitter ce; |
|
|
|
private ClassEmitter ce; |
|
|
|
private State state; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class State |
|
|
|
private State state; |
|
|
|
extends MethodInfo |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ClassInfo classInfo; |
|
|
|
|
|
|
|
int access; |
|
|
|
|
|
|
|
Signature sig; |
|
|
|
|
|
|
|
Type[] argumentTypes; |
|
|
|
|
|
|
|
int localOffset; |
|
|
|
|
|
|
|
Type[] exceptionTypes; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
State(ClassInfo classInfo, int access, Signature sig, Type[] exceptionTypes) { |
|
|
|
|
|
|
|
this.classInfo = classInfo; |
|
|
|
|
|
|
|
this.access = access; |
|
|
|
|
|
|
|
this.sig = sig; |
|
|
|
|
|
|
|
this.exceptionTypes = exceptionTypes; |
|
|
|
|
|
|
|
localOffset = TypeUtils.isStatic(access) ? 0 : 1; |
|
|
|
|
|
|
|
argumentTypes = sig.getArgumentTypes(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public ClassInfo getClassInfo() { |
|
|
|
|
|
|
|
return classInfo; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public int getModifiers() { |
|
|
|
|
|
|
|
return access; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Signature getSignature() { |
|
|
|
|
|
|
|
return sig; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Type[] getExceptionTypes() { |
|
|
|
|
|
|
|
return exceptionTypes; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CodeEmitter(ClassEmitter ce, MethodVisitor mv, int access, Signature sig, Type[] exceptionTypes) { |
|
|
|
CodeEmitter(ClassEmitter ce, MethodVisitor mv, int access, Signature sig, Type[] exceptionTypes) { |
|
|
|
super(access, sig.getDescriptor(), mv); |
|
|
|
super(access, sig.getDescriptor(), mv); |
|
|
|
@ -118,6 +98,7 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
this.state = wrap.state; |
|
|
|
this.state = wrap.state; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean isStaticHook() { |
|
|
|
public boolean isStaticHook() { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -156,9 +137,17 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
exception.getInternalName()); |
|
|
|
exception.getInternalName()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void goTo(Label label) { mv.visitJumpInsn(Constants.GOTO, label); } |
|
|
|
public void goTo(Label label) { |
|
|
|
public void ifnull(Label label) { mv.visitJumpInsn(Constants.IFNULL, label); } |
|
|
|
mv.visitJumpInsn(Constants.GOTO, label); |
|
|
|
public void ifnonnull(Label label) { mv.visitJumpInsn(Constants.IFNONNULL, label); } |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void ifnull(Label label) { |
|
|
|
|
|
|
|
mv.visitJumpInsn(Constants.IFNULL, label); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void ifnonnull(Label label) { |
|
|
|
|
|
|
|
mv.visitJumpInsn(Constants.IFNONNULL, label); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void if_jump(int mode, Label label) { |
|
|
|
public void if_jump(int mode, Label label) { |
|
|
|
mv.visitJumpInsn(mode, label); |
|
|
|
mv.visitJumpInsn(mode, label); |
|
|
|
@ -172,8 +161,12 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
int intOp = -1; |
|
|
|
int intOp = -1; |
|
|
|
int jumpmode = mode; |
|
|
|
int jumpmode = mode; |
|
|
|
switch (mode) { |
|
|
|
switch (mode) { |
|
|
|
case GE: jumpmode = LT; break; |
|
|
|
case GE: |
|
|
|
case LE: jumpmode = GT; break; |
|
|
|
jumpmode = LT; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case LE: |
|
|
|
|
|
|
|
jumpmode = GT; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
switch (type.getSort()) { |
|
|
|
switch (type.getSort()) { |
|
|
|
case Type.LONG: |
|
|
|
case Type.LONG: |
|
|
|
@ -198,12 +191,22 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
throw new IllegalArgumentException("Bad comparison for type " + type); |
|
|
|
throw new IllegalArgumentException("Bad comparison for type " + type); |
|
|
|
default: |
|
|
|
default: |
|
|
|
switch (mode) { |
|
|
|
switch (mode) { |
|
|
|
case EQ: intOp = Constants.IF_ICMPEQ; break; |
|
|
|
case EQ: |
|
|
|
case NE: intOp = Constants.IF_ICMPNE; break; |
|
|
|
intOp = Constants.IF_ICMPEQ; |
|
|
|
case GE: swap(); /* fall through */ |
|
|
|
break; |
|
|
|
case LT: intOp = Constants.IF_ICMPLT; break; |
|
|
|
case NE: |
|
|
|
case LE: swap(); /* fall through */ |
|
|
|
intOp = Constants.IF_ICMPNE; |
|
|
|
case GT: intOp = Constants.IF_ICMPGT; break; |
|
|
|
break; |
|
|
|
|
|
|
|
case GE: |
|
|
|
|
|
|
|
swap(); /* fall through */ |
|
|
|
|
|
|
|
case LT: |
|
|
|
|
|
|
|
intOp = Constants.IF_ICMPLT; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case LE: |
|
|
|
|
|
|
|
swap(); /* fall through */ |
|
|
|
|
|
|
|
case GT: |
|
|
|
|
|
|
|
intOp = Constants.IF_ICMPGT; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
mv.visitJumpInsn(intOp, label); |
|
|
|
mv.visitJumpInsn(intOp, label); |
|
|
|
return; |
|
|
|
return; |
|
|
|
@ -211,43 +214,87 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
if_jump(jumpmode, label); |
|
|
|
if_jump(jumpmode, label); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void pop() { mv.visitInsn(Constants.POP); } |
|
|
|
public void pop() { |
|
|
|
public void pop2() { mv.visitInsn(Constants.POP2); } |
|
|
|
mv.visitInsn(Constants.POP); |
|
|
|
public void dup() { mv.visitInsn(Constants.DUP); } |
|
|
|
} |
|
|
|
public void dup2() { mv.visitInsn(Constants.DUP2); } |
|
|
|
|
|
|
|
public void dup_x1() { mv.visitInsn(Constants.DUP_X1); } |
|
|
|
public void pop2() { |
|
|
|
public void dup_x2() { mv.visitInsn(Constants.DUP_X2); } |
|
|
|
mv.visitInsn(Constants.POP2); |
|
|
|
public void dup2_x1() { mv.visitInsn(Constants.DUP2_X1); } |
|
|
|
} |
|
|
|
public void dup2_x2() { mv.visitInsn(Constants.DUP2_X2); } |
|
|
|
|
|
|
|
public void swap() { mv.visitInsn(Constants.SWAP); } |
|
|
|
public void dup() { |
|
|
|
public void aconst_null() { mv.visitInsn(Constants.ACONST_NULL); } |
|
|
|
mv.visitInsn(Constants.DUP); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void dup2() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.DUP2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void dup_x1() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.DUP_X1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void dup_x2() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.DUP_X2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void dup2_x1() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.DUP2_X1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void dup2_x2() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.DUP2_X2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void swap() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.SWAP); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void aconst_null() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.ACONST_NULL); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void swap(Type prev, Type type) { |
|
|
|
public void swap(Type prev, Type type) { |
|
|
|
if (type.getSize() == 1) { |
|
|
|
if (type.getSize() == 1) { |
|
|
|
if (prev.getSize() == 1) { |
|
|
|
if (prev.getSize() == 1) { |
|
|
|
swap(); // same as dup_x1(), pop();
|
|
|
|
swap(); // same as dup_x1(), pop();
|
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
dup_x2(); |
|
|
|
dup_x2(); |
|
|
|
pop(); |
|
|
|
pop(); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
if (prev.getSize() == 1) { |
|
|
|
if (prev.getSize() == 1) { |
|
|
|
dup2_x1(); |
|
|
|
dup2_x1(); |
|
|
|
pop2(); |
|
|
|
pop2(); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
dup2_x2(); |
|
|
|
dup2_x2(); |
|
|
|
pop2(); |
|
|
|
pop2(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void monitorenter() { mv.visitInsn(Constants.MONITORENTER); } |
|
|
|
public void monitorenter() { |
|
|
|
public void monitorexit() { mv.visitInsn(Constants.MONITOREXIT); } |
|
|
|
mv.visitInsn(Constants.MONITORENTER); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void monitorexit() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.MONITOREXIT); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void math(int op, Type type) { |
|
|
|
|
|
|
|
mv.visitInsn(type.getOpcode(op)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void math(int op, Type type) { mv.visitInsn(type.getOpcode(op)); } |
|
|
|
public void array_load(Type type) { |
|
|
|
|
|
|
|
mv.visitInsn(type.getOpcode(Constants.IALOAD)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void array_load(Type type) { mv.visitInsn(type.getOpcode(Constants.IALOAD)); } |
|
|
|
public void array_store(Type type) { |
|
|
|
public void array_store(Type type) { mv.visitInsn(type.getOpcode(Constants.IASTORE)); } |
|
|
|
mv.visitInsn(type.getOpcode(Constants.IASTORE)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Casts from one primitive numeric type to another |
|
|
|
* Casts from one primitive numeric type to another |
|
|
|
@ -257,42 +304,56 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
if (from == Type.DOUBLE_TYPE) { |
|
|
|
if (from == Type.DOUBLE_TYPE) { |
|
|
|
if (to == Type.FLOAT_TYPE) { |
|
|
|
if (to == Type.FLOAT_TYPE) { |
|
|
|
mv.visitInsn(Constants.D2F); |
|
|
|
mv.visitInsn(Constants.D2F); |
|
|
|
} else if (to == Type.LONG_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.LONG_TYPE) { |
|
|
|
mv.visitInsn(Constants.D2L); |
|
|
|
mv.visitInsn(Constants.D2L); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitInsn(Constants.D2I); |
|
|
|
mv.visitInsn(Constants.D2I); |
|
|
|
cast_numeric(Type.INT_TYPE, to); |
|
|
|
cast_numeric(Type.INT_TYPE, to); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (from == Type.FLOAT_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (from == Type.FLOAT_TYPE) { |
|
|
|
if (to == Type.DOUBLE_TYPE) { |
|
|
|
if (to == Type.DOUBLE_TYPE) { |
|
|
|
mv.visitInsn(Constants.F2D); |
|
|
|
mv.visitInsn(Constants.F2D); |
|
|
|
} else if (to == Type.LONG_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.LONG_TYPE) { |
|
|
|
mv.visitInsn(Constants.F2L); |
|
|
|
mv.visitInsn(Constants.F2L); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitInsn(Constants.F2I); |
|
|
|
mv.visitInsn(Constants.F2I); |
|
|
|
cast_numeric(Type.INT_TYPE, to); |
|
|
|
cast_numeric(Type.INT_TYPE, to); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (from == Type.LONG_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (from == Type.LONG_TYPE) { |
|
|
|
if (to == Type.DOUBLE_TYPE) { |
|
|
|
if (to == Type.DOUBLE_TYPE) { |
|
|
|
mv.visitInsn(Constants.L2D); |
|
|
|
mv.visitInsn(Constants.L2D); |
|
|
|
} else if (to == Type.FLOAT_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.FLOAT_TYPE) { |
|
|
|
mv.visitInsn(Constants.L2F); |
|
|
|
mv.visitInsn(Constants.L2F); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitInsn(Constants.L2I); |
|
|
|
mv.visitInsn(Constants.L2I); |
|
|
|
cast_numeric(Type.INT_TYPE, to); |
|
|
|
cast_numeric(Type.INT_TYPE, to); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
if (to == Type.BYTE_TYPE) { |
|
|
|
if (to == Type.BYTE_TYPE) { |
|
|
|
mv.visitInsn(Constants.I2B); |
|
|
|
mv.visitInsn(Constants.I2B); |
|
|
|
} else if (to == Type.CHAR_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.CHAR_TYPE) { |
|
|
|
mv.visitInsn(Constants.I2C); |
|
|
|
mv.visitInsn(Constants.I2C); |
|
|
|
} else if (to == Type.DOUBLE_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.DOUBLE_TYPE) { |
|
|
|
mv.visitInsn(Constants.I2D); |
|
|
|
mv.visitInsn(Constants.I2D); |
|
|
|
} else if (to == Type.FLOAT_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.FLOAT_TYPE) { |
|
|
|
mv.visitInsn(Constants.I2F); |
|
|
|
mv.visitInsn(Constants.I2F); |
|
|
|
} else if (to == Type.LONG_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.LONG_TYPE) { |
|
|
|
mv.visitInsn(Constants.I2L); |
|
|
|
mv.visitInsn(Constants.I2L); |
|
|
|
} else if (to == Type.SHORT_TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (to == Type.SHORT_TYPE) { |
|
|
|
mv.visitInsn(Constants.I2S); |
|
|
|
mv.visitInsn(Constants.I2S); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -302,13 +363,17 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public void push(int i) { |
|
|
|
public void push(int i) { |
|
|
|
if (i < -1) { |
|
|
|
if (i < -1) { |
|
|
|
mv.visitLdcInsn(i); |
|
|
|
mv.visitLdcInsn(i); |
|
|
|
} else if (i <= 5) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (i <= 5) { |
|
|
|
mv.visitInsn(TypeUtils.ICONST(i)); |
|
|
|
mv.visitInsn(TypeUtils.ICONST(i)); |
|
|
|
} else if (i <= Byte.MAX_VALUE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (i <= Byte.MAX_VALUE) { |
|
|
|
mv.visitIntInsn(Constants.BIPUSH, i); |
|
|
|
mv.visitIntInsn(Constants.BIPUSH, i); |
|
|
|
} else if (i <= Short.MAX_VALUE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (i <= Short.MAX_VALUE) { |
|
|
|
mv.visitIntInsn(Constants.SIPUSH, i); |
|
|
|
mv.visitIntInsn(Constants.SIPUSH, i); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitLdcInsn(i); |
|
|
|
mv.visitLdcInsn(i); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -316,7 +381,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public void push(long value) { |
|
|
|
public void push(long value) { |
|
|
|
if (value == 0L || value == 1L) { |
|
|
|
if (value == 0L || value == 1L) { |
|
|
|
mv.visitInsn(TypeUtils.LCONST(value)); |
|
|
|
mv.visitInsn(TypeUtils.LCONST(value)); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitLdcInsn(value); |
|
|
|
mv.visitLdcInsn(value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -324,14 +390,17 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public void push(float value) { |
|
|
|
public void push(float value) { |
|
|
|
if (value == 0f || value == 1f || value == 2f) { |
|
|
|
if (value == 0f || value == 1f || value == 2f) { |
|
|
|
mv.visitInsn(TypeUtils.FCONST(value)); |
|
|
|
mv.visitInsn(TypeUtils.FCONST(value)); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitLdcInsn(value); |
|
|
|
mv.visitLdcInsn(value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void push(double value) { |
|
|
|
public void push(double value) { |
|
|
|
if (value == 0d || value == 1d) { |
|
|
|
if (value == 0d || value == 1d) { |
|
|
|
mv.visitInsn(TypeUtils.DCONST(value)); |
|
|
|
mv.visitInsn(TypeUtils.DCONST(value)); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
mv.visitLdcInsn(value); |
|
|
|
mv.visitLdcInsn(value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -347,7 +416,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public void newarray(Type type) { |
|
|
|
public void newarray(Type type) { |
|
|
|
if (TypeUtils.isPrimitive(type)) { |
|
|
|
if (TypeUtils.isPrimitive(type)) { |
|
|
|
mv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type)); |
|
|
|
mv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type)); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
emit_type(Constants.ANEWARRAY, type); |
|
|
|
emit_type(Constants.ANEWARRAY, type); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -372,6 +442,7 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Pushes the specified argument of the current method onto the stack. |
|
|
|
* Pushes the specified argument of the current method onto the stack. |
|
|
|
|
|
|
|
* |
|
|
|
* @param index the zero-based index into the argument list |
|
|
|
* @param index the zero-based index into the argument list |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void load_arg(int index) { |
|
|
|
public void load_arg(int index) { |
|
|
|
@ -557,7 +628,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
String desc; |
|
|
|
String desc; |
|
|
|
if (TypeUtils.isArray(type)) { |
|
|
|
if (TypeUtils.isArray(type)) { |
|
|
|
desc = type.getDescriptor(); |
|
|
|
desc = type.getDescriptor(); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
desc = type.getInternalName(); |
|
|
|
desc = type.getInternalName(); |
|
|
|
} |
|
|
|
} |
|
|
|
mv.visitTypeInsn(opcode, desc); |
|
|
|
mv.visitTypeInsn(opcode, desc); |
|
|
|
@ -568,9 +640,17 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
aaload(); |
|
|
|
aaload(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void aaload() { mv.visitInsn(Constants.AALOAD); } |
|
|
|
public void aaload() { |
|
|
|
public void aastore() { mv.visitInsn(Constants.AASTORE); } |
|
|
|
mv.visitInsn(Constants.AALOAD); |
|
|
|
public void athrow() { mv.visitInsn(Constants.ATHROW); } |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void aastore() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.AASTORE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void athrow() { |
|
|
|
|
|
|
|
mv.visitInsn(Constants.ATHROW); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public Label make_label() { |
|
|
|
public Label make_label() { |
|
|
|
return new Label(); |
|
|
|
return new Label(); |
|
|
|
@ -606,7 +686,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
float density; |
|
|
|
float density; |
|
|
|
if (keys.length == 0) { |
|
|
|
if (keys.length == 0) { |
|
|
|
density = 0; |
|
|
|
density = 0; |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1); |
|
|
|
density = (float) keys.length / (keys[keys.length - 1] - keys[0] + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
process_switch(keys, callback, density >= 0.5f); |
|
|
|
process_switch(keys, callback, density >= 0.5f); |
|
|
|
@ -640,7 +721,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
callback.processCase(i + min, end); |
|
|
|
callback.processCase(i + min, end); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
Label[] labels = new Label[len]; |
|
|
|
Label[] labels = new Label[len]; |
|
|
|
for (int i = 0; i < len; i++) { |
|
|
|
for (int i = 0; i < len; i++) { |
|
|
|
labels[i] = make_label(); |
|
|
|
labels[i] = make_label(); |
|
|
|
@ -657,9 +739,11 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
callback.processDefault(); |
|
|
|
callback.processDefault(); |
|
|
|
mark(end); |
|
|
|
mark(end); |
|
|
|
|
|
|
|
|
|
|
|
} catch (RuntimeException | Error e) { |
|
|
|
} |
|
|
|
|
|
|
|
catch (RuntimeException | Error e) { |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} catch (Exception e) { |
|
|
|
} |
|
|
|
|
|
|
|
catch (Exception e) { |
|
|
|
throw new CodeGenerationException(e); |
|
|
|
throw new CodeGenerationException(e); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -705,16 +789,45 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* If the argument is a primitive class, replaces the primitive value |
|
|
|
* If the argument is a primitive class, replaces the primitive value |
|
|
|
* on the top of the stack with the wrapped (Object) equivalent. For |
|
|
|
* on the top of the stack with the wrapped (Object) equivalent using valueOf() methods. |
|
|
|
* example, char -> Character. |
|
|
|
* For example, char -> Character. |
|
|
|
* If the class is Void, a null is pushed onto the stack instead. |
|
|
|
* If the class is Void, a null is pushed onto the stack instead. |
|
|
|
|
|
|
|
* |
|
|
|
* @param type the class indicating the current type of the top stack value |
|
|
|
* @param type the class indicating the current type of the top stack value |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void box(Type type) { |
|
|
|
public void box(Type type) { |
|
|
|
if (TypeUtils.isPrimitive(type)) { |
|
|
|
if (TypeUtils.isPrimitive(type)) { |
|
|
|
if (type == Type.VOID_TYPE) { |
|
|
|
switch (type.getSort()) { |
|
|
|
|
|
|
|
case Type.VOID: |
|
|
|
aconst_null(); |
|
|
|
aconst_null(); |
|
|
|
} else { |
|
|
|
break; |
|
|
|
|
|
|
|
// SPRING PATCH BEGIN
|
|
|
|
|
|
|
|
case Type.CHAR: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_CHARACTER, CHARACTER_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.BOOLEAN: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_BOOLEAN, BOOLEAN_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.DOUBLE: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_DOUBLE, DOUBLE_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.FLOAT: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_FLOAT, FLOAT_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.LONG: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_LONG, LONG_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.INT: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_INTEGER, INTEGER_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.SHORT: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_SHORT, SHORT_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case Type.BYTE: |
|
|
|
|
|
|
|
invoke_static(Constants.TYPE_BYTE, BYTE_VALUE_OF); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
// SPRING PATCH END
|
|
|
|
|
|
|
|
default: |
|
|
|
Type boxed = TypeUtils.getBoxedType(type); |
|
|
|
Type boxed = TypeUtils.getBoxedType(type); |
|
|
|
new_instance(boxed); |
|
|
|
new_instance(boxed); |
|
|
|
if (type.getSize() == 2) { |
|
|
|
if (type.getSize() == 2) { |
|
|
|
@ -722,7 +835,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
dup_x2(); |
|
|
|
dup_x2(); |
|
|
|
dup_x2(); |
|
|
|
dup_x2(); |
|
|
|
pop(); |
|
|
|
pop(); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
// p -> po -> opo -> oop -> o
|
|
|
|
// p -> po -> opo -> oop -> o
|
|
|
|
dup_x1(); |
|
|
|
dup_x1(); |
|
|
|
swap(); |
|
|
|
swap(); |
|
|
|
@ -736,6 +850,7 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
* If the argument is a primitive class, replaces the object |
|
|
|
* If the argument is a primitive class, replaces the object |
|
|
|
* on the top of the stack with the unwrapped (primitive) |
|
|
|
* on the top of the stack with the unwrapped (primitive) |
|
|
|
* equivalent. For example, Character -> char. |
|
|
|
* equivalent. For example, Character -> char. |
|
|
|
|
|
|
|
* |
|
|
|
* @param type the class indicating the desired type of the top stack value |
|
|
|
* @param type the class indicating the desired type of the top stack value |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void unbox(Type type) { |
|
|
|
public void unbox(Type type) { |
|
|
|
@ -769,7 +884,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
|
|
|
|
|
|
|
|
if (sig == null) { |
|
|
|
if (sig == null) { |
|
|
|
checkcast(type); |
|
|
|
checkcast(type); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
checkcast(t); |
|
|
|
checkcast(t); |
|
|
|
invoke_virtual(t, sig); |
|
|
|
invoke_virtual(t, sig); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -817,7 +933,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
default: |
|
|
|
default: |
|
|
|
push(0); |
|
|
|
push(0); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
aconst_null(); |
|
|
|
aconst_null(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -840,7 +957,8 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
unbox(type); |
|
|
|
unbox(type); |
|
|
|
mark(end); |
|
|
|
mark(end); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
checkcast(type); |
|
|
|
checkcast(type); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -858,11 +976,14 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
Signature sig = method.getSignature(); |
|
|
|
Signature sig = method.getSignature(); |
|
|
|
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) { |
|
|
|
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) { |
|
|
|
invoke_constructor(type, sig); |
|
|
|
invoke_constructor(type, sig); |
|
|
|
} else if (TypeUtils.isStatic(method.getModifiers())) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (TypeUtils.isStatic(method.getModifiers())) { |
|
|
|
invoke_static(type, sig, TypeUtils.isInterface(classInfo.getModifiers())); |
|
|
|
invoke_static(type, sig, TypeUtils.isInterface(classInfo.getModifiers())); |
|
|
|
} else if (TypeUtils.isInterface(classInfo.getModifiers())) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (TypeUtils.isInterface(classInfo.getModifiers())) { |
|
|
|
invoke_interface(type, sig); |
|
|
|
invoke_interface(type, sig); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
invoke_virtual(virtualType, sig); |
|
|
|
invoke_virtual(virtualType, sig); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -870,4 +991,50 @@ public class CodeEmitter extends LocalVariablesSorter { |
|
|
|
public void invoke(MethodInfo method) { |
|
|
|
public void invoke(MethodInfo method) { |
|
|
|
invoke(method, method.getClassInfo().getType()); |
|
|
|
invoke(method, method.getClassInfo().getType()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class State extends MethodInfo { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ClassInfo classInfo; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int access; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Signature sig; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Type[] argumentTypes; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int localOffset; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Type[] exceptionTypes; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
State(ClassInfo classInfo, int access, Signature sig, Type[] exceptionTypes) { |
|
|
|
|
|
|
|
this.classInfo = classInfo; |
|
|
|
|
|
|
|
this.access = access; |
|
|
|
|
|
|
|
this.sig = sig; |
|
|
|
|
|
|
|
this.exceptionTypes = exceptionTypes; |
|
|
|
|
|
|
|
localOffset = TypeUtils.isStatic(access) ? 0 : 1; |
|
|
|
|
|
|
|
argumentTypes = sig.getArgumentTypes(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public ClassInfo getClassInfo() { |
|
|
|
|
|
|
|
return classInfo; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public int getModifiers() { |
|
|
|
|
|
|
|
return access; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Signature getSignature() { |
|
|
|
|
|
|
|
return sig; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Type[] getExceptionTypes() { |
|
|
|
|
|
|
|
return exceptionTypes; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|