Open-source multiplayer game server compatible with the RuneScape client https://www.openrs2.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
openrs2/asm/src/main/java/dev/openrs2/asm/InsnNodeUtils.kt

284 lines
6.5 KiB

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.PrintWriter
import java.io.StringWriter
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 (opcode) {
in PURE_OPCODES -> true
in IMPURE_OPCODES -> 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)
StringWriter().use { stringWriter ->
PrintWriter(stringWriter).use { printWriter ->
printer.print(printWriter)
return stringWriter.toString().trim()
}
}
}