From 272b1eb650f7e196e995ba9744b1280767dda051 Mon Sep 17 00:00:00 2001 From: Graham Date: Fri, 7 Aug 2020 17:23:13 +0100 Subject: [PATCH] Add support for removing an argument whose local variable slot is used This obviously doesn't work if the slot is loaded before something is stored in it, but it does allow us to remove unused arguments whose slot is re-used for another purpose. Signed-off-by: Graham --- .../java/dev/openrs2/asm/MethodNodeUtils.kt | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.kt b/asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.kt index c1fbc97b..ef8c62c6 100644 --- a/asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.kt +++ b/asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.kt @@ -21,16 +21,16 @@ private fun localIndex(access: Int, argTypes: Array, argIndex: Int): Int { return localIndex } -private fun remap(i: Int, argType: Type, localIndex: Int): Int { - return if (i >= localIndex) { - i - argType.size - } else { - i +private fun remap(i: Int, argType: Type, localIndex: Int, newLocalIndex: Int): Int { + return when { + i > localIndex -> i - argType.size + i == localIndex -> newLocalIndex + else -> i } } -private fun remapAll(indexes: List, argType: Type, localIndex: Int): MutableList { - return indexes.mapTo(mutableListOf()) { remap(it, argType, localIndex) } +private fun remapAll(indexes: List, argType: Type, localIndex: Int, newLocalIndex: Int): MutableList { + return indexes.mapTo(mutableListOf()) { remap(it, argType, localIndex, newLocalIndex) } } fun MethodNode.removeArgument(argIndex: Int) { @@ -68,36 +68,65 @@ fun MethodNode.removeArgument(argIndex: Int) { // remap locals val localIndex = localIndex(access, argTypes, argIndex) - maxLocals -= argType.size + val newLocalIndex = maxLocals - argType.size if (localVariables != null) { - localVariables.removeIf { it.index == localIndex } for (v in localVariables) { - v.index = remap(v.index, argType, localIndex) + v.index = remap(v.index, argType, localIndex, newLocalIndex) } } if (visibleLocalVariableAnnotations != null) { - visibleLocalVariableAnnotations.removeIf { localIndex in it.index } for (annotation in visibleLocalVariableAnnotations) { - annotation.index = remapAll(annotation.index, argType, localIndex) + annotation.index = remapAll(annotation.index, argType, localIndex, newLocalIndex) } } if (invisibleLocalVariableAnnotations != null) { - invisibleLocalVariableAnnotations.removeIf { localIndex in it.index } for (annotation in invisibleLocalVariableAnnotations) { - annotation.index = remapAll(annotation.index, argType, localIndex) + annotation.index = remapAll(annotation.index, argType, localIndex, newLocalIndex) } } + var newLocalIndexUsed = false + for (insn in instructions) { when (insn) { - is VarInsnNode -> insn.`var` = remap(insn.`var`, argType, localIndex) - is IincInsnNode -> insn.`var` = remap(insn.`var`, argType, localIndex) + is VarInsnNode -> { + insn.`var` = remap(insn.`var`, argType, localIndex, newLocalIndex) + + if (insn.`var` == newLocalIndex) { + newLocalIndexUsed = true + } + } + is IincInsnNode -> { + insn.`var` = remap(insn.`var`, argType, localIndex, newLocalIndex) + + if (insn.`var` == newLocalIndex) { + newLocalIndexUsed = true + } + } is FrameNode -> throw UnsupportedOperationException("SKIP_FRAMES and COMPUTE_FRAMES must be used") } } + + if (newLocalIndexUsed) { + return + } + + maxLocals -= argType.size + + if (localVariables != null) { + localVariables.removeIf { it.index == newLocalIndex } + } + + if (visibleLocalVariableAnnotations != null) { + visibleLocalVariableAnnotations.removeIf { newLocalIndex in it.index } + } + + if (invisibleLocalVariableAnnotations != null) { + invisibleLocalVariableAnnotations.removeIf { newLocalIndex in it.index } + } } fun MethodNode.removeDeadCode(owner: String) {