From 293bf83e30d8c643192d70fa01b6375777998299 Mon Sep 17 00:00:00 2001 From: Graham Date: Fri, 12 Jan 2024 22:03:28 +0000 Subject: [PATCH] Improve initializer extraction in StaticFieldUnscrambler This commit makes the following improvements: - Converts the list of instructions in the entry and exit block to a set, which makes checking for containment more efficient. - Removes redundant excluded field filtering, which is already handled by the unscramble() method. - Treats fields written with PUTSTATIC outside the entry or exit block as complex, instead of just fields read with GETSTATIC. - Treats fields with multiple simple initializers as complex. - Treats fields where we fail to extract a simple initializer as complex. This fixes a bug where we accidentally thought those fields had no initializer. Signed-off-by: Graham --- .../bytecode/remap/StaticFieldUnscrambler.kt | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/StaticFieldUnscrambler.kt b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/StaticFieldUnscrambler.kt index 557c9329e3..a5c58f0d12 100644 --- a/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/StaticFieldUnscrambler.kt +++ b/deob-bytecode/src/main/kotlin/org/openrs2/deob/bytecode/remap/StaticFieldUnscrambler.kt @@ -57,7 +57,7 @@ public class StaticFieldUnscrambler( return fields } - private fun MethodNode.extractEntryExitBlocks(): List { + private fun MethodNode.extractEntryExitBlocks(): Set { /* * Most (or all?) of the methods have "simple" initializers * that we're capable of moving in the first and last basic blocks of @@ -69,14 +69,14 @@ public class StaticFieldUnscrambler( val last = instructions.lastOrNull() if (last == null || last.opcode != Opcodes.RETURN) { - return entry + return entry.toSet() } val exit = instructions.toList() .dropLast(1) .takeLastWhile { it.isSequential } - return entry.plus(exit) + return (entry + exit).toSet() } private fun MethodNode.extractInitializers( @@ -86,26 +86,35 @@ public class StaticFieldUnscrambler( val simpleInitializers = mutableMapOf>() val complexInitializers = instructions.asSequence() - .filter { !entryExitBlocks.contains(it) } + .filter { it !in entryExitBlocks } .filterIsInstance() - .filter { it.opcode == Opcodes.GETSTATIC && it.owner == owner } - .filter { !excludedFields.matches(it.owner, it.name, it.desc) } + .filter { it.owner == owner } .map(::MemberDesc) - .toSet() + .toMutableSet() val putstatics = entryExitBlocks .filterIsInstance() .filter { it.opcode == Opcodes.PUTSTATIC && it.owner == owner } - .filter { !excludedFields.matches(it.owner, it.name, it.desc) } for (putstatic in putstatics) { val desc = MemberDesc(putstatic) - if (simpleInitializers.containsKey(desc) || complexInitializers.contains(desc)) { + if (desc in complexInitializers) { + continue + } + + if (desc in simpleInitializers) { + simpleInitializers -= desc + complexInitializers += desc continue } // TODO(gpe): use a filter here (pure with no *LOADs?) - simpleInitializers[desc] = getExpression(putstatic) ?: continue + val initializer = getExpression(putstatic) + if (initializer != null) { + simpleInitializers[desc] = initializer + } else { + complexInitializers += desc + } } return Pair(simpleInitializers, complexInitializers)