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

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
}
}