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) : Interpreter(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() 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() 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? { 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 } }