forked from openrs2/openrs2
parent
fdcc5a217f
commit
8020ac98ab
@ -1,335 +0,0 @@ |
|||||||
package dev.openrs2.asm; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.io.PrintWriter; |
|
||||||
import java.io.StringWriter; |
|
||||||
import java.io.UncheckedIOException; |
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes; |
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode; |
|
||||||
import org.objectweb.asm.tree.InsnNode; |
|
||||||
import org.objectweb.asm.tree.IntInsnNode; |
|
||||||
import org.objectweb.asm.tree.LdcInsnNode; |
|
||||||
import org.objectweb.asm.util.Textifier; |
|
||||||
import org.objectweb.asm.util.TraceMethodVisitor; |
|
||||||
|
|
||||||
public final class InsnNodeUtils { |
|
||||||
public static AbstractInsnNode nextReal(AbstractInsnNode insn) { |
|
||||||
while ((insn = insn.getNext()) != null && insn.getOpcode() == -1) { |
|
||||||
/* empty */ |
|
||||||
} |
|
||||||
return insn; |
|
||||||
} |
|
||||||
|
|
||||||
public static AbstractInsnNode previousReal(AbstractInsnNode insn) { |
|
||||||
while ((insn = insn.getPrevious()) != null && insn.getOpcode() == -1) { |
|
||||||
/* empty */ |
|
||||||
} |
|
||||||
return insn; |
|
||||||
} |
|
||||||
|
|
||||||
public static AbstractInsnNode nextVirtual(AbstractInsnNode insn) { |
|
||||||
while ((insn = insn.getNext()) != null && insn.getOpcode() != -1) { |
|
||||||
/* empty */ |
|
||||||
} |
|
||||||
return insn; |
|
||||||
} |
|
||||||
|
|
||||||
public static AbstractInsnNode previousVirtual(AbstractInsnNode insn) { |
|
||||||
while ((insn = insn.getPrevious()) != null && insn.getOpcode() != -1) { |
|
||||||
/* empty */ |
|
||||||
} |
|
||||||
return insn; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isIntConstant(AbstractInsnNode insn) { |
|
||||||
switch (insn.getOpcode()) { |
|
||||||
case Opcodes.ICONST_M1: |
|
||||||
case Opcodes.ICONST_0: |
|
||||||
case Opcodes.ICONST_1: |
|
||||||
case Opcodes.ICONST_2: |
|
||||||
case Opcodes.ICONST_3: |
|
||||||
case Opcodes.ICONST_4: |
|
||||||
case Opcodes.ICONST_5: |
|
||||||
case Opcodes.BIPUSH: |
|
||||||
case Opcodes.SIPUSH: |
|
||||||
return true; |
|
||||||
case Opcodes.LDC: |
|
||||||
var ldc = (LdcInsnNode) insn; |
|
||||||
return ldc.cst instanceof Integer; |
|
||||||
} |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public static int getIntConstant(AbstractInsnNode insn) { |
|
||||||
switch (insn.getOpcode()) { |
|
||||||
case Opcodes.ICONST_M1: |
|
||||||
return -1; |
|
||||||
case Opcodes.ICONST_0: |
|
||||||
return 0; |
|
||||||
case Opcodes.ICONST_1: |
|
||||||
return 1; |
|
||||||
case Opcodes.ICONST_2: |
|
||||||
return 2; |
|
||||||
case Opcodes.ICONST_3: |
|
||||||
return 3; |
|
||||||
case Opcodes.ICONST_4: |
|
||||||
return 4; |
|
||||||
case Opcodes.ICONST_5: |
|
||||||
return 5; |
|
||||||
case Opcodes.BIPUSH: |
|
||||||
case Opcodes.SIPUSH: |
|
||||||
var intInsn = (IntInsnNode) insn; |
|
||||||
return intInsn.operand; |
|
||||||
case Opcodes.LDC: |
|
||||||
var ldc = (LdcInsnNode) insn; |
|
||||||
if (ldc.cst instanceof Integer) { |
|
||||||
return (Integer) ldc.cst; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
throw new IllegalArgumentException(); |
|
||||||
} |
|
||||||
|
|
||||||
public static AbstractInsnNode createIntConstant(int value) { |
|
||||||
switch (value) { |
|
||||||
case -1: |
|
||||||
return new InsnNode(Opcodes.ICONST_M1); |
|
||||||
case 0: |
|
||||||
return new InsnNode(Opcodes.ICONST_0); |
|
||||||
case 1: |
|
||||||
return new InsnNode(Opcodes.ICONST_1); |
|
||||||
case 2: |
|
||||||
return new InsnNode(Opcodes.ICONST_2); |
|
||||||
case 3: |
|
||||||
return new InsnNode(Opcodes.ICONST_3); |
|
||||||
case 4: |
|
||||||
return new InsnNode(Opcodes.ICONST_4); |
|
||||||
case 5: |
|
||||||
return new InsnNode(Opcodes.ICONST_5); |
|
||||||
} |
|
||||||
|
|
||||||
if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { |
|
||||||
return new IntInsnNode(Opcodes.BIPUSH, value); |
|
||||||
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { |
|
||||||
return new IntInsnNode(Opcodes.SIPUSH, value); |
|
||||||
} else { |
|
||||||
return new LdcInsnNode(value); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isPure(AbstractInsnNode insn) { |
|
||||||
var opcode = insn.getOpcode(); |
|
||||||
switch (opcode) { |
|
||||||
case -1: |
|
||||||
case Opcodes.NOP: |
|
||||||
case Opcodes.ACONST_NULL: |
|
||||||
case Opcodes.ICONST_M1: |
|
||||||
case Opcodes.ICONST_0: |
|
||||||
case Opcodes.ICONST_1: |
|
||||||
case Opcodes.ICONST_2: |
|
||||||
case Opcodes.ICONST_3: |
|
||||||
case Opcodes.ICONST_4: |
|
||||||
case Opcodes.ICONST_5: |
|
||||||
case Opcodes.LCONST_0: |
|
||||||
case Opcodes.LCONST_1: |
|
||||||
case Opcodes.FCONST_0: |
|
||||||
case Opcodes.FCONST_1: |
|
||||||
case Opcodes.FCONST_2: |
|
||||||
case Opcodes.DCONST_0: |
|
||||||
case Opcodes.DCONST_1: |
|
||||||
case Opcodes.BIPUSH: |
|
||||||
case Opcodes.SIPUSH: |
|
||||||
case Opcodes.LDC: |
|
||||||
case Opcodes.ILOAD: |
|
||||||
case Opcodes.LLOAD: |
|
||||||
case Opcodes.FLOAD: |
|
||||||
case Opcodes.DLOAD: |
|
||||||
case Opcodes.ALOAD: |
|
||||||
return true; |
|
||||||
case Opcodes.IALOAD: |
|
||||||
case Opcodes.LALOAD: |
|
||||||
case Opcodes.FALOAD: |
|
||||||
case Opcodes.DALOAD: |
|
||||||
case Opcodes.AALOAD: |
|
||||||
case Opcodes.BALOAD: |
|
||||||
case Opcodes.CALOAD: |
|
||||||
case Opcodes.SALOAD: |
|
||||||
/* might throw NPE or index out of bounds exception */ |
|
||||||
case Opcodes.ISTORE: |
|
||||||
case Opcodes.LSTORE: |
|
||||||
case Opcodes.FSTORE: |
|
||||||
case Opcodes.DSTORE: |
|
||||||
case Opcodes.ASTORE: |
|
||||||
case Opcodes.IASTORE: |
|
||||||
case Opcodes.LASTORE: |
|
||||||
case Opcodes.FASTORE: |
|
||||||
case Opcodes.DASTORE: |
|
||||||
case Opcodes.AASTORE: |
|
||||||
case Opcodes.BASTORE: |
|
||||||
case Opcodes.CASTORE: |
|
||||||
case Opcodes.SASTORE: |
|
||||||
return false; |
|
||||||
case Opcodes.POP: |
|
||||||
case Opcodes.POP2: |
|
||||||
case Opcodes.DUP: |
|
||||||
case Opcodes.DUP_X1: |
|
||||||
case Opcodes.DUP_X2: |
|
||||||
case Opcodes.DUP2: |
|
||||||
case Opcodes.DUP2_X1: |
|
||||||
case Opcodes.DUP2_X2: |
|
||||||
case Opcodes.SWAP: |
|
||||||
case Opcodes.IADD: |
|
||||||
case Opcodes.LADD: |
|
||||||
case Opcodes.FADD: |
|
||||||
case Opcodes.DADD: |
|
||||||
case Opcodes.ISUB: |
|
||||||
case Opcodes.LSUB: |
|
||||||
case Opcodes.FSUB: |
|
||||||
case Opcodes.DSUB: |
|
||||||
case Opcodes.IMUL: |
|
||||||
case Opcodes.LMUL: |
|
||||||
case Opcodes.FMUL: |
|
||||||
case Opcodes.DMUL: |
|
||||||
case Opcodes.IDIV: |
|
||||||
case Opcodes.LDIV: |
|
||||||
case Opcodes.FDIV: |
|
||||||
case Opcodes.DDIV: |
|
||||||
case Opcodes.IREM: |
|
||||||
case Opcodes.LREM: |
|
||||||
case Opcodes.FREM: |
|
||||||
case Opcodes.DREM: |
|
||||||
/* |
|
||||||
* XXX(gpe): strictly speaking the *DIV and *REM instructions have |
|
||||||
* side effects (unless we can prove that the second argument is |
|
||||||
* non-zero). However, treating them as having side effects reduces |
|
||||||
* the number of dummy variables we can remove, so we pretend they |
|
||||||
* don't have any side effects. |
|
||||||
* |
|
||||||
* This doesn't seem to cause any problems with the client, as it |
|
||||||
* doesn't deliberately try to trigger divide-by-zero exceptions. |
|
||||||
*/ |
|
||||||
case Opcodes.INEG: |
|
||||||
case Opcodes.LNEG: |
|
||||||
case Opcodes.FNEG: |
|
||||||
case Opcodes.DNEG: |
|
||||||
case Opcodes.ISHL: |
|
||||||
case Opcodes.LSHL: |
|
||||||
case Opcodes.ISHR: |
|
||||||
case Opcodes.LSHR: |
|
||||||
case Opcodes.IUSHR: |
|
||||||
case Opcodes.LUSHR: |
|
||||||
case Opcodes.IAND: |
|
||||||
case Opcodes.LAND: |
|
||||||
case Opcodes.IOR: |
|
||||||
case Opcodes.LOR: |
|
||||||
case Opcodes.IXOR: |
|
||||||
case Opcodes.LXOR: |
|
||||||
return true; |
|
||||||
case Opcodes.IINC: |
|
||||||
return false; |
|
||||||
case Opcodes.I2L: |
|
||||||
case Opcodes.I2F: |
|
||||||
case Opcodes.I2D: |
|
||||||
case Opcodes.L2I: |
|
||||||
case Opcodes.L2F: |
|
||||||
case Opcodes.L2D: |
|
||||||
case Opcodes.F2I: |
|
||||||
case Opcodes.F2L: |
|
||||||
case Opcodes.F2D: |
|
||||||
case Opcodes.D2I: |
|
||||||
case Opcodes.D2L: |
|
||||||
case Opcodes.D2F: |
|
||||||
case Opcodes.I2B: |
|
||||||
case Opcodes.I2C: |
|
||||||
case Opcodes.I2S: |
|
||||||
case Opcodes.LCMP: |
|
||||||
case Opcodes.FCMPL: |
|
||||||
case Opcodes.FCMPG: |
|
||||||
case Opcodes.DCMPL: |
|
||||||
case Opcodes.DCMPG: |
|
||||||
return true; |
|
||||||
case Opcodes.IFEQ: |
|
||||||
case Opcodes.IFNE: |
|
||||||
case Opcodes.IFLT: |
|
||||||
case Opcodes.IFGE: |
|
||||||
case Opcodes.IFGT: |
|
||||||
case Opcodes.IFLE: |
|
||||||
case Opcodes.IF_ICMPEQ: |
|
||||||
case Opcodes.IF_ICMPNE: |
|
||||||
case Opcodes.IF_ICMPLT: |
|
||||||
case Opcodes.IF_ICMPGE: |
|
||||||
case Opcodes.IF_ICMPGT: |
|
||||||
case Opcodes.IF_ICMPLE: |
|
||||||
case Opcodes.IF_ACMPEQ: |
|
||||||
case Opcodes.IF_ACMPNE: |
|
||||||
case Opcodes.GOTO: |
|
||||||
case Opcodes.JSR: |
|
||||||
case Opcodes.RET: |
|
||||||
case Opcodes.TABLESWITCH: |
|
||||||
case Opcodes.LOOKUPSWITCH: |
|
||||||
case Opcodes.IRETURN: |
|
||||||
case Opcodes.LRETURN: |
|
||||||
case Opcodes.FRETURN: |
|
||||||
case Opcodes.DRETURN: |
|
||||||
case Opcodes.ARETURN: |
|
||||||
case Opcodes.RETURN: |
|
||||||
return false; |
|
||||||
case Opcodes.GETSTATIC: |
|
||||||
return true; |
|
||||||
case Opcodes.PUTSTATIC: |
|
||||||
case Opcodes.GETFIELD: |
|
||||||
/* might throw NPE */ |
|
||||||
case Opcodes.PUTFIELD: |
|
||||||
return false; |
|
||||||
case Opcodes.INVOKEVIRTUAL: |
|
||||||
case Opcodes.INVOKESPECIAL: |
|
||||||
case Opcodes.INVOKESTATIC: |
|
||||||
case Opcodes.INVOKEINTERFACE: |
|
||||||
case Opcodes.INVOKEDYNAMIC: |
|
||||||
return false; |
|
||||||
case Opcodes.NEW: |
|
||||||
return true; |
|
||||||
case Opcodes.NEWARRAY: |
|
||||||
case Opcodes.ANEWARRAY: |
|
||||||
/* arrays might be created with negative size */ |
|
||||||
case Opcodes.ARRAYLENGTH: |
|
||||||
/* might throw NPE */ |
|
||||||
case Opcodes.ATHROW: |
|
||||||
case Opcodes.CHECKCAST: |
|
||||||
return false; |
|
||||||
case Opcodes.INSTANCEOF: |
|
||||||
return true; |
|
||||||
case Opcodes.MONITORENTER: |
|
||||||
case Opcodes.MONITOREXIT: |
|
||||||
case Opcodes.MULTIANEWARRAY: |
|
||||||
case Opcodes.IFNULL: |
|
||||||
case Opcodes.IFNONNULL: |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
throw new IllegalArgumentException(); |
|
||||||
} |
|
||||||
|
|
||||||
public static String toString(AbstractInsnNode insn) { |
|
||||||
var printer = new Textifier(); |
|
||||||
|
|
||||||
var visitor = new TraceMethodVisitor(printer); |
|
||||||
insn.accept(visitor); |
|
||||||
|
|
||||||
try ( |
|
||||||
var stringWriter = new StringWriter(); |
|
||||||
var printWriter = new PrintWriter(stringWriter) |
|
||||||
) { |
|
||||||
printer.print(printWriter); |
|
||||||
return stringWriter.toString().trim(); |
|
||||||
} catch (IOException ex) { |
|
||||||
throw new UncheckedIOException(ex); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private InsnNodeUtils() { |
|
||||||
/* empty */ |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,288 @@ |
|||||||
|
package dev.openrs2.asm |
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes |
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode |
||||||
|
import org.objectweb.asm.tree.InsnNode |
||||||
|
import org.objectweb.asm.tree.IntInsnNode |
||||||
|
import org.objectweb.asm.tree.LdcInsnNode |
||||||
|
import org.objectweb.asm.util.Textifier |
||||||
|
import org.objectweb.asm.util.TraceMethodVisitor |
||||||
|
import java.io.IOException |
||||||
|
import java.io.PrintWriter |
||||||
|
import java.io.StringWriter |
||||||
|
import java.io.UncheckedIOException |
||||||
|
|
||||||
|
private val PURE_OPCODES = setOf( |
||||||
|
-1, |
||||||
|
Opcodes.NOP, |
||||||
|
Opcodes.ACONST_NULL, |
||||||
|
Opcodes.ICONST_M1, |
||||||
|
Opcodes.ICONST_0, |
||||||
|
Opcodes.ICONST_1, |
||||||
|
Opcodes.ICONST_2, |
||||||
|
Opcodes.ICONST_3, |
||||||
|
Opcodes.ICONST_4, |
||||||
|
Opcodes.ICONST_5, |
||||||
|
Opcodes.LCONST_0, |
||||||
|
Opcodes.LCONST_1, |
||||||
|
Opcodes.FCONST_0, |
||||||
|
Opcodes.FCONST_1, |
||||||
|
Opcodes.FCONST_2, |
||||||
|
Opcodes.DCONST_0, |
||||||
|
Opcodes.DCONST_1, |
||||||
|
Opcodes.BIPUSH, |
||||||
|
Opcodes.SIPUSH, |
||||||
|
Opcodes.LDC, |
||||||
|
Opcodes.ILOAD, |
||||||
|
Opcodes.LLOAD, |
||||||
|
Opcodes.FLOAD, |
||||||
|
Opcodes.DLOAD, |
||||||
|
Opcodes.ALOAD, |
||||||
|
Opcodes.POP, |
||||||
|
Opcodes.POP2, |
||||||
|
Opcodes.DUP, |
||||||
|
Opcodes.DUP_X1, |
||||||
|
Opcodes.DUP_X2, |
||||||
|
Opcodes.DUP2, |
||||||
|
Opcodes.DUP2_X1, |
||||||
|
Opcodes.DUP2_X2, |
||||||
|
Opcodes.SWAP, |
||||||
|
Opcodes.IADD, |
||||||
|
Opcodes.LADD, |
||||||
|
Opcodes.FADD, |
||||||
|
Opcodes.DADD, |
||||||
|
Opcodes.ISUB, |
||||||
|
Opcodes.LSUB, |
||||||
|
Opcodes.FSUB, |
||||||
|
Opcodes.DSUB, |
||||||
|
Opcodes.IMUL, |
||||||
|
Opcodes.LMUL, |
||||||
|
Opcodes.FMUL, |
||||||
|
Opcodes.DMUL, |
||||||
|
/* |
||||||
|
* XXX(gpe): strictly speaking the *DEV and *REM instructions have side |
||||||
|
* effects (unless we can prove that the second argument is non-zero). |
||||||
|
* However, treating them as having side effects reduces the number of |
||||||
|
* dummy variables we can remove, so we pretend they don't have any side |
||||||
|
* effects. |
||||||
|
* |
||||||
|
* This doesn't seem to cause any problems with the client, as it doesn't |
||||||
|
* deliberately try to trigger divide-by-zero exceptions. |
||||||
|
*/ |
||||||
|
Opcodes.IDIV, |
||||||
|
Opcodes.LDIV, |
||||||
|
Opcodes.FDIV, |
||||||
|
Opcodes.DDIV, |
||||||
|
Opcodes.IREM, |
||||||
|
Opcodes.LREM, |
||||||
|
Opcodes.FREM, |
||||||
|
Opcodes.DREM, |
||||||
|
Opcodes.INEG, |
||||||
|
Opcodes.LNEG, |
||||||
|
Opcodes.FNEG, |
||||||
|
Opcodes.DNEG, |
||||||
|
Opcodes.ISHL, |
||||||
|
Opcodes.LSHL, |
||||||
|
Opcodes.ISHR, |
||||||
|
Opcodes.LSHR, |
||||||
|
Opcodes.IUSHR, |
||||||
|
Opcodes.LUSHR, |
||||||
|
Opcodes.IAND, |
||||||
|
Opcodes.LAND, |
||||||
|
Opcodes.IOR, |
||||||
|
Opcodes.LOR, |
||||||
|
Opcodes.IXOR, |
||||||
|
Opcodes.LXOR, |
||||||
|
Opcodes.I2L, |
||||||
|
Opcodes.I2F, |
||||||
|
Opcodes.I2D, |
||||||
|
Opcodes.L2I, |
||||||
|
Opcodes.L2F, |
||||||
|
Opcodes.L2D, |
||||||
|
Opcodes.F2I, |
||||||
|
Opcodes.F2L, |
||||||
|
Opcodes.F2D, |
||||||
|
Opcodes.D2I, |
||||||
|
Opcodes.D2L, |
||||||
|
Opcodes.D2F, |
||||||
|
Opcodes.I2B, |
||||||
|
Opcodes.I2C, |
||||||
|
Opcodes.I2S, |
||||||
|
Opcodes.LCMP, |
||||||
|
Opcodes.FCMPL, |
||||||
|
Opcodes.FCMPG, |
||||||
|
Opcodes.DCMPL, |
||||||
|
Opcodes.DCMPG, |
||||||
|
Opcodes.GETSTATIC, |
||||||
|
Opcodes.NEW, |
||||||
|
Opcodes.INSTANCEOF |
||||||
|
) |
||||||
|
|
||||||
|
private val IMPURE_OPCODES = setOf( |
||||||
|
Opcodes.IALOAD, |
||||||
|
Opcodes.LALOAD, |
||||||
|
Opcodes.FALOAD, |
||||||
|
Opcodes.DALOAD, |
||||||
|
Opcodes.AALOAD, |
||||||
|
Opcodes.BALOAD, |
||||||
|
Opcodes.CALOAD, |
||||||
|
Opcodes.SALOAD, |
||||||
|
Opcodes.ISTORE, |
||||||
|
Opcodes.LSTORE, |
||||||
|
Opcodes.FSTORE, |
||||||
|
Opcodes.DSTORE, |
||||||
|
Opcodes.ASTORE, |
||||||
|
Opcodes.IASTORE, |
||||||
|
Opcodes.LASTORE, |
||||||
|
Opcodes.FASTORE, |
||||||
|
Opcodes.DASTORE, |
||||||
|
Opcodes.AASTORE, |
||||||
|
Opcodes.BASTORE, |
||||||
|
Opcodes.CASTORE, |
||||||
|
Opcodes.SASTORE, |
||||||
|
Opcodes.IINC, |
||||||
|
Opcodes.IFEQ, |
||||||
|
Opcodes.IFNE, |
||||||
|
Opcodes.IFLT, |
||||||
|
Opcodes.IFGE, |
||||||
|
Opcodes.IFGT, |
||||||
|
Opcodes.IFLE, |
||||||
|
Opcodes.IF_ICMPEQ, |
||||||
|
Opcodes.IF_ICMPNE, |
||||||
|
Opcodes.IF_ICMPLT, |
||||||
|
Opcodes.IF_ICMPGE, |
||||||
|
Opcodes.IF_ICMPGT, |
||||||
|
Opcodes.IF_ICMPLE, |
||||||
|
Opcodes.IF_ACMPEQ, |
||||||
|
Opcodes.IF_ACMPNE, |
||||||
|
Opcodes.GOTO, |
||||||
|
Opcodes.JSR, |
||||||
|
Opcodes.RET, |
||||||
|
Opcodes.TABLESWITCH, |
||||||
|
Opcodes.LOOKUPSWITCH, |
||||||
|
Opcodes.IRETURN, |
||||||
|
Opcodes.LRETURN, |
||||||
|
Opcodes.FRETURN, |
||||||
|
Opcodes.DRETURN, |
||||||
|
Opcodes.ARETURN, |
||||||
|
Opcodes.RETURN, |
||||||
|
Opcodes.PUTSTATIC, |
||||||
|
Opcodes.GETFIELD, |
||||||
|
Opcodes.PUTFIELD, |
||||||
|
Opcodes.INVOKEVIRTUAL, |
||||||
|
Opcodes.INVOKESPECIAL, |
||||||
|
Opcodes.INVOKESTATIC, |
||||||
|
Opcodes.INVOKEINTERFACE, |
||||||
|
Opcodes.INVOKEDYNAMIC, |
||||||
|
Opcodes.NEWARRAY, |
||||||
|
Opcodes.ANEWARRAY, |
||||||
|
Opcodes.ARRAYLENGTH, |
||||||
|
Opcodes.ATHROW, |
||||||
|
Opcodes.CHECKCAST, |
||||||
|
Opcodes.MONITORENTER, |
||||||
|
Opcodes.MONITOREXIT, |
||||||
|
Opcodes.MULTIANEWARRAY, |
||||||
|
Opcodes.IFNULL, |
||||||
|
Opcodes.IFNONNULL |
||||||
|
) |
||||||
|
|
||||||
|
val AbstractInsnNode.nextReal: AbstractInsnNode? |
||||||
|
get() { |
||||||
|
var insn = next |
||||||
|
while (insn != null && insn.opcode == -1) { |
||||||
|
insn = insn.next |
||||||
|
} |
||||||
|
return insn |
||||||
|
} |
||||||
|
|
||||||
|
val AbstractInsnNode.previousReal: AbstractInsnNode? |
||||||
|
get() { |
||||||
|
var insn = previous |
||||||
|
while (insn != null && insn.opcode == -1) { |
||||||
|
insn = insn.previous |
||||||
|
} |
||||||
|
return insn |
||||||
|
} |
||||||
|
|
||||||
|
val AbstractInsnNode.nextVirtual: AbstractInsnNode? |
||||||
|
get() { |
||||||
|
var insn = next |
||||||
|
while (insn != null && insn.opcode != -1) { |
||||||
|
insn = insn.next |
||||||
|
} |
||||||
|
return insn |
||||||
|
} |
||||||
|
|
||||||
|
val AbstractInsnNode.previousVirtual: AbstractInsnNode? |
||||||
|
get() { |
||||||
|
var insn = previous |
||||||
|
while (insn != null && insn.opcode != -1) { |
||||||
|
insn = insn.previous |
||||||
|
} |
||||||
|
return insn |
||||||
|
} |
||||||
|
|
||||||
|
val AbstractInsnNode.intConstant: Int? |
||||||
|
get() = when (this) { |
||||||
|
is IntInsnNode -> { |
||||||
|
if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) { |
||||||
|
operand |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
is LdcInsnNode -> { |
||||||
|
val cst = cst |
||||||
|
if (cst is Int) { |
||||||
|
cst |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
else -> when (opcode) { |
||||||
|
Opcodes.ICONST_M1 -> -1 |
||||||
|
Opcodes.ICONST_0 -> 0 |
||||||
|
Opcodes.ICONST_1 -> 1 |
||||||
|
Opcodes.ICONST_2 -> 2 |
||||||
|
Opcodes.ICONST_3 -> 3 |
||||||
|
Opcodes.ICONST_4 -> 4 |
||||||
|
Opcodes.ICONST_5 -> 5 |
||||||
|
else -> null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val AbstractInsnNode.pure: Boolean |
||||||
|
get() = when { |
||||||
|
PURE_OPCODES.contains(opcode) -> true |
||||||
|
IMPURE_OPCODES.contains(opcode) -> false |
||||||
|
else -> throw IllegalArgumentException() |
||||||
|
} |
||||||
|
|
||||||
|
fun createIntConstant(value: Int): AbstractInsnNode = when (value) { |
||||||
|
-1 -> InsnNode(Opcodes.ICONST_M1) |
||||||
|
0 -> InsnNode(Opcodes.ICONST_0) |
||||||
|
1 -> InsnNode(Opcodes.ICONST_1) |
||||||
|
2 -> InsnNode(Opcodes.ICONST_2) |
||||||
|
3 -> InsnNode(Opcodes.ICONST_3) |
||||||
|
4 -> InsnNode(Opcodes.ICONST_4) |
||||||
|
5 -> InsnNode(Opcodes.ICONST_5) |
||||||
|
in Byte.MIN_VALUE..Byte.MAX_VALUE -> IntInsnNode(Opcodes.BIPUSH, value) |
||||||
|
in Short.MIN_VALUE..Short.MAX_VALUE -> IntInsnNode(Opcodes.SIPUSH, value) |
||||||
|
else -> LdcInsnNode(value) |
||||||
|
} |
||||||
|
|
||||||
|
fun AbstractInsnNode.toPrettyString(): String { |
||||||
|
val printer = Textifier() |
||||||
|
val visitor = TraceMethodVisitor(printer) |
||||||
|
accept(visitor) |
||||||
|
try { |
||||||
|
StringWriter().use { stringWriter -> |
||||||
|
PrintWriter(stringWriter).use { printWriter -> |
||||||
|
printer.print(printWriter) |
||||||
|
return stringWriter.toString().trim { it <= ' ' } |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (ex: IOException) { |
||||||
|
throw UncheckedIOException(ex) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue