Convert MethodNodeUtils to Kotlin

master
Graham 5 years ago
parent 862c79e31c
commit db785e38d0
  1. 173
      asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.java
  2. 134
      asm/src/main/java/dev/openrs2/asm/MethodNodeUtils.kt
  3. 4
      asm/src/main/java/dev/openrs2/asm/classpath/Library.java
  4. 4
      asm/src/main/java/dev/openrs2/asm/transform/Transformer.kt
  5. 4
      bundler/src/main/java/dev/openrs2/bundler/transform/BufferSizeTransformer.java
  6. 4
      deob/src/main/java/dev/openrs2/deob/transform/BitwiseOpTransformer.java
  7. 4
      deob/src/main/java/dev/openrs2/deob/transform/CounterTransformer.java
  8. 4
      deob/src/main/java/dev/openrs2/deob/transform/OpaquePredicateTransformer.java
  9. 6
      deob/src/main/java/dev/openrs2/deob/transform/ResetTransformer.java
  10. 8
      deob/src/main/java/dev/openrs2/deob/transform/UnusedArgTransformer.java

@ -1,173 +0,0 @@
package dev.openrs2.asm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.objectweb.asm.tree.analysis.Analyzer;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicInterpreter;
public final class MethodNodeUtils {
private static int localIndex(int access, List<Type> argTypes, int argIndex) {
var localIndex = 0;
if ((access & Opcodes.ACC_STATIC) == 0) {
localIndex++;
}
for (int i = 0; i < argIndex; i++) {
localIndex += argTypes.get(i).getSize();
}
return localIndex;
}
private static int remap(int i, Type argType, int localIndex) {
if (i >= localIndex) {
return i - argType.getSize();
}
return i;
}
private static List<Integer> remapAll(List<Integer> indexes, Type argType, int localIndex) {
return indexes.stream()
.map(i -> remap(i, argType, localIndex))
.collect(Collectors.toList());
}
public static void removeArgument(MethodNode method, int argIndex) {
/* remove argument from the signature */
var type = Type.getType(method.desc);
var argTypes = new ArrayList<>(Arrays.asList(type.getArgumentTypes()));
var argType = argTypes.remove(argIndex);
method.desc = Type.getMethodDescriptor(type.getReturnType(), argTypes.toArray(Type[]::new));
if (method.signature != null) {
throw new UnsupportedOperationException("Signatures unsupported");
}
/* calculate index of the local we're removing */
var localIndex = localIndex(method.access, argTypes, argIndex);
/* remove ParameterNode */
if (method.parameters != null) {
method.parameters.remove(argIndex);
}
/* remove annotations */
if (method.visibleAnnotableParameterCount != 0) {
throw new UnsupportedOperationException("Non-zero visibleAnnotableParameterCount unsupported");
}
if (method.visibleParameterAnnotations != null) {
@SuppressWarnings("unchecked")
var annotations = (List<AnnotationNode>[]) new List<?>[method.visibleParameterAnnotations.length - 1];
System.arraycopy(method.visibleParameterAnnotations, 0, annotations, 0, argIndex);
System.arraycopy(method.visibleParameterAnnotations, argIndex + 1, annotations, argIndex, method.visibleParameterAnnotations.length - argIndex - 1);
method.visibleParameterAnnotations = annotations;
}
if (method.invisibleAnnotableParameterCount != 0) {
throw new UnsupportedOperationException("Non-zero invisibleAnnotableParameterCount unsupported");
}
if (method.invisibleParameterAnnotations != null) {
@SuppressWarnings("unchecked")
var annotations = (List<AnnotationNode>[]) new List<?>[method.invisibleParameterAnnotations.length - 1];
System.arraycopy(method.invisibleParameterAnnotations, 0, annotations, 0, argIndex);
System.arraycopy(method.invisibleParameterAnnotations, argIndex + 1, annotations, argIndex, method.invisibleParameterAnnotations.length - argIndex - 1);
method.invisibleParameterAnnotations = annotations;
}
/* reduce maxLocals */
method.maxLocals -= argType.getSize();
/* remap locals */
if (method.localVariables != null) {
method.localVariables.removeIf(v -> v.index == localIndex);
method.localVariables.forEach(v -> v.index = remap(v.index, argType, localIndex));
}
if (method.visibleLocalVariableAnnotations != null) {
method.visibleLocalVariableAnnotations.removeIf(v -> v.index.contains(localIndex));
method.visibleLocalVariableAnnotations.forEach(v -> v.index = remapAll(v.index, argType, localIndex));
}
if (method.invisibleLocalVariableAnnotations != null) {
method.invisibleLocalVariableAnnotations.removeIf(v -> v.index.contains(localIndex));
method.invisibleLocalVariableAnnotations.forEach(v -> v.index = remapAll(v.index, argType, localIndex));
}
for (var insn : method.instructions) {
switch (insn.getType()) {
case AbstractInsnNode.VAR_INSN:
var varInsn = (VarInsnNode) insn;
varInsn.var = remap(varInsn.var, argType, localIndex);
break;
case AbstractInsnNode.IINC_INSN:
var iincInsn = (IincInsnNode) insn;
iincInsn.var = remap(iincInsn.var, argType, localIndex);
break;
case AbstractInsnNode.FRAME:
var frame = (FrameNode) insn;
if (frame.type != Opcodes.F_NEW) {
throw new UnsupportedOperationException("Only F_NEW frames are supported");
}
for (int i = 0; i < argType.getSize(); i++) {
frame.local.remove(localIndex);
}
break;
}
}
}
public static void removeDeadCode(String owner, MethodNode method) throws AnalyzerException {
boolean changed;
do {
changed = false;
var analyzer = new Analyzer<>(new BasicInterpreter());
var frames = analyzer.analyze(owner, method);
var deadLabels = new HashSet<LabelNode>();
var i = 0;
for (var it = method.instructions.iterator(); it.hasNext(); ) {
var insn = it.next();
if (frames[i++] != null) {
continue;
}
if (insn.getType() == AbstractInsnNode.LABEL) {
deadLabels.add((LabelNode) insn);
} else {
it.remove();
changed = true;
}
}
if (method.tryCatchBlocks.removeIf(tryCatch -> deadLabels.contains(tryCatch.start) && deadLabels.contains(tryCatch.end))) {
changed = true;
}
} while (changed);
}
public static boolean hasCode(MethodNode method) {
return (method.access & (Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT)) == 0;
}
private MethodNodeUtils() {
/* empty */
}
}

