-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deal with cache misses due to timestamps from using ZipFileSystem ins…
…tead of ZipOutputStream to modify jars
- Loading branch information
1 parent
aef7fa2
commit 24591d6
Showing
4 changed files
with
103 additions
and
21 deletions.
There are no files selected for viewing
30 changes: 30 additions & 0 deletions
30
src/instrumentation/java/dev/lukebemish/taskgraphrunner/instrumentation/ASMUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package dev.lukebemish.taskgraphrunner.instrumentation; | ||
|
||
import org.objectweb.asm.ConstantDynamic; | ||
import org.objectweb.asm.Handle; | ||
import org.objectweb.asm.Opcodes; | ||
import org.objectweb.asm.Type; | ||
|
||
import java.lang.invoke.ConstantBootstraps; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.MethodType; | ||
|
||
final class ASMUtils { | ||
private ASMUtils() {} | ||
|
||
static ConstantDynamic booleanConstant(boolean bool) { | ||
return new ConstantDynamic( | ||
// booleans are funky in ConstantDynamics. Here's an alternative... | ||
bool ? "TRUE" : "FALSE", | ||
Boolean.class.descriptorString(), | ||
new Handle( | ||
Opcodes.H_INVOKESTATIC, | ||
Type.getInternalName(ConstantBootstraps.class), | ||
"getStaticFinal", | ||
MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class, Class.class).descriptorString(), | ||
false | ||
), | ||
Type.getType(Boolean.class) | ||
); | ||
} | ||
} |
32 changes: 28 additions & 4 deletions
32
src/instrumentation/java/dev/lukebemish/taskgraphrunner/instrumentation/AgentMain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,38 @@ | ||
package dev.lukebemish.taskgraphrunner.instrumentation; | ||
|
||
import java.lang.instrument.Instrumentation; | ||
import java.lang.instrument.UnmodifiableClassException; | ||
import java.util.zip.ZipOutputStream; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public final class AgentMain { | ||
private AgentMain() {} | ||
|
||
public static void premain(String args, Instrumentation instrumentation) throws UnmodifiableClassException { | ||
public static void premain(String args, Instrumentation instrumentation) { | ||
instrumentation.addTransformer(new ZipOutputStreamRetransformer(), true); | ||
instrumentation.retransformClasses(ZipOutputStream.class); | ||
instrumentation.addTransformer(new ZipFileSystemRetransformer(), true); | ||
try { | ||
Class<?> zipOutputStream = Class.forName("java.util.zip.ZipOutputStream"); | ||
instrumentation.retransformClasses(zipOutputStream); | ||
} catch (Throwable t) { | ||
System.err.printf("Failed to retransform ZipOutputStream: %s%n", t); | ||
} | ||
try { | ||
List<Class<?>> classes = new ArrayList<>(); | ||
Class<?> zipFileSystem = Class.forName("jdk.nio.zipfs.ZipFileSystem"); | ||
|
||
var nestFinder = new Object() { | ||
void findNested(Class<?> clazz) { | ||
classes.add(clazz); | ||
for (Class<?> nested : clazz.getDeclaredClasses()) { | ||
findNested(nested); | ||
} | ||
} | ||
}; | ||
|
||
nestFinder.findNested(zipFileSystem); | ||
instrumentation.retransformClasses(classes.toArray(Class<?>[]::new)); | ||
} catch (Throwable t) { | ||
System.err.printf("Failed to retransform ZipOutputStream: %s%n", t); | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
...ation/java/dev/lukebemish/taskgraphrunner/instrumentation/ZipFileSystemRetransformer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package dev.lukebemish.taskgraphrunner.instrumentation; | ||
|
||
import org.objectweb.asm.ClassReader; | ||
import org.objectweb.asm.ClassVisitor; | ||
import org.objectweb.asm.ClassWriter; | ||
import org.objectweb.asm.MethodVisitor; | ||
import org.objectweb.asm.Opcodes; | ||
|
||
import java.lang.instrument.ClassFileTransformer; | ||
import java.lang.instrument.IllegalClassFormatException; | ||
import java.security.ProtectionDomain; | ||
|
||
public class ZipFileSystemRetransformer implements ClassFileTransformer { | ||
ZipFileSystemRetransformer() {} | ||
|
||
@Override | ||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { | ||
// Let's just target everything nested in ZipFileSystem | ||
if (className.equals("jdk/nio/zipfs/ZipFileSystem") || className.startsWith("jdk/nio/zipfs/ZipFileSystem$")) { | ||
var classReader = new ClassReader(classfileBuffer); | ||
var writer = new ClassWriter(0); | ||
var visitor = new ClassVisitor(Opcodes.ASM9, writer) { | ||
@Override | ||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { | ||
// We're less selective than with ZOS here -- since the entries are not created in the file system, we can get away with just replacing the call to System.currentTimeMillis | ||
var delegate = super.visitMethod(access, name, descriptor, signature, exceptions); | ||
return new MethodVisitor(Opcodes.ASM9, delegate) { | ||
@Override | ||
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { | ||
if (name.equals("currentTimeMillis") && opcode == Opcodes.INVOKESTATIC && owner.equals("java/lang/System") && descriptor.equals("()J")) { | ||
super.visitLdcInsn(0L); | ||
} else { | ||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); | ||
} | ||
} | ||
}; | ||
} | ||
}; | ||
classReader.accept(visitor, 0); | ||
return writer.toByteArray(); | ||
} | ||
return ClassFileTransformer.super.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters