diff --git a/deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.kt b/deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.kt index daca06853a..1b38910f2c 100644 --- a/deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.kt +++ b/deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.kt @@ -1,7 +1,5 @@ package dev.openrs2.deob.analysis -import com.google.common.collect.ImmutableSet -import com.google.common.collect.Sets import dev.openrs2.asm.intConstant import org.objectweb.asm.Opcodes import org.objectweb.asm.Type @@ -16,7 +14,7 @@ class IntInterpreter(private val parameters: Array?>?) : Interpreter?>?) : Interpreter return IntValue.newUnknown(basicValue) + isInstanceMethod && local == 0 -> return IntValue.Unknown(basicValue) isInstanceMethod -> local - 1 else -> local } val parameter = parameters[parameterIndex] if (parameter != null) { - return IntValue.newConstant(basicValue, parameter) + return IntValue.Constant(basicValue, parameter) } } - return IntValue.newUnknown(basicValue) + return IntValue.Unknown(basicValue) } @Throws(AnalyzerException::class) @@ -43,9 +41,9 @@ class IntInterpreter(private val parameters: Array?>?) : Interpreter?>?) : Interpreter() - for (v in value.intValues) { + val set = mutableSetOf() + for (v in value.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().toInt() insn.opcode == Opcodes.I2S -> v.toShort().toInt() - else -> return IntValue.newUnknown(basicValue) + else -> return IntValue.Unknown(basicValue) } set.add(result) } - return IntValue.newConstant(basicValue, set.build()) + return IntValue.Constant(basicValue, set) } @Throws(AnalyzerException::class) override fun binaryOperation(insn: AbstractInsnNode, value1: IntValue, value2: IntValue): IntValue? { val basicValue = basicInterpreter.binaryOperation(insn, value1.basicValue, value2.basicValue) ?: return null - if (value1.isUnknown || value2.isUnknown) { - return IntValue.newUnknown(basicValue) + if (value1 !is IntValue.Constant || value2 !is IntValue.Constant) { + return IntValue.Unknown(basicValue) } - val set = ImmutableSet.builder() - for (v1 in value1.intValues) { - for (v2 in value2.intValues) { + val set = mutableSetOf() + for (v1 in value1.values) { + for (v2 in value2.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.newUnknown(basicValue) + return IntValue.Unknown(basicValue) } v1 / v2 } Opcodes.IREM -> { if (v2 == 0) { - return IntValue.newUnknown(basicValue) + return IntValue.Unknown(basicValue) } v1 % v2 } @@ -109,12 +107,12 @@ class IntInterpreter(private val parameters: Array?>?) : Interpreter v1 and v2 Opcodes.IOR -> v1 or v2 Opcodes.IXOR -> v1 xor v2 - else -> return IntValue.newUnknown(basicValue) + else -> return IntValue.Unknown(basicValue) } set.add(result) } } - return IntValue.newConstant(basicValue, set.build()) + return IntValue.Constant(basicValue, set) } @Throws(AnalyzerException::class) @@ -127,14 +125,14 @@ class IntInterpreter(private val parameters: Array?>?) : Interpreter): IntValue? { val args = values.map { it.basicValue }.toList() val basicValue = basicInterpreter.naryOperation(insn, args) ?: return null - return IntValue.newUnknown(basicValue) + return IntValue.Unknown(basicValue) } @Throws(AnalyzerException::class) @@ -149,15 +147,15 @@ class IntInterpreter(private val parameters: Array?>?) : Interpreter MAX_TRACKED_VALUES) { - IntValue.newUnknown(basicValue) + IntValue.Unknown(basicValue) } else { - IntValue.newConstant(basicValue, set) + IntValue.Constant(basicValue, set) } } diff --git a/deob/src/main/java/dev/openrs2/deob/analysis/IntValue.java b/deob/src/main/java/dev/openrs2/deob/analysis/IntValue.java deleted file mode 100644 index 986fb5cb24..0000000000 --- a/deob/src/main/java/dev/openrs2/deob/analysis/IntValue.java +++ /dev/null @@ -1,88 +0,0 @@ -package dev.openrs2.deob.analysis; - -import java.util.Objects; -import java.util.Set; - -import com.google.common.base.MoreObjects; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import org.objectweb.asm.tree.analysis.BasicValue; -import org.objectweb.asm.tree.analysis.Value; - -public final class IntValue implements Value { - public static IntValue newConstant(BasicValue basicValue, int intValue) { - return newConstant(basicValue, ImmutableSet.of(intValue)); - } - - public static IntValue newConstant(BasicValue basicValue, Set intValues) { - Preconditions.checkArgument(basicValue == BasicValue.INT_VALUE); - Preconditions.checkArgument(!intValues.isEmpty()); - return new IntValue(basicValue, intValues); - } - - public static IntValue newUnknown(BasicValue basicValue) { - Preconditions.checkNotNull(basicValue); - return new IntValue(basicValue, ImmutableSet.of()); - } - - private final BasicValue basicValue; - private final Set intValues; - - private IntValue(BasicValue basicValue, Set intValues) { - this.basicValue = basicValue; - this.intValues = intValues; - } - - public BasicValue getBasicValue() { - return basicValue; - } - - public boolean isUnknown() { - return intValues.isEmpty(); - } - - public boolean isSingleConstant() { - return intValues.size() == 1; - } - - public int getIntValue() { - Preconditions.checkState(isSingleConstant()); - return intValues.iterator().next(); - } - - public Set getIntValues() { - Preconditions.checkArgument(!isUnknown()); - return intValues; - } - - @Override - public int getSize() { - return basicValue.getSize(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IntValue intValue1 = (IntValue) o; - return basicValue.equals(intValue1.basicValue) && - Objects.equals(intValues, intValue1.intValues); - } - - @Override - public int hashCode() { - return Objects.hash(basicValue, intValues); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("basicValue", basicValue) - .add("intValues", intValues) - .toString(); - } -} diff --git a/deob/src/main/java/dev/openrs2/deob/analysis/IntValue.kt b/deob/src/main/java/dev/openrs2/deob/analysis/IntValue.kt new file mode 100644 index 0000000000..8455b874aa --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/analysis/IntValue.kt @@ -0,0 +1,25 @@ +package dev.openrs2.deob.analysis + +import org.objectweb.asm.tree.analysis.BasicValue +import org.objectweb.asm.tree.analysis.Value + +sealed class IntValue : Value { + data class Unknown(override val basicValue: BasicValue) : IntValue() + data class Constant(override val basicValue: BasicValue, val values: Set) : IntValue() { + val singleton: Int? + + init { + require(values.isNotEmpty()) + + singleton = if (values.size == 1) values.first() else null + } + + constructor(basicValue: BasicValue, value: Int) : this(basicValue, setOf(value)) + } + + abstract val basicValue: BasicValue + + override fun getSize(): Int { + return basicValue.size + } +} diff --git a/deob/src/main/java/dev/openrs2/deob/transform/DummyArgTransformer.kt b/deob/src/main/java/dev/openrs2/deob/transform/DummyArgTransformer.kt index 5aa698baeb..3d87747295 100644 --- a/deob/src/main/java/dev/openrs2/deob/transform/DummyArgTransformer.kt +++ b/deob/src/main/java/dev/openrs2/deob/transform/DummyArgTransformer.kt @@ -10,6 +10,7 @@ import dev.openrs2.asm.transform.Transformer import dev.openrs2.common.collect.DisjointSet import dev.openrs2.deob.ArgRef import dev.openrs2.deob.analysis.IntInterpreter +import dev.openrs2.deob.analysis.IntValue import dev.openrs2.deob.analysis.SourcedIntValue import org.objectweb.asm.Opcodes import org.objectweb.asm.Type @@ -106,7 +107,7 @@ class DummyArgTransformer : Transformer() { val set = mutableSetOf() for ((source, intValue) in intValues) { - if (intValue.isUnknown) { + if (intValue !is IntValue.Constant) { return null } @@ -114,13 +115,13 @@ class DummyArgTransformer : Transformer() { continue } - if (intValue.isSingleConstant) { - if (isMutuallyRecursiveDummy(method, arg, source, intValue.intValue)) { + if (intValue.singleton != null) { + if (isMutuallyRecursiveDummy(method, arg, source, intValue.singleton)) { continue } } - set.addAll(intValue.intValues) + set.addAll(intValue.values) } return if (set.isEmpty()) { @@ -237,11 +238,11 @@ class DummyArgTransformer : Transformer() { } Opcodes.IFEQ, Opcodes.IFNE -> { val value = frame.getStack(stackSize - 1) - if (value.isUnknown) { + if (value !is IntValue.Constant) { continue@frame } - val result = evaluateUnaryBranch(insn.opcode, value.intValues) + val result = evaluateUnaryBranch(insn.opcode, value.values) @Suppress("NON_EXHAUSTIVE_WHEN") when (result) { BranchResult.ALWAYS_TAKEN -> alwaysTakenBranches.add(insn as JumpInsnNode) @@ -251,11 +252,11 @@ class DummyArgTransformer : Transformer() { Opcodes.IF_ICMPEQ, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPLT, Opcodes.IF_ICMPGE, Opcodes.IF_ICMPGT, Opcodes.IF_ICMPLE -> { val value1 = frame.getStack(stackSize - 2) val value2 = frame.getStack(stackSize - 1) - if (value1.isUnknown || value2.isUnknown) { + if (value1 !is IntValue.Constant || value2 !is IntValue.Constant) { continue@frame } - val result = evaluateBinaryBranch(insn.opcode, value1.intValues, value2.intValues) + val result = evaluateBinaryBranch(insn.opcode, value1.values, value2.values) @Suppress("NON_EXHAUSTIVE_WHEN") when (result) { BranchResult.ALWAYS_TAKEN -> alwaysTakenBranches.add(insn as JumpInsnNode) @@ -276,8 +277,8 @@ class DummyArgTransformer : Transformer() { val nextFrame = frames[nextInsnIndex] val value = nextFrame.getStack(nextFrame.stackSize - 1) - if (value.isSingleConstant) { - constInsns[insn] = value.intValue + if (value is IntValue.Constant && value.singleton != null) { + constInsns[insn] = value.singleton } } }