下面列出了org.objectweb.asm.Opcodes# LCMP 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
static Collection<MethodNode> mangleComparisions(ClassNode cn, MethodNode node) {
HashMap<Integer, MethodNode> comparisionMethodMap = new HashMap<>();
for (AbstractInsnNode insnNode : node.instructions.toArray()) {
if (insnNode.getOpcode() >= Opcodes.LCMP && insnNode.getOpcode() <= Opcodes.DCMPG) {
if (!comparisionMethodMap.containsKey(insnNode.getOpcode())) {
comparisionMethodMap.put(insnNode.getOpcode(), generateComparisionMethod(cn, insnNode.getOpcode()));
}
MethodNode comparisionMethod = comparisionMethodMap.get(insnNode.getOpcode());
// Invokes the comparision method instead of the comparision opcode
// e.g: invokestatic Test.compare:(DD)I
node.instructions.insert(insnNode, new MethodInsnNode(Opcodes.INVOKESTATIC, cn.name, comparisionMethod.name, comparisionMethod.desc, false));
node.instructions.remove(insnNode);
}
}
return comparisionMethodMap.values();
}
/**
* Generates a method that looks like this:
* <p>
* private static int compare(double, double);
* Flags: PRIVATE, STATIC
* Code:
* 0: dload_0
* 1: dload_2
* 2: dcmpl (<--- The opcode)
* 3: ireturn
*
* @param cn The ClassNode the method is supposed to be
* @param opcode the comparision opcode. Allowed opcodes: LCMP, FCMPL, FCMPG, DCMPL, DCMPG
* @return The method node
*/
private static MethodNode generateComparisionMethod(ClassNode cn, int opcode) {
if (!(opcode >= Opcodes.LCMP && opcode <= Opcodes.DCMPG))
throw new IllegalArgumentException("The opcode must be LCMP, FCMPL, FCMPG, DCMPL or DCMPG");
// The type of numbers which are compared
Type type = opcode == Opcodes.LCMP ? Type.LONG_TYPE : (opcode == Opcodes.FCMPG || opcode == Opcodes.FCMPL) ? Type.FLOAT_TYPE : Type.DOUBLE_TYPE;
String desc = "(" + type.toString() + type.toString() + ")I";
MethodNode methodNode = new MethodNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, NameUtils.generateMethodName(cn, desc), desc, null, new String[0]);
methodNode.instructions = new InsnList();
methodNode.instructions.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), 0));
methodNode.instructions.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), type.getSize()));
methodNode.instructions.add(new InsnNode(opcode));
methodNode.instructions.add(new InsnNode(Opcodes.IRETURN));
return methodNode;
}
private boolean matchesConditionalInsn(int last, AbstractInsnNode insn) {
for (int conditionalOpcode : this.expandOpcodes) {
int opcode = insn.getOpcode();
if (opcode == conditionalOpcode) {
if (last == Opcodes.LCMP || last == Opcodes.FCMPL || last == Opcodes.FCMPG || last == Opcodes.DCMPL || last == Opcodes.DCMPG) {
this.log(" BeforeConstant is ignoring {} following {}", Bytecode.getOpcodeName(opcode), Bytecode.getOpcodeName(last));
return false;
}
this.log(" BeforeConstant found {} instruction", Bytecode.getOpcodeName(opcode));
return true;
}
}
if (this.intValue != null && this.intValue.intValue() == 0 && Bytecode.isConstant(insn)) {
Object value = Bytecode.getConstant(insn);
this.log(" BeforeConstant found INTEGER constant: value = {}", value);
return value instanceof Integer && ((Integer)value).intValue() == 0;
}
return false;
}
@Override
public EvaluationFunctor<Number> compare(Type lt, Type rt, ComparisonExpr.ValueComparisonType type) {
String name = lt.getClassName() + type.name() + rt.getClassName() + "RETint";
if(cache.containsKey(name)) {
return _get(name);
}
String desc = "(" + lt.getDescriptor() + rt.getDescriptor() + ")I";
MethodNode m = makeBase(name, desc);
{
Type opType = TypeUtils.resolveBinOpType(lt, rt);
InsnList insns = new InsnList();
insns.add(new VarInsnNode(TypeUtils.getVariableLoadOpcode(lt), 0));
cast(insns, lt, opType);
insns.add(new VarInsnNode(TypeUtils.getVariableLoadOpcode(rt), lt.getSize()));
cast(insns, rt, opType);
int op;
if (opType == Type.DOUBLE_TYPE) {
op = type == ComparisonExpr.ValueComparisonType.GT ? Opcodes.DCMPG : Opcodes.DCMPL;
} else if (opType == Type.FLOAT_TYPE) {
op = type == ComparisonExpr.ValueComparisonType.GT ? Opcodes.FCMPG : Opcodes.FCMPL;
} else if (opType == Type.LONG_TYPE) {
op = Opcodes.LCMP;
} else {
throw new IllegalArgumentException();
}
insns.add(new InsnNode(op));
insns.add(new InsnNode(Opcodes.IRETURN));
m.node.instructions = insns;
}
return buildBridge(m);
}
public InsnValue compareConstants(AbstractInsnNode insn, InsnValue value1, InsnValue value2) {
Object o = value1.getValue(), oo = value2.getValue();
if (o == null || oo == null) {
// Can't compare since the values haven't been resolved.
return InsnValue.INT_VALUE;
}
int v = 0;
switch (insn.getOpcode()) {
case Opcodes.LCMP:
long l1 = (long) o, l2 = (long) oo;
v = (l1 == l2) ? 0 : (l2 < l1) ? 1 : -1;
break;
case Opcodes.FCMPL:
case Opcodes.FCMPG:
float f1 = (float) o, f2 = (float) oo;
if (f1 == Float.NaN || f2 == Float.NaN) {
v = insn.getOpcode() == Opcodes.FCMPG ? -1 : 1;
} else {
v = (f1 == f2) ? 0 : (f2 < f1) ? 1 : -1;
}
break;
case Opcodes.DCMPL:
case Opcodes.DCMPG:
double d1 = (float) o, d2 = (double) oo;
if (d1 == Float.NaN || d2 == Float.NaN) {
v = insn.getOpcode() == Opcodes.DCMPG ? -1 : 1;
} else {
v = (d1 == d2) ? 0 : (d2 < d1) ? 1 : -1;
}
break;
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPNE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
int i1 = (int) o, i2 = (int) oo;
switch (insn.getOpcode()) {
case Opcodes.IF_ICMPEQ:
v = i2 == i1 ? 1 : 0;
break;
case Opcodes.IF_ICMPNE:
v = i2 != i1 ? 1 : 0;
break;
case Opcodes.IF_ICMPLT:
v = i2 < i1 ? 1 : 0;
break;
case Opcodes.IF_ICMPLE:
v = i2 <= i1 ? 1 : 0;
break;
case Opcodes.IF_ICMPGE:
v = i2 >= i1 ? 1 : 0;
break;
case Opcodes.IF_ICMPGT:
v = i2 > i1 ? 1 : 0;
break;
}
break;
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
v = ((insn.getOpcode() == Opcodes.IF_ACMPNE) ? !o.equals(oo) : o.equals(oo)) ? 1 : 0;
break;
}
return InsnValue.intValue(v);
}
private List<AbstractInsnNode> getPossibleInsns(AbstractInsnNode ain)
{
List<AbstractInsnNode> instrs = new ArrayList<>();
while(ain != null)
{
if(ain instanceof LineNumberNode || ain instanceof FrameNode)
{
ain = ain.getNext();
continue;
}
instrs.add(ain);
if(instrs.size() >= 23)
break;
ain = ain.getNext();
}
if(instrs.size() == 23 && instrs.get(0).getOpcode() == Opcodes.ILOAD
&& instrs.get(1).getOpcode() == Opcodes.ICONST_1
&& instrs.get(2).getOpcode() == Opcodes.ISUB
&& instrs.get(3).getOpcode() == Opcodes.ISTORE)
{
int var1 = ((VarInsnNode)instrs.get(0)).var;
int var2 = ((VarInsnNode)instrs.get(3)).var;
if(instrs.get(4).getOpcode() == Opcodes.ILOAD
&& ((VarInsnNode)instrs.get(4)).var == var1
&& instrs.get(5).getOpcode() == Opcodes.ILOAD
&& ((VarInsnNode)instrs.get(5)).var == var2
&& instrs.get(6).getOpcode() == Opcodes.IMUL
&& instrs.get(7).getOpcode() == Opcodes.ISTORE
&& ((VarInsnNode)instrs.get(7)).var == var2
&& instrs.get(8).getOpcode() == Opcodes.ILOAD
&& ((VarInsnNode)instrs.get(8)).var == var2
&& instrs.get(9).getOpcode() == Opcodes.ICONST_2
&& instrs.get(10).getOpcode() == Opcodes.IREM
&& instrs.get(11).getOpcode() == Opcodes.ISTORE
&& ((VarInsnNode)instrs.get(11)).var == var2
&& instrs.get(12).getOpcode() == Opcodes.ILOAD
&& ((VarInsnNode)instrs.get(12)).var == var2
&& instrs.get(13).getOpcode() == Opcodes.I2L
&& instrs.get(14).getOpcode() == Opcodes.ICONST_0
&& instrs.get(15).getOpcode() == Opcodes.I2L
&& instrs.get(16).getOpcode() == Opcodes.LCMP
&& instrs.get(17).getOpcode() == Opcodes.ICONST_1
&& instrs.get(18).getOpcode() == Opcodes.IXOR
&& instrs.get(19).getOpcode() == Opcodes.ICONST_1
&& instrs.get(20).getOpcode() == Opcodes.IAND
&& instrs.get(21).getOpcode() == Opcodes.IFEQ
&& instrs.get(22).getOpcode() == Opcodes.IINC)
return instrs;
}
return null;
}
public static boolean isBinaryOp(Instruction instr) {
switch (instr.getOpcode()) {
case Opcodes.ISHL:
case Opcodes.ISHR:
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.IUSHR:
case Opcodes.LUSHR:
case Opcodes.DCMPG:
case Opcodes.DCMPL:
case Opcodes.FCMPG:
case Opcodes.FCMPL:
case Opcodes.LCMP:
case Opcodes.IOR:
case Opcodes.LOR:
case Opcodes.IXOR:
case Opcodes.LXOR:
case Opcodes.IAND:
case Opcodes.LAND:
case Opcodes.FADD:
case Opcodes.DADD:
case Opcodes.IADD:
case Opcodes.LADD:
case Opcodes.FSUB:
case Opcodes.DSUB:
case Opcodes.ISUB:
case Opcodes.LSUB:
case Opcodes.FDIV:
case Opcodes.DDIV:
case Opcodes.LDIV:
case Opcodes.IDIV:
case Opcodes.IREM:
case Opcodes.FREM:
case Opcodes.DREM:
case Opcodes.LREM:
case Opcodes.FMUL:
case Opcodes.DMUL:
case Opcodes.IMUL:
case Opcodes.LMUL:
return true;
}
return false;
}
public static boolean isArithmeticOp(Instruction instr) {
switch (instr.getOpcode()) {
case Opcodes.ISHL:
case Opcodes.ISHR:
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.IUSHR:
case Opcodes.LUSHR:
case Opcodes.DCMPG:
case Opcodes.DCMPL:
case Opcodes.FCMPG:
case Opcodes.FCMPL:
case Opcodes.LCMP:
case Opcodes.FNEG:
case Opcodes.DNEG:
case Opcodes.INEG:
case Opcodes.D2F:
case Opcodes.D2I:
case Opcodes.D2L:
case Opcodes.F2D:
case Opcodes.F2I:
case Opcodes.F2L:
case Opcodes.L2D:
case Opcodes.L2F:
case Opcodes.L2I:
case Opcodes.I2L:
case Opcodes.I2B:
case Opcodes.I2C:
case Opcodes.I2D:
case Opcodes.I2F:
case Opcodes.I2S:
case Opcodes.IOR:
case Opcodes.LOR:
case Opcodes.IXOR:
case Opcodes.LXOR:
case Opcodes.IAND:
case Opcodes.LAND:
case Opcodes.FADD:
case Opcodes.DADD:
case Opcodes.IADD:
case Opcodes.LADD:
case Opcodes.FSUB:
case Opcodes.DSUB:
case Opcodes.ISUB:
case Opcodes.LSUB:
case Opcodes.FDIV:
case Opcodes.DDIV:
case Opcodes.LDIV:
case Opcodes.IDIV:
case Opcodes.IREM:
case Opcodes.FREM:
case Opcodes.DREM:
case Opcodes.LREM:
case Opcodes.FMUL:
case Opcodes.DMUL:
case Opcodes.IMUL:
case Opcodes.LMUL:
return true;
}
return false;
}