From 9ff6b49ca2c559d6938715fd0b48bb8c3e2c1d19 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 14 Jul 2016 15:16:47 +0100 Subject: Simply method generation --- .../couscous/ast/visitors/DynamicNodeVisitor.java | 117 ++++++++------------- .../zwobble/couscous/util/asm/Implementations.java | 32 ++++++ 2 files changed, 76 insertions(+), 73 deletions(-) create mode 100644 src/main/java/org/zwobble/couscous/util/asm/Implementations.java (limited to 'src/main/java/org') diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java index 55419f7..75aaef4 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java @@ -5,18 +5,19 @@ import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.modifier.FieldManifestation; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.scaffold.InstrumentedType; -import net.bytebuddy.implementation.Implementation; -import net.bytebuddy.implementation.bytecode.*; +import net.bytebuddy.implementation.bytecode.Duplication; +import net.bytebuddy.implementation.bytecode.StackManipulation; +import net.bytebuddy.implementation.bytecode.Throw; +import net.bytebuddy.implementation.bytecode.TypeCreation; import net.bytebuddy.implementation.bytecode.assign.TypeCasting; import net.bytebuddy.implementation.bytecode.member.FieldAccess; import net.bytebuddy.implementation.bytecode.member.MethodInvocation; import net.bytebuddy.implementation.bytecode.member.MethodReturn; import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess; -import net.bytebuddy.jar.asm.MethodVisitor; import net.bytebuddy.matcher.ElementMatchers; import org.zwobble.couscous.ast.Node; import org.zwobble.couscous.ast.NodeTypes; +import org.zwobble.couscous.util.asm.Implementations; import org.zwobble.couscous.util.asm.StackManipulationSwitch; import org.zwobble.couscous.util.asm.TypeDescriptions; @@ -88,80 +89,50 @@ public class DynamicNodeVisitor { .defineConstructor(Visibility.PUBLIC) .withParameters(clazz) - .intercept(new Implementation() { - @Override - public InstrumentedType prepare(InstrumentedType instrumentedType) { - return instrumentedType; - } + .intercept(Implementations.stackManipulation(target -> new StackManipulation.Compound( + // this() + MethodVariableAccess.REFERENCE.loadOffset(0), + MethodInvocation.invoke(TypeDescriptions.findConstructor(Object.class)), - @Override - public ByteCodeAppender appender(Target implementationTarget) { - return new ByteCodeAppender() { - @Override - public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { - StackManipulation.Size size = new StackManipulation.Compound( - // this() - MethodVariableAccess.REFERENCE.loadOffset(0), - MethodInvocation.invoke(TypeDescriptions.findConstructor(Object.class)), + // this.visitor = visitor + MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadOffset(1), + FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).putter(), - // this.visitor = visitor - MethodVariableAccess.REFERENCE.loadOffset(0), - MethodVariableAccess.REFERENCE.loadOffset(1), - FieldAccess.forField(TypeDescriptions.findField(implementationTarget, "visitor")).putter(), - - // return - MethodReturn.VOID - ).apply(methodVisitor, implementationContext); - return new Size(size.getMaximalSize(), instrumentedMethod.getStackSize()); - } - }; - } - }) + // return + MethodReturn.VOID + ))) .method(ElementMatchers.named("accept")) - .intercept(new Implementation() { - @Override - public InstrumentedType prepare(InstrumentedType instrumentedType) { - return instrumentedType; - } - - @Override - public ByteCodeAppender appender(Target target) { - return new ByteCodeAppender() { - @Override - public Size apply(MethodVisitor methodVisitor, Context context, MethodDescription instrumentedMethod) { - MethodDescription typeMethod = TypeDescriptions.findMethod(Node.class, "type"); - StackManipulation.Size size = new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(1), - MethodInvocation.invoke(typeMethod), - new StackManipulationSwitch( - new StackManipulation.Compound( - TypeCreation.of(new TypeDescription.ForLoadedType(UnsupportedOperationException.class)), - Duplication.SINGLE, - MethodInvocation.invoke(TypeDescriptions.findConstructor(UnsupportedOperationException.class)), - Throw.INSTANCE - ), - eagerMap(visitMethods, method -> { - Class nodeClass = method.getParameterTypes()[0]; - return StackManipulationSwitch.switchCase( - NodeTypes.forClass(nodeClass), - new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), - FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).getter(), - MethodVariableAccess.REFERENCE.loadOffset(1), - TypeCasting.to(new TypeDescription.ForLoadedType(nodeClass)), - MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(method)), - MethodReturn.VOID - ) - ); - }) + .intercept(Implementations.stackManipulation(target -> { + MethodDescription typeMethod = TypeDescriptions.findMethod(Node.class, "type"); + return new StackManipulation.Compound( + MethodVariableAccess.REFERENCE.loadOffset(1), + MethodInvocation.invoke(typeMethod), + new StackManipulationSwitch( + new StackManipulation.Compound( + TypeCreation.of(new TypeDescription.ForLoadedType(UnsupportedOperationException.class)), + Duplication.SINGLE, + MethodInvocation.invoke(TypeDescriptions.findConstructor(UnsupportedOperationException.class)), + Throw.INSTANCE + ), + eagerMap(visitMethods, method -> { + Class nodeClass = method.getParameterTypes()[0]; + return StackManipulationSwitch.switchCase( + NodeTypes.forClass(nodeClass), + new StackManipulation.Compound( + MethodVariableAccess.REFERENCE.loadOffset(0), + FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).getter(), + MethodVariableAccess.REFERENCE.loadOffset(1), + TypeCasting.to(new TypeDescription.ForLoadedType(nodeClass)), + MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(method)), + MethodReturn.VOID ) - ).apply(methodVisitor, context); - return new Size(size.getMaximalSize(), instrumentedMethod.getStackSize()); - } - }; - } - }) + ); + }) + ) + ); + })) .make() .load(DynamicNodeVisitor.class.getClassLoader()) .getLoaded(); diff --git a/src/main/java/org/zwobble/couscous/util/asm/Implementations.java b/src/main/java/org/zwobble/couscous/util/asm/Implementations.java new file mode 100644 index 0000000..ee6911c --- /dev/null +++ b/src/main/java/org/zwobble/couscous/util/asm/Implementations.java @@ -0,0 +1,32 @@ +package org.zwobble.couscous.util.asm; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.dynamic.scaffold.InstrumentedType; +import net.bytebuddy.implementation.Implementation; +import net.bytebuddy.implementation.bytecode.ByteCodeAppender; +import net.bytebuddy.implementation.bytecode.StackManipulation; +import net.bytebuddy.jar.asm.MethodVisitor; + +import java.util.function.Function; + +public class Implementations { + public static Implementation stackManipulation(Function build) { + return new Implementation() { + @Override + public InstrumentedType prepare(InstrumentedType instrumentedType) { + return instrumentedType; + } + + @Override + public ByteCodeAppender appender(Target implementationTarget) { + return new ByteCodeAppender() { + @Override + public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { + return new ByteCodeAppender.Simple(build.apply(implementationTarget)) + .apply(methodVisitor, implementationContext, instrumentedMethod); + } + }; + } + }; + } +} -- cgit v1.2.3