From 4d267e491b84349a736eb611cc3b6a44ee6853b6 Mon Sep 17 00:00:00 2001 From: Gabriel Tofvesson Date: Thu, 28 Jan 2021 17:04:17 +0100 Subject: [PATCH] Implement interface injection --- src/dev/w1zzrd/asm/Combine.java | 47 ++++++++++++++++++- src/dev/w1zzrd/asm/GraftSource.java | 16 +++++-- .../w1zzrd/asm/analysis/AsmAnnotation.java | 14 +++++- .../exception/SignatureCheckException.java | 22 +++++++++ 4 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 src/dev/w1zzrd/asm/exception/SignatureCheckException.java diff --git a/src/dev/w1zzrd/asm/Combine.java b/src/dev/w1zzrd/asm/Combine.java index 9239107..cfad2e4 100644 --- a/src/dev/w1zzrd/asm/Combine.java +++ b/src/dev/w1zzrd/asm/Combine.java @@ -2,6 +2,7 @@ package dev.w1zzrd.asm; import dev.w1zzrd.asm.analysis.AsmAnnotation; import dev.w1zzrd.asm.exception.MethodNodeResolutionException; +import dev.w1zzrd.asm.exception.SignatureCheckException; import dev.w1zzrd.asm.exception.SignatureInstanceMismatchException; import dev.w1zzrd.asm.signature.MethodSignature; import dev.w1zzrd.asm.signature.TypeSignature; @@ -30,7 +31,7 @@ public class Combine { } public void inject(MethodNode node, GraftSource source) { - final AsmAnnotation annotation = source.getInjectAnnotation(node); + final AsmAnnotation annotation = source.getMethodInjectAnnotation(node); final boolean acceptReturn = annotation.getEntry("acceptOriginalReturn"); @@ -195,6 +196,50 @@ public class Combine { this.target.methods.add(inject); } + public void inject(FieldNode field, GraftSource source) { + if (field.desc.equals(source.getTypeName())) + field.desc = target.name; + + // Remove existing field with same name + for (FieldNode node : target.fields) + if (node.name.equals(field.name)) { + target.fields.remove(node); + break; + } + + target.fields.add(field); + } + + public void setSuperClass(String superDesc) { + // Theoretically usable for redefining Object (under a new ClassLoader) + if (superDesc == null) { + target.superName = null; + return; + } + + if (new TypeSignature(superDesc).isPrimitive()) + throw new SignatureCheckException("Superclass cannot be primitive: "+superDesc); + + target.superName = superDesc; + } + + public String getSuperclass() { + return target.superName; + } + + public TypeSignature[] getInterfaces() { + return target.interfaces.stream().map(TypeSignature::new).toArray(TypeSignature[]::new); + } + + public boolean removeInterface(String interfaceDesc) { + return target.interfaces.remove(interfaceDesc); + } + + public void addInterface(String interfaceDesc) { + if (!target.interfaces.contains(interfaceDesc)) + target.interfaces.add(interfaceDesc); + } + private boolean initiateGrafting(MethodNode node, GraftSource source) { DynamicSourceUnit unit = new DynamicSourceUnit(source, node); diff --git a/src/dev/w1zzrd/asm/GraftSource.java b/src/dev/w1zzrd/asm/GraftSource.java index 018b25d..f6b0f20 100644 --- a/src/dev/w1zzrd/asm/GraftSource.java +++ b/src/dev/w1zzrd/asm/GraftSource.java @@ -132,18 +132,26 @@ public final class GraftSource { return methodAnnotations .keySet() .stream() - .sorted(Comparator.comparingInt(a -> getInjectAnnotation(a).getEntry("priority"))) + .sorted(Comparator.comparingInt(a -> getMethodInjectAnnotation(a).getEntry("priority"))) .collect(Collectors.toList()); } - public Set getInjectFields() { - return fieldAnnotations.keySet(); + public List getInjectFields() { + return fieldAnnotations + .keySet() + .stream() + .sorted(Comparator.comparingInt(a -> getFieldInjectAnnotation(a).getEntry("priority"))) + .collect(Collectors.toList()); } - public AsmAnnotation getInjectAnnotation(MethodNode node) { + public AsmAnnotation getMethodInjectAnnotation(MethodNode node) { return getInjectionDirective(methodAnnotations.get(node)); } + public AsmAnnotation getFieldInjectAnnotation(FieldNode node) { + return getInjectionDirective(fieldAnnotations.get(node)); + } + private static boolean hasNoInjectionDirective(List> annotations) { return getInjectionDirective(annotations) == null; } diff --git a/src/dev/w1zzrd/asm/analysis/AsmAnnotation.java b/src/dev/w1zzrd/asm/analysis/AsmAnnotation.java index a5f3e55..3bde844 100644 --- a/src/dev/w1zzrd/asm/analysis/AsmAnnotation.java +++ b/src/dev/w1zzrd/asm/analysis/AsmAnnotation.java @@ -102,6 +102,18 @@ public final class AsmAnnotation { return hasDefaultEntry(name) || hasExplicitEntry(name); } + public static AsmAnnotation getAnnotation(Class find, Iterable nodes) { + if (nodes == null) + return null; + + for (AnnotationNode node : nodes) { + AsmAnnotation annot = getAnnotation(node); + if (annot.getAnnotationType().equals(find)) + return annot; + } + + return null; + } public static AsmAnnotation getAnnotation(AnnotationNode node) { Class cls; @@ -116,6 +128,6 @@ public final class AsmAnnotation { for (int i = 0; i < node.values.size(); i += 2) entries.put((String)node.values.get(i), node.values.get(i + 1)); - return new AsmAnnotation(cls, entries); + return new AsmAnnotation<>(cls, entries); } } diff --git a/src/dev/w1zzrd/asm/exception/SignatureCheckException.java b/src/dev/w1zzrd/asm/exception/SignatureCheckException.java new file mode 100644 index 0000000..c308927 --- /dev/null +++ b/src/dev/w1zzrd/asm/exception/SignatureCheckException.java @@ -0,0 +1,22 @@ +package dev.w1zzrd.asm.exception; + +public final class SignatureCheckException extends RuntimeException { + public SignatureCheckException() { + } + + public SignatureCheckException(String message) { + super(message); + } + + public SignatureCheckException(String message, Throwable cause) { + super(message, cause); + } + + public SignatureCheckException(Throwable cause) { + super(cause); + } + + public SignatureCheckException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +}