package net.scapeemulator.asm.util;
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;
/**
* Several utility methods related to instruction nodes.
* @author Graham Edgecombe
*/
public final class InsnNodeUtils {
/**
* Creates a numeric push instruction.
* @param num The number to push.
* @return The instruction node.
*/
public static AbstractInsnNode createNumericPushInsn(Number num) {
long value = num.longValue();
if (value == -1) {
return new InsnNode(Opcodes.ICONST_M1);
} else if (value == 0) {
return new InsnNode(Opcodes.ICONST_0);
} else if (value == 1) {
return new InsnNode(Opcodes.ICONST_1);
} else if (value == 2) {
return new InsnNode(Opcodes.ICONST_2);
} else if (value == 3) {
return new InsnNode(Opcodes.ICONST_3);
} else if (value == 4) {
return new InsnNode(Opcodes.ICONST_4);
} else if (value == 5) {
return new InsnNode(Opcodes.ICONST_5);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
return new IntInsnNode(Opcodes.BIPUSH, (int) value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
return new IntInsnNode(Opcodes.SIPUSH, (int) value);
} else if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
return new LdcInsnNode((int) value);
} else {
return new LdcInsnNode(/*(long)*/ value);
}
}
/**
* Reads the value of a numeric push instruction (which can be an
* {@code ICONST_*} instruction, an {@code BIPUSH} instruction, an
* {@code SIPUSH} instruction or a {@code LDC_*} instruction.
* @param push The instruction node.
* @return The numeric value.
*/
public static long getNumericPushValue(AbstractInsnNode push) {
if (push instanceof InsnNode) {
switch (push.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;
default:
throw new AssertionError();
}
} else if (push instanceof IntInsnNode) {
return ((IntInsnNode) push).operand;
} else {
return ((Number) ((LdcInsnNode) push).cst).longValue();
}
}
/**
* Finds the next non-psuedo node following the specified node.
* @param node The node.
* @return The next non-psuedo node, or {@code null} if the end of the
* instruction list is reached.
*/
public static AbstractInsnNode nextNonPsuedoNode(AbstractInsnNode node) {
while ((node = node.getNext()) != null && node.getOpcode() == -1);
return node;
}
/**
* Finds the previous non-psuedo node following the specified node.
* @param node The node.
* @return The previous non-psuedo node, or {@code null} if the start of
* the instruction list is reached.
*/
public static AbstractInsnNode previousNonPsuedoNode(AbstractInsnNode node) {
while ((node = node.getPrevious()) != null && node.getOpcode() == -1);
return node;
}
/**
* Finds the next psuedo node following the specified node.
* @param node The node.
* @return The next psuedo node, or {@code null} if the end of the
* instruction list is reached.
*/
public static AbstractInsnNode nextPsuedoNode(AbstractInsnNode node) {
while ((node = node.getNext()) != null && node.getOpcode() != -1);
return node;
}
/**
* Finds the previous psuedo node following the specified node.
* @param node The node.
* @return The previous psuedo node, or {@code null} if the start of the
* instruction list is reached.
*/
public static AbstractInsnNode previousPsuedoNode(AbstractInsnNode node) {
while ((node = node.getPrevious()) != null && node.getOpcode() != -1);
return node;
}
/**
* Default private constructor to prevent instantiation.
*/
private InsnNodeUtils() {
}
}