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.
151 lines
5.4 KiB
151 lines
5.4 KiB
package org.openrs2.deob.bytecode.analysis
|
|
|
|
import org.objectweb.asm.Opcodes
|
|
import org.objectweb.asm.Type
|
|
import org.objectweb.asm.tree.AbstractInsnNode
|
|
import org.objectweb.asm.tree.IincInsnNode
|
|
import org.objectweb.asm.tree.analysis.BasicInterpreter
|
|
import org.objectweb.asm.tree.analysis.Interpreter
|
|
import org.openrs2.asm.intConstant
|
|
|
|
public class IntInterpreter(private val args: Array<IntValueSet>) : Interpreter<IntValue>(Opcodes.ASM9) {
|
|
private val basicInterpreter = BasicInterpreter()
|
|
|
|
override fun newValue(type: Type?): IntValue? {
|
|
val basicValue = basicInterpreter.newValue(type) ?: return null
|
|
return IntValue(basicValue)
|
|
}
|
|
|
|
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): IntValue {
|
|
val basicValue = basicInterpreter.newParameterValue(isInstanceMethod, local, type)
|
|
|
|
val index = when {
|
|
isInstanceMethod && local == 0 -> return IntValue(basicValue)
|
|
isInstanceMethod -> local - 1
|
|
else -> local
|
|
}
|
|
|
|
return IntValue(basicValue, args[index])
|
|
}
|
|
|
|
override fun newOperation(insn: AbstractInsnNode): IntValue {
|
|
val basicValue = basicInterpreter.newOperation(insn)
|
|
val v = insn.intConstant
|
|
return if (v != null) {
|
|
IntValue(basicValue, IntValueSet.singleton(v))
|
|
} else {
|
|
IntValue(basicValue)
|
|
}
|
|
}
|
|
|
|
override fun copyOperation(insn: AbstractInsnNode, value: IntValue): IntValue {
|
|
return value
|
|
}
|
|
|
|
override fun unaryOperation(insn: AbstractInsnNode, value: IntValue): IntValue? {
|
|
val basicValue = basicInterpreter.unaryOperation(insn, value.basicValue) ?: return null
|
|
|
|
if (value.set !is IntValueSet.Constant) {
|
|
return IntValue(basicValue)
|
|
}
|
|
|
|
val set = mutableSetOf<Int>()
|
|
for (v in value.set.values) {
|
|
val result = when {
|
|
insn.opcode == Opcodes.INEG -> -v
|
|
insn is IincInsnNode -> v + insn.incr
|
|
insn.opcode == Opcodes.I2B -> v.toByte().toInt()
|
|
insn.opcode == Opcodes.I2C -> v.toChar().code
|
|
insn.opcode == Opcodes.I2S -> v.toShort().toInt()
|
|
else -> return IntValue(basicValue)
|
|
}
|
|
set.add(result)
|
|
}
|
|
return IntValue(basicValue, IntValueSet.Constant(set))
|
|
}
|
|
|
|
override fun binaryOperation(insn: AbstractInsnNode, value1: IntValue, value2: IntValue): IntValue? {
|
|
val basicValue = basicInterpreter.binaryOperation(insn, value1.basicValue, value2.basicValue) ?: return null
|
|
|
|
if (value1.set !is IntValueSet.Constant || value2.set !is IntValueSet.Constant) {
|
|
return IntValue(basicValue)
|
|
}
|
|
|
|
val set = mutableSetOf<Int>()
|
|
for (v1 in value1.set.values) {
|
|
for (v2 in value2.set.values) {
|
|
val result = when (insn.opcode) {
|
|
Opcodes.IADD -> v1 + v2
|
|
Opcodes.ISUB -> v1 - v2
|
|
Opcodes.IMUL -> v1 * v2
|
|
Opcodes.IDIV -> {
|
|
if (v2 == 0) {
|
|
return IntValue(basicValue)
|
|
}
|
|
v1 / v2
|
|
}
|
|
Opcodes.IREM -> {
|
|
if (v2 == 0) {
|
|
return IntValue(basicValue)
|
|
}
|
|
v1 % v2
|
|
}
|
|
Opcodes.ISHL -> v1 shl v2
|
|
Opcodes.ISHR -> v1 shr v2
|
|
Opcodes.IUSHR -> v1 ushr v2
|
|
Opcodes.IAND -> v1 and v2
|
|
Opcodes.IOR -> v1 or v2
|
|
Opcodes.IXOR -> v1 xor v2
|
|
else -> return IntValue(basicValue)
|
|
}
|
|
set.add(result)
|
|
}
|
|
}
|
|
return IntValue(basicValue, IntValueSet.Constant(set))
|
|
}
|
|
|
|
override fun ternaryOperation(
|
|
insn: AbstractInsnNode,
|
|
value1: IntValue,
|
|
value2: IntValue,
|
|
value3: IntValue
|
|
): IntValue? {
|
|
val basicValue =
|
|
basicInterpreter.ternaryOperation(insn, value1.basicValue, value2.basicValue, value3.basicValue)
|
|
?: return null
|
|
return IntValue(basicValue)
|
|
}
|
|
|
|
override fun naryOperation(insn: AbstractInsnNode, values: List<IntValue>): IntValue? {
|
|
val args = values.map(IntValue::basicValue)
|
|
val basicValue = basicInterpreter.naryOperation(insn, args) ?: return null
|
|
return IntValue(basicValue)
|
|
}
|
|
|
|
override fun returnOperation(insn: AbstractInsnNode, value: IntValue, expected: IntValue) {
|
|
basicInterpreter.returnOperation(insn, value.basicValue, expected.basicValue)
|
|
}
|
|
|
|
override fun merge(value1: IntValue, value2: IntValue): IntValue {
|
|
val basicValue = basicInterpreter.merge(value1.basicValue, value2.basicValue)
|
|
|
|
if (value1 == value2) {
|
|
return value1
|
|
}
|
|
|
|
if (value1.set !is IntValueSet.Constant || value2.set !is IntValueSet.Constant) {
|
|
return IntValue(basicValue)
|
|
}
|
|
|
|
val set = value1.set union value2.set
|
|
return if (set is IntValueSet.Constant && set.values.size > MAX_TRACKED_VALUES) {
|
|
IntValue(basicValue)
|
|
} else {
|
|
IntValue(basicValue, set)
|
|
}
|
|
}
|
|
|
|
private companion object {
|
|
private const val MAX_TRACKED_VALUES = 1
|
|
}
|
|
}
|
|
|