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 <gpe@openrs2.dev>
pull/132/head
Graham 4 years ago
parent 2b8aa0c70d
commit 272b1eb650
  1. 61
      asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.kt

@ -21,16 +21,16 @@ private fun localIndex(access: Int, argTypes: Array<Type>, argIndex: Int): Int {
return localIndex return localIndex
} }
private fun remap(i: Int, argType: Type, localIndex: Int): Int { private fun remap(i: Int, argType: Type, localIndex: Int, newLocalIndex: Int): Int {
return if (i >= localIndex) { return when {
i - argType.size i > localIndex -> i - argType.size
} else { i == localIndex -> newLocalIndex
i else -> i
} }
} }
private fun remapAll(indexes: List<Int>, argType: Type, localIndex: Int): MutableList<Int> { private fun remapAll(indexes: List<Int>, argType: Type, localIndex: Int, newLocalIndex: Int): MutableList<Int> {
return indexes.mapTo(mutableListOf()) { remap(it, argType, localIndex) } return indexes.mapTo(mutableListOf()) { remap(it, argType, localIndex, newLocalIndex) }
} }
fun MethodNode.removeArgument(argIndex: Int) { fun MethodNode.removeArgument(argIndex: Int) {
@ -68,36 +68,65 @@ fun MethodNode.removeArgument(argIndex: Int) {
// remap locals // remap locals
val localIndex = localIndex(access, argTypes, argIndex) val localIndex = localIndex(access, argTypes, argIndex)
maxLocals -= argType.size val newLocalIndex = maxLocals - argType.size
if (localVariables != null) { if (localVariables != null) {
localVariables.removeIf { it.index == localIndex }
for (v in localVariables) { for (v in localVariables) {
v.index = remap(v.index, argType, localIndex) v.index = remap(v.index, argType, localIndex, newLocalIndex)
} }
} }
if (visibleLocalVariableAnnotations != null) { if (visibleLocalVariableAnnotations != null) {
visibleLocalVariableAnnotations.removeIf { localIndex in it.index }
for (annotation in visibleLocalVariableAnnotations) { for (annotation in visibleLocalVariableAnnotations) {
annotation.index = remapAll(annotation.index, argType, localIndex) annotation.index = remapAll(annotation.index, argType, localIndex, newLocalIndex)
} }
} }
if (invisibleLocalVariableAnnotations != null) { if (invisibleLocalVariableAnnotations != null) {
invisibleLocalVariableAnnotations.removeIf { localIndex in it.index }
for (annotation in invisibleLocalVariableAnnotations) { 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) { for (insn in instructions) {
when (insn) { when (insn) {
is VarInsnNode -> insn.`var` = remap(insn.`var`, argType, localIndex) is VarInsnNode -> {
is IincInsnNode -> insn.`var` = remap(insn.`var`, argType, localIndex) 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") 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) { fun MethodNode.removeDeadCode(owner: String) {

Loading…
Cancel
Save