@ -0,0 +1,134 @@
package dev.openrs2.asm
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.*
import org.objectweb.asm.tree.analysis.Analyzer
import org.objectweb.asm.tree.analysis.AnalyzerException
import org.objectweb.asm.tree.analysis.BasicInterpreter
import org.objectweb.asm.tree.analysis.BasicValue
private fun localIndex(access: Int, argTypes: Array<Type>, argIndex: Int): Int {
var localIndex = 0
if (access and Opcodes.ACC_STATIC == 0) {
localIndex++
}
for (i in 0 until argIndex) {
localIndex += argTypes[i].size
}
return localIndex
}
private fun remap(i: Int, argType: Type, localIndex: Int): Int {
return if (i >= localIndex) {
i - argType.size
} else {
i
}
}
private fun remapAll(indexes: List<Int>, argType: Type, localIndex: Int): MutableList<Int> {
return indexes.map { remap(it, argType, localIndex) }.toMutableList()
}
fun MethodNode.removeArgument(argIndex: Int) {
// remove argument from the descriptor
val type = Type.getType(desc)
val argType = type.argumentTypes[argIndex]
val argTypes = type.argumentTypes.filterIndexed { index, _ -> index != argIndex }.toTypedArray()
desc = Type.getMethodDescriptor(type.returnType, *argTypes)
// the client doesn't use signatures so don't bother with them
if (signature != null) {
throw UnsupportedOperationException("Signatures unsupported")
}
parameters?.removeAt(argIndex)
// remove annotations
if (visibleAnnotableParameterCount != 0) {
throw UnsupportedOperationException("Non-zero visibleAnnotableParameterCount unsupported")
}
if (visibleParameterAnnotations != null) {
visibleParameterAnnotations =
visibleParameterAnnotations.filterIndexed { index, _ -> index != argIndex }.toTypedArray()
}
if (invisibleAnnotableParameterCount != 0) {
throw UnsupportedOperationException("Non-zero invisibleAnnotableParameterCount unsupported")
}
if (invisibleParameterAnnotations != null) {
invisibleParameterAnnotations =
invisibleParameterAnnotations.filterIndexed { index, _ -> index != argIndex }.toTypedArray()
}
// remap locals
val localIndex = localIndex(access, argTypes, argIndex)
maxLocals -= argType.size
if (localVariables != null) {
localVariables.removeIf { it.index == localIndex }
localVariables.forEach { it.index = remap(it.index, argType, localIndex) }
}
if (visibleLocalVariableAnnotations != null) {
visibleLocalVariableAnnotations.removeIf { it.index.contains(localIndex) }
visibleLocalVariableAnnotations.forEach { it.index = remapAll(it.index, argType, localIndex) }
}
if (invisibleLocalVariableAnnotations != null) {
invisibleLocalVariableAnnotations.removeIf { it.index.contains(localIndex) }
invisibleLocalVariableAnnotations.forEach { it.index = remapAll(it.index, argType, localIndex) }
}
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 FrameNode -> {
if (insn.type != Opcodes.F_NEW) {
throw UnsupportedOperationException("Only F_NEW frames are supported")
}
for (i in 0 until argType.size) {
insn.local.removeAt(localIndex)
}
}
}
}
}
@Throws(AnalyzerException::class)
fun MethodNode.removeDeadCode(owner: String) {
var changed: Boolean
do {
changed = false
val analyzer = Analyzer<BasicValue>(BasicInterpreter())
val frames = analyzer.analyze(owner, this)
val deadLabels = mutableSetOf<LabelNode>()
val it = instructions.iterator()
var i = 0
for (insn in it) {
if (frames[i++] != null) {
continue
}
if (insn is LabelNode) {
deadLabels.add(insn)
} else {
it.remove()
changed = true
}
}
changed = changed or tryCatchBlocks.removeIf { deadLabels.contains(it.start) && deadLabels.contains(it.end) }
} while (changed)
}
fun MethodNode.hasCode(): Boolean {
return access and (Opcodes.ACC_NATIVE or Opcodes.ACC_ABSTRACT) == 0
}

@ -15,7 +15,7 @@ import java.util.jar.JarOutputStream;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.remap.ClassForNameRemapper; import dev.openrs2.asm.remap.ClassForNameRemapper;
import dev.openrs2.util.io.DeterministicJarOutputStream; import dev.openrs2.util.io.DeterministicJarOutputStream;
import dev.openrs2.util.io.SkipOutputStream; import dev.openrs2.util.io.SkipOutputStream;
@ -119,7 +119,7 @@ public final class Library implements Iterable<ClassNode> {
for (var clazz : classes.values()) { for (var clazz : classes.values()) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (MethodNodeUtils.hasCode(method)) { if (MethodNodeUtilsKt.hasCode(method)) {
ClassForNameRemapper.remap(remapper, method); ClassForNameRemapper.remap(remapper, method);
} }
} }

@ -1,8 +1,8 @@
package dev.openrs2.asm.transform package dev.openrs2.asm.transform
import dev.openrs2.asm.MethodNodeUtils.hasCode
import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library import dev.openrs2.asm.classpath.Library
import dev.openrs2.asm.hasCode
import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldNode import org.objectweb.asm.tree.FieldNode
import org.objectweb.asm.tree.MethodNode import org.objectweb.asm.tree.MethodNode
@ -29,7 +29,7 @@ abstract class Transformer {
for (method in clazz.methods) { for (method in clazz.methods) {
changed = changed or preTransformMethod(classPath, library, clazz, method) changed = changed or preTransformMethod(classPath, library, clazz, method)
if (hasCode(method)) { if (method.hasCode()) {
changed = changed or transformCode(classPath, library, clazz, method) changed = changed or transformCode(classPath, library, clazz, method)
} }

@ -5,7 +5,7 @@ import java.util.Optional;
import dev.openrs2.asm.InsnMatcher; import dev.openrs2.asm.InsnMatcher;
import dev.openrs2.asm.InsnNodeUtils; import dev.openrs2.asm.InsnNodeUtils;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.classpath.ClassPath; import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer; import dev.openrs2.asm.transform.Transformer;
@ -46,7 +46,7 @@ public final class BufferSizeTransformer extends Transformer {
for (var library : classPath.getLibraries()) { for (var library : classPath.getLibraries()) {
for (var clazz : library) { for (var clazz : library) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (!MethodNodeUtils.hasCode(method)) { if (!MethodNodeUtilsKt.hasCode(method)) {
continue; continue;
} }

@ -5,7 +5,7 @@ import java.util.Map;
import dev.openrs2.asm.InsnMatcher; import dev.openrs2.asm.InsnMatcher;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.classpath.ClassPath; import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer; import dev.openrs2.asm.transform.Transformer;
@ -35,7 +35,7 @@ public final class BitwiseOpTransformer extends Transformer {
for (var library : classPath.getLibraries()) { for (var library : classPath.getLibraries()) {
for (var clazz : library) { for (var clazz : library) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (!MethodNodeUtils.hasCode(method)) { if (!MethodNodeUtilsKt.hasCode(method)) {
continue; continue;
} }

@ -7,7 +7,7 @@ import java.util.Set;
import dev.openrs2.asm.InsnMatcher; import dev.openrs2.asm.InsnMatcher;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.classpath.ClassPath; import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer; import dev.openrs2.asm.transform.Transformer;
@ -37,7 +37,7 @@ public final class CounterTransformer extends Transformer {
for (var library : classPath.getLibraries()) { for (var library : classPath.getLibraries()) {
for (var clazz : library) { for (var clazz : library) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (MethodNodeUtils.hasCode(method)) { if (MethodNodeUtilsKt.hasCode(method)) {
findCounters(method, references, resets, increments); findCounters(method, references, resets, increments);
} }
} }

@ -6,7 +6,7 @@ import java.util.Set;
import dev.openrs2.asm.InsnMatcher; import dev.openrs2.asm.InsnMatcher;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.classpath.ClassPath; import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer; import dev.openrs2.asm.transform.Transformer;
@ -39,7 +39,7 @@ public final class OpaquePredicateTransformer extends Transformer {
for (var library : classPath.getLibraries()) { for (var library : classPath.getLibraries()) {
for (var clazz : library) { for (var clazz : library) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (MethodNodeUtils.hasCode(method)) { if (MethodNodeUtilsKt.hasCode(method)) {
findFlowObstructors(library, method); findFlowObstructors(library, method);
} }
} }

@ -5,7 +5,7 @@ import java.util.Set;
import dev.openrs2.asm.InsnNodeUtils; import dev.openrs2.asm.InsnNodeUtils;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.classpath.ClassPath; import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer; import dev.openrs2.asm.transform.Transformer;
@ -66,7 +66,7 @@ public final class ResetTransformer extends Transformer {
} }
private static void findResetMethods(Set<MemberRef> resetMethods, ClassNode clazz, MethodNode method) throws AnalyzerException { private static void findResetMethods(Set<MemberRef> resetMethods, ClassNode clazz, MethodNode method) throws AnalyzerException {
MethodNodeUtils.removeDeadCode(clazz.name, method); MethodNodeUtilsKt.removeDeadCode(method, clazz.name);
for (var insn : method.instructions) { for (var insn : method.instructions) {
if (insn.getOpcode() == -1 || insn.getOpcode() != Opcodes.INVOKESTATIC) { if (insn.getOpcode() == -1 || insn.getOpcode() != Opcodes.INVOKESTATIC) {
@ -87,7 +87,7 @@ public final class ResetTransformer extends Transformer {
for (var library : classPath.getLibraries()) { for (var library : classPath.getLibraries()) {
for (var clazz : library) { for (var clazz : library) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (!MethodNodeUtils.hasCode(method)) { if (!MethodNodeUtilsKt.hasCode(method)) {
continue; continue;
} }

@ -8,7 +8,7 @@ import java.util.Set;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.asm.MethodNodeUtils; import dev.openrs2.asm.MethodNodeUtilsKt;
import dev.openrs2.asm.classpath.ClassPath; import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer; import dev.openrs2.asm.transform.Transformer;
@ -66,7 +66,7 @@ public final class UnusedArgTransformer extends Transformer {
for (var library : classPath.getLibraries()) { for (var library : classPath.getLibraries()) {
for (var clazz : library) { for (var clazz : library) {
for (var method : clazz.methods) { for (var method : clazz.methods) {
if (MethodNodeUtils.hasCode(method)) { if (MethodNodeUtilsKt.hasCode(method)) {
populateRetainedArgs(classPath, clazz, method); populateRetainedArgs(classPath, clazz, method);
} }
} }
@ -123,7 +123,7 @@ public final class UnusedArgTransformer extends Transformer {
@Override @Override
protected boolean preTransformMethod(ClassPath classPath, Library library, ClassNode clazz, MethodNode method) throws AnalyzerException { protected boolean preTransformMethod(ClassPath classPath, Library library, ClassNode clazz, MethodNode method) throws AnalyzerException {
/* delete unused int args from call sites */ /* delete unused int args from call sites */
if (MethodNodeUtils.hasCode(method)) { if (MethodNodeUtilsKt.hasCode(method)) {
var analyzer = new Analyzer<>(new ConstSourceInterpreter()); var analyzer = new Analyzer<>(new ConstSourceInterpreter());
var frames = analyzer.analyze(clazz.name, method); var frames = analyzer.analyze(clazz.name, method);
var deadInsns = new ArrayList<AbstractInsnNode>(); var deadInsns = new ArrayList<AbstractInsnNode>();
@ -185,7 +185,7 @@ public final class UnusedArgTransformer extends Transformer {
for (var i = argTypes.length - 1; i >= 0; i--) { for (var i = argTypes.length - 1; i >= 0; i--) {
var argType = argTypes[i]; var argType = argTypes[i];
if (INT_SORTS.contains(argType.getSort()) && !retainedArgs.contains(new ArgRef(partition, i))) { if (INT_SORTS.contains(argType.getSort()) && !retainedArgs.contains(new ArgRef(partition, i))) {
MethodNodeUtils.removeArgument(method, i); MethodNodeUtilsKt.removeArgument(method, i);
deletedArgs++; deletedArgs++;
} }
} }

Loading…
Cancel
Save