diff options
Diffstat (limited to 'agent/src')
-rw-r--r-- | agent/src/main/java/moe/nea/modernjava/agent/LenientType.java | 34 | ||||
-rw-r--r-- | agent/src/main/java/moe/nea/modernjava/agent/Pack200Retransformer.java | 90 |
2 files changed, 95 insertions, 29 deletions
diff --git a/agent/src/main/java/moe/nea/modernjava/agent/LenientType.java b/agent/src/main/java/moe/nea/modernjava/agent/LenientType.java new file mode 100644 index 0000000..88462f3 --- /dev/null +++ b/agent/src/main/java/moe/nea/modernjava/agent/LenientType.java @@ -0,0 +1,34 @@ +package moe.nea.modernjava.agent; + +import org.objectweb.asm.Type; + +public class LenientType { + /** + * {@link Type#getType(String)}, but implementing the old lenient behaviour. + * This deviates from the old behaviour in that it defaults to creating an object, + * instead of a method, but this is generally the desired behaviour. + */ + public static Type getType(String typeDescriptor) { + char c = 0; + if (!typeDescriptor.isEmpty()) { + c = typeDescriptor.charAt(0); + } + switch (c) { + case 'V': + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case '[': + case 'L': + case '(': + return Type.getType(typeDescriptor); + default: + return Type.getObjectType(typeDescriptor); + } + } +} diff --git a/agent/src/main/java/moe/nea/modernjava/agent/Pack200Retransformer.java b/agent/src/main/java/moe/nea/modernjava/agent/Pack200Retransformer.java index 67480bf..4d31329 100644 --- a/agent/src/main/java/moe/nea/modernjava/agent/Pack200Retransformer.java +++ b/agent/src/main/java/moe/nea/modernjava/agent/Pack200Retransformer.java @@ -3,6 +3,9 @@ package moe.nea.modernjava.agent; 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 org.objectweb.asm.Type; import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.commons.Remapper; @@ -20,33 +23,62 @@ import java.util.List; * but the java agent is far more reliable. */ public class Pack200Retransformer implements ClassFileTransformer { - // relocate("dev.architectury.pack200.java", "java.util.jar") - List<String> classes = Arrays.asList("AdaptiveCoding", "Attribute", "BandStructure", "ClassReader", "ClassWriter", "Code", "Coding", "CodingChooser", "CodingMethod", "ConstantPool", "Constants", "Driver", "DriverResource", "DriverResource_ja", "DriverResource_zh_CN", "FixedList", "Fixups", "Histogram", "Instruction", "NativeUnpack", "Pack200", "Pack200Adapter", "Pack200Plugin", "Package", "PackageReader", "PackageWriter", "PackerImpl", "PopulationCoding", "PropMap", "TLGlobals", "UnpackerImpl", "Utils"); - String architecturyPackage = "dev/architectury/pack200/java/"; - String javaPackage = "java/util/jar/"; - - public static void premain(String agentArgs, Instrumentation inst) { - inst.addTransformer(new Pack200Retransformer()); - } - - @Override - public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - ClassReader reader = new ClassReader(classfileBuffer); - ClassWriter writer = new ClassWriter(reader, 0); - Remapper remapper = new Remapper() { - @Override - public String map(String internalName) { - if (internalName.startsWith(javaPackage)) { - for (String aClass : classes) { - if (internalName.equals(javaPackage + aClass) || (internalName.startsWith(javaPackage + aClass + "$"))) - return internalName.replace(javaPackage, architecturyPackage); - } - } - return internalName; - } - }; - ClassVisitor visitor = new ClassRemapper(writer, remapper); - reader.accept(visitor, 0); - return writer.toByteArray(); - } + // relocate("dev.architectury.pack200.java", "java.util.jar") + List<String> classes = Arrays.asList("AdaptiveCoding", "Attribute", "BandStructure", "ClassReader", "ClassWriter", "Code", "Coding", "CodingChooser", "CodingMethod", "ConstantPool", "Constants", "Driver", "DriverResource", "DriverResource_ja", "DriverResource_zh_CN", "FixedList", "Fixups", "Histogram", "Instruction", "NativeUnpack", "Pack200", "Pack200Adapter", "Pack200Plugin", "Package", "PackageReader", "PackageWriter", "PackerImpl", "PopulationCoding", "PropMap", "TLGlobals", "UnpackerImpl", "Utils"); + String architecturyPackage = "dev/architectury/pack200/java/"; + String javaPackage = "java/util/jar/"; + + public static void premain(String agentArgs, Instrumentation inst) { + inst.addTransformer(new Pack200Retransformer()); + } + + @Override + public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + if (className.startsWith("moe/nea/modernjava/agent")) return classfileBuffer; + ClassReader reader = new ClassReader(classfileBuffer); + ClassWriter writer = new ClassWriter(reader, 0); + ClassVisitor visitor = writer; + visitor = getRemapVisitor(visitor); + visitor = getTypeVisitor(className, visitor); + reader.accept(visitor, 0); + return writer.toByteArray(); + } + + private ClassVisitor getRemapVisitor(ClassVisitor parent) { + Remapper remapper = new Remapper() { + @Override + public String map(String internalName) { + if (internalName.startsWith(javaPackage)) { + for (String aClass : classes) { + if (internalName.equals(javaPackage + aClass) || (internalName.startsWith(javaPackage + aClass + "$"))) + return internalName.replace(javaPackage, architecturyPackage); + } + } + return internalName; + } + }; + return new ClassRemapper(parent, remapper); + } + + private ClassVisitor getTypeVisitor(String className, ClassVisitor parent) { + if (className.startsWith("org/objectweb/asm/")) return parent; + return new ClassVisitor(Opcodes.ASM9, parent) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { + boolean isType = owner.equals("org/objectweb$/asm/Type".replace("$","")); + boolean isName = "getType".equals(name); + boolean isDesc = "(Ljava/lang/String;)Lorg/objectweb/asm/Type;".equals(descriptor); + if (isType && isName && isDesc) { + owner = Type.getInternalName(LenientType.class); + } + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + + } + }; + } + }; + } } |