forked from openrs2/openrs2
I'm not yet sure if I'm going to need to use this, but I want to get it in the repository so I have a copy of it for the future (this is already the second time I've written something similar to it!)master
parent
5d2fd11128
commit
176b109688
@ -0,0 +1,352 @@ |
|||||||
|
package dev.openrs2.asm; |
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes; |
||||||
|
import org.objectweb.asm.Type; |
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode; |
||||||
|
import org.objectweb.asm.tree.FieldInsnNode; |
||||||
|
import org.objectweb.asm.tree.LdcInsnNode; |
||||||
|
import org.objectweb.asm.tree.MethodInsnNode; |
||||||
|
import org.objectweb.asm.tree.MultiANewArrayInsnNode; |
||||||
|
|
||||||
|
public final class StackMetadata { |
||||||
|
private static final StackMetadata NONE = new StackMetadata(0, 0); |
||||||
|
private static final StackMetadata POP1 = new StackMetadata(1, 0); |
||||||
|
private static final StackMetadata POP1_PUSH1 = new StackMetadata(1, 1); |
||||||
|
private static final StackMetadata POP1_PUSH2 = new StackMetadata(1, 2); |
||||||
|
private static final StackMetadata POP2 = new StackMetadata(2, 0); |
||||||
|
private static final StackMetadata POP2_PUSH1 = new StackMetadata(2, 1); |
||||||
|
private static final StackMetadata POP2_PUSH2 = new StackMetadata(2, 2); |
||||||
|
private static final StackMetadata POP2_PUSH3 = new StackMetadata(2, 3); |
||||||
|
private static final StackMetadata POP2_PUSH4 = new StackMetadata(2, 4); |
||||||
|
private static final StackMetadata POP3 = new StackMetadata(3, 0); |
||||||
|
private static final StackMetadata POP3_PUSH2 = new StackMetadata(3, 2); |
||||||
|
private static final StackMetadata POP3_PUSH4 = new StackMetadata(3, 4); |
||||||
|
private static final StackMetadata POP3_PUSH5 = new StackMetadata(3, 5); |
||||||
|
private static final StackMetadata POP4 = new StackMetadata(4, 0); |
||||||
|
private static final StackMetadata POP4_PUSH1 = new StackMetadata(4, 1); |
||||||
|
private static final StackMetadata POP4_PUSH2 = new StackMetadata(4, 2); |
||||||
|
private static final StackMetadata POP4_PUSH6 = new StackMetadata(4, 6); |
||||||
|
private static final StackMetadata PUSH1 = new StackMetadata(0, 1); |
||||||
|
private static final StackMetadata PUSH2 = new StackMetadata(0, 2); |
||||||
|
|
||||||
|
public static StackMetadata get(AbstractInsnNode insn) { |
||||||
|
var opcode = insn.getOpcode(); |
||||||
|
switch (opcode) { |
||||||
|
case Opcodes.NOP: |
||||||
|
return NONE; |
||||||
|
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: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.LCONST_0: |
||||||
|
case Opcodes.LCONST_1: |
||||||
|
return PUSH2; |
||||||
|
case Opcodes.FCONST_0: |
||||||
|
case Opcodes.FCONST_1: |
||||||
|
case Opcodes.FCONST_2: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.DCONST_0: |
||||||
|
case Opcodes.DCONST_1: |
||||||
|
return PUSH2; |
||||||
|
case Opcodes.BIPUSH: |
||||||
|
case Opcodes.SIPUSH: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.LDC: |
||||||
|
var cst = ((LdcInsnNode) insn).cst; |
||||||
|
if (cst instanceof Double || cst instanceof Long) { |
||||||
|
return PUSH2; |
||||||
|
} else { |
||||||
|
return PUSH1; |
||||||
|
} |
||||||
|
case Opcodes.ILOAD: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.LLOAD: |
||||||
|
return PUSH2; |
||||||
|
case Opcodes.FLOAD: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.DLOAD: |
||||||
|
return PUSH2; |
||||||
|
case Opcodes.ALOAD: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.IALOAD: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LALOAD: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.FALOAD: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DALOAD: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.AALOAD: |
||||||
|
case Opcodes.BALOAD: |
||||||
|
case Opcodes.CALOAD: |
||||||
|
case Opcodes.SALOAD: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.ISTORE: |
||||||
|
return POP1; |
||||||
|
case Opcodes.LSTORE: |
||||||
|
return POP2; |
||||||
|
case Opcodes.FSTORE: |
||||||
|
return POP1; |
||||||
|
case Opcodes.DSTORE: |
||||||
|
return POP2; |
||||||
|
case Opcodes.ASTORE: |
||||||
|
return POP1; |
||||||
|
case Opcodes.IASTORE: |
||||||
|
return POP3; |
||||||
|
case Opcodes.LASTORE: |
||||||
|
return POP4; |
||||||
|
case Opcodes.FASTORE: |
||||||
|
return POP3; |
||||||
|
case Opcodes.DASTORE: |
||||||
|
return POP4; |
||||||
|
case Opcodes.AASTORE: |
||||||
|
case Opcodes.BASTORE: |
||||||
|
case Opcodes.CASTORE: |
||||||
|
case Opcodes.SASTORE: |
||||||
|
return POP3; |
||||||
|
case Opcodes.POP: |
||||||
|
return POP1; |
||||||
|
case Opcodes.POP2: |
||||||
|
return POP2; |
||||||
|
case Opcodes.DUP: |
||||||
|
return POP1_PUSH2; |
||||||
|
case Opcodes.DUP_X1: |
||||||
|
return POP2_PUSH3; |
||||||
|
case Opcodes.DUP_X2: |
||||||
|
return POP3_PUSH4; |
||||||
|
case Opcodes.DUP2: |
||||||
|
return POP2_PUSH4; |
||||||
|
case Opcodes.DUP2_X1: |
||||||
|
return POP3_PUSH5; |
||||||
|
case Opcodes.DUP2_X2: |
||||||
|
return POP4_PUSH6; |
||||||
|
case Opcodes.SWAP: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.IADD: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LADD: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.FADD: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DADD: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.ISUB: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LSUB: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.FSUB: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DSUB: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.IMUL: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LMUL: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.FMUL: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DMUL: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.IDIV: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LDIV: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.FDIV: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DDIV: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.IREM: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LREM: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.FREM: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DREM: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.INEG: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.LNEG: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.FNEG: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.DNEG: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.ISHL: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LSHL: |
||||||
|
return POP3_PUSH2; |
||||||
|
case Opcodes.ISHR: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LSHR: |
||||||
|
return POP3_PUSH2; |
||||||
|
case Opcodes.IUSHR: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LUSHR: |
||||||
|
return POP3_PUSH2; |
||||||
|
case Opcodes.IAND: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LAND: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.IOR: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LOR: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.IXOR: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.LXOR: |
||||||
|
return POP4_PUSH2; |
||||||
|
case Opcodes.IINC: |
||||||
|
return NONE; |
||||||
|
case Opcodes.I2L: |
||||||
|
return POP1_PUSH2; |
||||||
|
case Opcodes.I2F: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.I2D: |
||||||
|
return POP1_PUSH2; |
||||||
|
case Opcodes.L2I: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.L2F: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.L2D: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.F2I: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.F2L: |
||||||
|
return POP1_PUSH2; |
||||||
|
case Opcodes.F2D: |
||||||
|
return POP1_PUSH2; |
||||||
|
case Opcodes.D2I: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.D2L: |
||||||
|
return POP2_PUSH2; |
||||||
|
case Opcodes.D2F: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.I2B: |
||||||
|
case Opcodes.I2C: |
||||||
|
case Opcodes.I2S: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.LCMP: |
||||||
|
return POP4_PUSH1; |
||||||
|
case Opcodes.FCMPL: |
||||||
|
case Opcodes.FCMPG: |
||||||
|
return POP2_PUSH1; |
||||||
|
case Opcodes.DCMPL: |
||||||
|
case Opcodes.DCMPG: |
||||||
|
return POP4_PUSH1; |
||||||
|
case Opcodes.IFEQ: |
||||||
|
case Opcodes.IFNE: |
||||||
|
case Opcodes.IFLT: |
||||||
|
case Opcodes.IFGE: |
||||||
|
case Opcodes.IFGT: |
||||||
|
case Opcodes.IFLE: |
||||||
|
return POP1; |
||||||
|
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: |
||||||
|
return POP2; |
||||||
|
case Opcodes.GOTO: |
||||||
|
return NONE; |
||||||
|
case Opcodes.JSR: |
||||||
|
return PUSH1; |
||||||
|
case Opcodes.RET: |
||||||
|
return NONE; |
||||||
|
case Opcodes.TABLESWITCH: |
||||||
|
case Opcodes.LOOKUPSWITCH: |
||||||
|
return POP1; |
||||||
|
case Opcodes.IRETURN: |
||||||
|
return POP1; |
||||||
|
case Opcodes.LRETURN: |
||||||
|
return POP2; |
||||||
|
case Opcodes.FRETURN: |
||||||
|
return POP1; |
||||||
|
case Opcodes.DRETURN: |
||||||
|
return POP2; |
||||||
|
case Opcodes.ARETURN: |
||||||
|
return POP1; |
||||||
|
case Opcodes.RETURN: |
||||||
|
return NONE; |
||||||
|
case Opcodes.GETSTATIC: |
||||||
|
case Opcodes.PUTSTATIC: |
||||||
|
case Opcodes.GETFIELD: |
||||||
|
case Opcodes.PUTFIELD: |
||||||
|
var fieldInsn = (FieldInsnNode) insn; |
||||||
|
var fieldSize = Type.getType(fieldInsn.desc).getSize(); |
||||||
|
|
||||||
|
int pushes = 0, pops = 0; |
||||||
|
|
||||||
|
if (opcode == Opcodes.GETFIELD || opcode == Opcodes.PUTFIELD) { |
||||||
|
pops++; |
||||||
|
} |
||||||
|
|
||||||
|
if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) { |
||||||
|
pushes += fieldSize; |
||||||
|
} else { |
||||||
|
pops += fieldSize; |
||||||
|
} |
||||||
|
|
||||||
|
return new StackMetadata(pops, pushes); |
||||||
|
case Opcodes.INVOKEVIRTUAL: |
||||||
|
case Opcodes.INVOKESPECIAL: |
||||||
|
case Opcodes.INVOKESTATIC: |
||||||
|
case Opcodes.INVOKEINTERFACE: |
||||||
|
var methodInsn = (MethodInsnNode) insn; |
||||||
|
var argumentsAndReturnSizes = Type.getArgumentsAndReturnSizes(methodInsn.desc); |
||||||
|
|
||||||
|
pushes = argumentsAndReturnSizes >> 2; |
||||||
|
pops = argumentsAndReturnSizes & 0x3; |
||||||
|
|
||||||
|
if (opcode != Opcodes.INVOKESTATIC) { |
||||||
|
pops++; |
||||||
|
} |
||||||
|
|
||||||
|
return new StackMetadata(pops, pushes); |
||||||
|
case Opcodes.INVOKEDYNAMIC: |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
case Opcodes.NEW: |
||||||
|
return POP1; |
||||||
|
case Opcodes.NEWARRAY: |
||||||
|
case Opcodes.ANEWARRAY: |
||||||
|
case Opcodes.ARRAYLENGTH: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.ATHROW: |
||||||
|
return POP1; |
||||||
|
case Opcodes.CHECKCAST: |
||||||
|
case Opcodes.INSTANCEOF: |
||||||
|
return POP1_PUSH1; |
||||||
|
case Opcodes.MONITORENTER: |
||||||
|
case Opcodes.MONITOREXIT: |
||||||
|
return POP1; |
||||||
|
case Opcodes.MULTIANEWARRAY: |
||||||
|
return new StackMetadata(((MultiANewArrayInsnNode) insn).dims, 1); |
||||||
|
case Opcodes.IFNULL: |
||||||
|
case Opcodes.IFNONNULL: |
||||||
|
return POP1; |
||||||
|
} |
||||||
|
|
||||||
|
throw new IllegalArgumentException(); |
||||||
|
} |
||||||
|
|
||||||
|
private final int pops, pushes; |
||||||
|
|
||||||
|
private StackMetadata(int pops, int pushes) { |
||||||
|
this.pops = pops; |
||||||
|
this.pushes = pushes; |
||||||
|
} |
||||||
|
|
||||||
|
public int getPops() { |
||||||
|
return pops; |
||||||
|
} |
||||||
|
|
||||||
|
public int getPushes() { |
||||||
|
return pushes; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue