Skip to content

Commit

Permalink
Merge MethodSignatureProcessor into JarTransformerChain (#30)
Browse files Browse the repository at this point in the history
Before this commit, all class files were parsed twice.

This change results in a ~10% decrease in average runtime on the JUnit
benchmark.
  • Loading branch information
fmeum authored Jan 20, 2023
1 parent 8f8e7df commit 61aa594
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 117 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/github/johnynek/jarjar/MainProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean ski
processors.add(new ZapProcessor(zapList));
processors.add(misplacedClassProcessor);
processors.add(new JarTransformerChain(new RemappingClassTransformer[] {
new RemappingClassTransformer(pr)
new RemappingClassTransformer(pr),
new MethodSignatureClassTransformer(pr),
}));
processors.add(new MethodSignatureProcessor(pr));
processors.add(new ResourceProcessor(pr));
chain = new JarProcessorChain(processors.toArray(new JarProcessor[processors.size()]));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.github.johnynek.jarjar;

import com.github.johnynek.jarjar.util.RemappingClassTransformer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.Remapper;

/**
* Remaps string values representing method signatures to use the new package.
*
* <p>{@link PackageRemapper} is only able to remap string values which exactly match the package
* being renamed. Method signatures are more difficult to detect so this class keeps track of which
* methods definitely take method signatures and remaps those explicitly.
*/
public class MethodSignatureClassTransformer extends RemappingClassTransformer {

/**
* List of method names which take a method signature as their parameter.
*
* <p>Right now we assume all these methods take exactly one parameter and that it's a stirng.
*/
private static final Set<String> METHOD_NAMES_WITH_PARAMS_TO_REWRITE =
new HashSet<String>(Arrays.asList("getImplMethodSignature"));

public MethodSignatureClassTransformer(Remapper remapper) {
super(remapper);
}

@Override
public MethodVisitor visitMethod(
int access,
java.lang.String name,
java.lang.String descriptor,
java.lang.String signature,
java.lang.String[] exceptions) {
return new MethodSignatureRemapperMethodVisitor(
cv.visitMethod(access, name, descriptor, signature, exceptions));
}

private class MethodSignatureRemapperMethodVisitor extends MethodVisitor {

// Whether to attempt to rewrite the next ldc instruction we see.
// This will be safe because we will only look for methods that will always immediately take
// a string.
private boolean rewriteNextLdcInstruction = false;

private MethodSignatureRemapperMethodVisitor(MethodVisitor methodVisitor) {
super(Opcodes.ASM9, methodVisitor);
}

private boolean shouldMarkNextLdcForRewrite(int opcode, String name) {
return opcode == Opcodes.INVOKEVIRTUAL && METHOD_NAMES_WITH_PARAMS_TO_REWRITE.contains(name);
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor) {
rewriteNextLdcInstruction = shouldMarkNextLdcForRewrite(opcode, name);
mv.visitMethodInsn(opcode, owner, name, descriptor);
}

@Override
public void visitMethodInsn(
int opcode, String owner, String name, String descriptor, boolean isInterface) {
rewriteNextLdcInstruction = shouldMarkNextLdcForRewrite(opcode, name);
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

@Override
public void visitLdcInsn(Object value) {
if (rewriteNextLdcInstruction && value instanceof String) {
rewriteNextLdcInstruction = false;
mv.visitLdcInsn(remapper.mapSignature((String) value, false));
} else {
mv.visitLdcInsn(value);
}
}
}
}
114 changes: 0 additions & 114 deletions src/main/java/com/github/johnynek/jarjar/MethodSignatureProcessor.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.github.johnynek.jarjar;

import com.github.johnynek.jarjar.util.JarTransformerChain;
import com.github.johnynek.jarjar.util.RemappingClassTransformer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -65,7 +67,8 @@ public void testRewriteMethod() throws IOException {
Rule rule = new Rule();
rule.setPattern("com.google.**");
rule.setResult("com.googleshaded.@1");
new MethodSignatureProcessor(new PackageRemapper(Arrays.asList(rule), false))
new JarTransformerChain(new RemappingClassTransformer[]{
new MethodSignatureClassTransformer(new PackageRemapper(Arrays.asList(rule), false))})
.process(entryStruct);
new ClassReader(entryStruct.data)
.accept(new VerifyingClassVisitor(), ClassReader.EXPAND_FRAMES);
Expand Down

0 comments on commit 61aa594

Please sign in to comment.