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/org/openrs2/asm/InsnMatcher.kt

290 lines
8.9 KiB

package org.openrs2.asm
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.AbstractInsnNode
import org.objectweb.asm.tree.InsnList
import org.objectweb.asm.tree.MethodNode
import org.objectweb.asm.util.Printer
public class InsnMatcher private constructor(private val regex: Regex) {
public fun match(method: MethodNode): Sequence<List<AbstractInsnNode>> {
return match(method.instructions)
}
public fun match(list: InsnList): Sequence<List<AbstractInsnNode>> {
val insns = ArrayList<AbstractInsnNode>(list.size())
val builder = StringBuilder(list.size())
for (instruction in list) {
if (instruction.opcode != -1) {
insns += instruction
builder.append(opcodeToCodepoint(instruction.opcode))
}
}
return regex.findAll(builder).map {
insns.subList(it.range.first, it.range.last + 1)
}
}
public companion object {
private const val PRIVATE_USE_AREA = 0xE000
private val OPCODE_GROUPS = mapOf(
"InsnNode" to intArrayOf(
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.IALOAD,
Opcodes.LALOAD,
Opcodes.FALOAD,
Opcodes.DALOAD,
Opcodes.AALOAD,
Opcodes.BALOAD,
Opcodes.CALOAD,
Opcodes.SALOAD,
Opcodes.IASTORE,
Opcodes.LASTORE,
Opcodes.FASTORE,
Opcodes.DASTORE,
Opcodes.AASTORE,
Opcodes.BASTORE,
Opcodes.CASTORE,
Opcodes.SASTORE,
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,
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.IRETURN,
Opcodes.LRETURN,
Opcodes.FRETURN,
Opcodes.DRETURN,
Opcodes.ARETURN,
Opcodes.RETURN,
Opcodes.ARRAYLENGTH,
Opcodes.ATHROW,
Opcodes.MONITORENTER,
Opcodes.MONITOREXIT
),
"IntInsnNode" to intArrayOf(
Opcodes.BIPUSH,
Opcodes.SIPUSH,
Opcodes.NEWARRAY
),
"VarInsnNode" to intArrayOf(
Opcodes.ILOAD,
Opcodes.LLOAD,
Opcodes.FLOAD,
Opcodes.DLOAD,
Opcodes.ALOAD,
Opcodes.ISTORE,
Opcodes.LSTORE,
Opcodes.FSTORE,
Opcodes.DSTORE,
Opcodes.ASTORE,
Opcodes.RET
),
"TypeInsnNode" to intArrayOf(
Opcodes.NEW,
Opcodes.ANEWARRAY,
Opcodes.CHECKCAST,
Opcodes.INSTANCEOF
),
"FieldInsnNode" to intArrayOf(
Opcodes.GETSTATIC,
Opcodes.PUTSTATIC,
Opcodes.GETFIELD,
Opcodes.PUTFIELD
),
"MethodInsnNode" to intArrayOf(
Opcodes.INVOKEVIRTUAL,
Opcodes.INVOKESPECIAL,
Opcodes.INVOKESTATIC,
Opcodes.INVOKEINTERFACE
),
"InvokeDynamicInsnNode" to intArrayOf(
Opcodes.INVOKEDYNAMIC
),
"JumpInsnNode" to intArrayOf(
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.IFNULL,
Opcodes.IFNONNULL
),
"LdcInsnNode" to intArrayOf(
Opcodes.LDC
),
"IincInsnNode" to intArrayOf(
Opcodes.IINC
),
"TableSwitchInsnNode" to intArrayOf(
Opcodes.TABLESWITCH
),
"LookupSwitchInsnNode" to intArrayOf(
Opcodes.LOOKUPSWITCH
),
"MultiANewArrayInsnNode" to intArrayOf(
Opcodes.MULTIANEWARRAY
),
"ICONST" to intArrayOf(
Opcodes.ICONST_M1,
Opcodes.ICONST_0,
Opcodes.ICONST_1,
Opcodes.ICONST_2,
Opcodes.ICONST_3,
Opcodes.ICONST_4,
Opcodes.ICONST_5
),
"FCONST" to intArrayOf(
Opcodes.FCONST_0,
Opcodes.FCONST_1,
Opcodes.FCONST_2
),
"DCONST" to intArrayOf(
Opcodes.DCONST_0,
Opcodes.DCONST_1
)
)
private fun opcodeToCodepoint(opcode: Int): Char {
return (PRIVATE_USE_AREA + opcode).toChar()
}
private fun appendOpcodeRegex(pattern: StringBuilder, opcode: String) {
val i = Printer.OPCODES.indexOf(opcode)
if (i != -1) {
pattern.append(opcodeToCodepoint(i))
return
}
val group = OPCODE_GROUPS[opcode]
if (group != null) {
pattern.append('(')
group.map { opcodeToCodepoint(it) }.joinTo(pattern, "|")
pattern.append(')')
return
}
if (opcode == "AbstractInsnNode") {
pattern.append('.')
return
}
throw IllegalArgumentException("$opcode is not a valid opcode or opcode group")
}
public fun compile(regex: String): InsnMatcher {
val pattern = StringBuilder()
val opcode = StringBuilder()
for (c in regex) {
if (c.isLetterOrDigit() || c == '_') {
opcode.append(c)
} else {
if (opcode.isNotEmpty()) {
appendOpcodeRegex(pattern, opcode.toString())
opcode.delete(0, opcode.length)
}
if (!c.isWhitespace()) {
pattern.append(c)
}
}
}
if (opcode.isNotEmpty()) {
appendOpcodeRegex(pattern, opcode.toString())
opcode.delete(0, opcode.length)
}
return InsnMatcher(Regex(pattern.toString()))
}
}
}