From 98b6fc96083745d0fa7bff53c50ddac989728e2c Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Sat, 20 Aug 2022 23:37:19 +0200 Subject: [PATCH] Use new frame generation abstraction and add more tests. --- .../bytebuddy/asm/ClassVisitorFactory.java | 137 ++++++------- .../build/AccessControllerPlugin.java | 62 +----- .../implementation/EqualsMethod.java | 84 +------- .../implementation/HashCodeMethod.java | 30 +-- .../implementation/Implementation.java | 194 +++++++++++++++++- ...lementationContextFrameGenerationTest.java | 124 +++++++++++ 6 files changed, 400 insertions(+), 231 deletions(-) create mode 100644 byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextFrameGenerationTest.java diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/asm/ClassVisitorFactory.java b/byte-buddy-dep/src/main/java/net/bytebuddy/asm/ClassVisitorFactory.java index 1ab2516a54f..1c7d469e754 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/asm/ClassVisitorFactory.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/asm/ClassVisitorFactory.java @@ -21,6 +21,7 @@ import net.bytebuddy.description.modifier.FieldManifestation; import net.bytebuddy.description.modifier.Ownership; import net.bytebuddy.description.modifier.Visibility; +import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.loading.MultipleParentClassLoader; @@ -39,6 +40,7 @@ import net.bytebuddy.implementation.bytecode.member.MethodReturn; import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess; import net.bytebuddy.matcher.ElementMatchers; +import net.bytebuddy.utility.CompoundList; import net.bytebuddy.utility.OpenedClassReader; import org.objectweb.asm.*; @@ -484,9 +486,7 @@ public Size apply(MethodVisitor methodVisitor, false); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(label); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(3, 1); @@ -528,9 +528,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(nullCheck); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, CompoundList.of( + implementationContext.getInstrumentedType(), + instrumentedMethod.getParameters().asTypeList())); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitFieldInsn(Opcodes.GETFIELD, implementationContext.getInstrumentedType().getInternalName(), @@ -567,9 +567,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa true); methodVisitor.visitInsn(Opcodes.POP); methodVisitor.visitLabel(end); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Type.getInternalName(target)}, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().append(methodVisitor, + Collections.singletonList(TypeDescription.ForLoadedType.of(target)), + CompoundList.of(implementationContext.getInstrumentedType(), instrumentedMethod.getParameters().asTypeList())); methodVisitor.visitVarInsn(Opcodes.ALOAD, 2); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(3, 3); @@ -618,9 +618,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(nullCheck); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, CompoundList.of( + implementationContext.getInstrumentedType(), + instrumentedMethod.getParameters().asTypeList())); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(targetLabel)); @@ -628,9 +628,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitVarInsn(Opcodes.ISTORE, 3); methodVisitor.visitLabel(loop); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{"[L" + Type.getInternalName(targetLabel) + ";", Opcodes.INTEGER}, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().append(methodVisitor, + Arrays.asList(TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.of(targetLabel)), TypeDescription.ForLoadedType.of(int.class)), + CompoundList.of(implementationContext.getInstrumentedType(), instrumentedMethod.getParameters().asTypeList())); methodVisitor.visitVarInsn(Opcodes.ILOAD, 3); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); @@ -650,10 +650,10 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitIincInsn(3, 1); methodVisitor.visitJumpInsn(Opcodes.GOTO, loop); methodVisitor.visitLabel(end); - - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_CHOP, 1, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of( + Collections.singletonList(implementationContext.getInstrumentedType()), + instrumentedMethod.getParameters().asTypeList(), + Collections.singletonList(TypeDescription.ArrayProjection.of(TypeDescription.ForLoadedType.of(targetLabel))))); methodVisitor.visitVarInsn(Opcodes.ALOAD, 2); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(5, 4); @@ -702,9 +702,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(nullCheck); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(targetHandle)); methodVisitor.visitInsn(Opcodes.DUP); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); @@ -808,9 +806,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitVarInsn(Opcodes.ISTORE, 2); methodVisitor.visitLabel(loop); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{Type.getInternalName(Object[].class), Opcodes.INTEGER}, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().append(methodVisitor, + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)), + instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitVarInsn(Opcodes.ILOAD, 2); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); @@ -833,9 +831,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(Opcodes.GOTO, loop); methodVisitor.visitLabel(end); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_CHOP, 1, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of( + instrumentedMethod.getParameters().asTypeList(), + TypeDescription.ForLoadedType.of(Object[].class))); methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(targetConstantDynamic)); methodVisitor.visitInsn(Opcodes.DUP); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); @@ -954,9 +952,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa false); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(noHandle); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, Type.getInternalName(sourceType)); methodVisitor.visitJumpInsn(Opcodes.IFEQ, noType); @@ -974,9 +970,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa false); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(noType); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, Type.getInternalName(sourceConstantDynamic)); methodVisitor.visitJumpInsn(Opcodes.IFEQ, noConstantDynamic); @@ -989,9 +983,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa false); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(noConstantDynamic); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(1, 1); @@ -1019,9 +1011,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(nullCheck); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(Object.class)); @@ -1029,9 +1019,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitVarInsn(Opcodes.ISTORE, 2); methodVisitor.visitLabel(loop); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{"[Ljava/lang/Object;", Opcodes.INTEGER}, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().append(methodVisitor, + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)), + instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitVarInsn(Opcodes.ILOAD, 2); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); @@ -1050,9 +1040,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitIincInsn(2, 1); methodVisitor.visitJumpInsn(Opcodes.GOTO, loop); methodVisitor.visitLabel(end); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_CHOP, 1, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of( + instrumentedMethod.getParameters().asTypeList(), + TypeDescription.ForLoadedType.of(Object[].class))); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(4, 3); @@ -1101,9 +1091,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitLabel(nullCheck); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, CompoundList.of( + implementationContext.getInstrumentedType(), + instrumentedMethod.getParameters().asTypeList())); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, Type.getInternalName(Object.class)); @@ -1111,9 +1101,9 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitVarInsn(Opcodes.ISTORE, 3); methodVisitor.visitLabel(loop); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{Type.getInternalName(Object[].class), Opcodes.INTEGER}, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().append(methodVisitor, + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)), + CompoundList.of(implementationContext.getInstrumentedType(), instrumentedMethod.getParameters().asTypeList())); methodVisitor.visitVarInsn(Opcodes.ILOAD, 3); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitInsn(Opcodes.ARRAYLENGTH); @@ -1137,31 +1127,30 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa false); methodVisitor.visitJumpInsn(Opcodes.GOTO, store); methodVisitor.visitLabel(label); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_FULL, - 4, - new Object[]{implementationContext.getInstrumentedType().getInternalName(), Type.getInternalName(Object[].class), Type.getInternalName(Object[].class), Opcodes.INTEGER}, - 2, - new Object[]{Type.getInternalName(Object[].class), Opcodes.INTEGER}); - } + implementationContext.getFrameGeneration().full(methodVisitor, + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)), + CompoundList.of( + Collections.singletonList(implementationContext.getInstrumentedType()), + instrumentedMethod.getParameters().asTypeList(), + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)))); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitVarInsn(Opcodes.ILOAD, 3); methodVisitor.visitInsn(Opcodes.AALOAD); methodVisitor.visitLabel(store); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_FULL, - 4, - new Object[]{implementationContext.getInstrumentedType().getInternalName(), Type.getInternalName(Object[].class), Type.getInternalName(Object[].class), Opcodes.INTEGER}, - 3, - new Object[]{Type.getInternalName(Object[].class), Opcodes.INTEGER, Type.getInternalName(Object.class)}); - } + implementationContext.getFrameGeneration().full(methodVisitor, + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class), TypeDescription.OBJECT), + CompoundList.of( + Collections.singletonList(implementationContext.getInstrumentedType()), + instrumentedMethod.getParameters().asTypeList(), + Arrays.asList(TypeDescription.ForLoadedType.of(Object[].class), TypeDescription.ForLoadedType.of(int.class)))); methodVisitor.visitInsn(Opcodes.AASTORE); methodVisitor.visitIincInsn(3, 1); methodVisitor.visitJumpInsn(Opcodes.GOTO, loop); methodVisitor.visitLabel(end); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_CHOP, 1, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().chop(methodVisitor, 1, CompoundList.of( + Collections.singletonList(implementationContext.getInstrumentedType()), + instrumentedMethod.getParameters().asTypeList(), + Collections.singletonList(TypeDescription.ForLoadedType.of(Object[].class)))); methodVisitor.visitVarInsn(Opcodes.ALOAD, 2); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(5, 4); @@ -1209,9 +1198,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, nullCheck); methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitJumpInsn(Opcodes.GOTO, end); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - } + implementationContext.getFrameGeneration().same(methodVisitor, instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitLabel(nullCheck); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, @@ -1224,10 +1211,10 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa "fromString", Type.getMethodDescriptor(Type.getType(targetTypePath), Type.getType(String.class)), false); - if (implementationContext.getFrameGeneration().isActive()) { // TODO - methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, 1, new Object[]{Type.getInternalName(targetTypePath)}); - } methodVisitor.visitLabel(end); + implementationContext.getFrameGeneration().same1(methodVisitor, + TypeDescription.ForLoadedType.of(targetTypePath), + instrumentedMethod.getParameters().asTypeList()); methodVisitor.visitInsn(Opcodes.ARETURN); return new Size(1, 2); } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/build/AccessControllerPlugin.java b/byte-buddy-dep/src/main/java/net/bytebuddy/build/AccessControllerPlugin.java index 7d58fb4fb12..b2e5ade4c07 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/build/AccessControllerPlugin.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/build/AccessControllerPlugin.java @@ -21,6 +21,7 @@ import net.bytebuddy.description.modifier.FieldManifestation; import net.bytebuddy.description.modifier.Ownership; import net.bytebuddy.description.modifier.Visibility; +import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.DynamicType; @@ -40,6 +41,7 @@ import java.security.Permission; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -273,51 +275,22 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa methodVisitor.visitLabel(end); methodVisitor.visitJumpInsn(Opcodes.GOTO, complete); methodVisitor.visitLabel(classNotFound); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, 1, new Object[]{Type.getInternalName(ClassNotFoundException.class)}); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, 1, new Object[]{Type.getInternalName(ClassNotFoundException.class)}); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same1(methodVisitor, + TypeDescription.ForLoadedType.of(ClassNotFoundException.class), + Collections.emptyList()); methodVisitor.visitInsn(Opcodes.POP); methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitFieldInsn(Opcodes.PUTSTATIC, instrumentedType.getInternalName(), name, Type.getDescriptor(boolean.class)); methodVisitor.visitJumpInsn(Opcodes.GOTO, complete); methodVisitor.visitLabel(securityException); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, 1, new Object[]{Type.getInternalName(SecurityException.class)}); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, 1, new Object[]{Type.getInternalName(SecurityException.class)}); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same1(methodVisitor, + TypeDescription.ForLoadedType.of(SecurityException.class), + Collections.emptyList()); methodVisitor.visitInsn(Opcodes.POP); methodVisitor.visitInsn(Opcodes.ICONST_1); methodVisitor.visitFieldInsn(Opcodes.PUTSTATIC, instrumentedType.getInternalName(), name, Type.getDescriptor(boolean.class)); methodVisitor.visitLabel(complete); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same(methodVisitor, Collections.emptyList()); return new Size(Math.max(3, size), 0); } @@ -513,22 +486,7 @@ public void visitCode() { false); mv.visitInsn(Type.getType(token.getReturnType().getDescriptor()).getOpcode(Opcodes.IRETURN)); mv.visitLabel(label); - switch (frameGeneration) { - case GENERATE: - mv.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - break; - case EXPAND: - Object[] localVariable = new Object[token.getParameterTypes().size()]; - for (int index = 0; index < localVariable.length; index++) { - localVariable[index] = token.getParameterTypes().get(index).getInternalName(); - } - mv.visitFrame(Opcodes.F_NEW, localVariable.length, localVariable, EMPTY.length, EMPTY); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + frameGeneration.same(mv, token.getParameterTypes()); } @Override diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/EqualsMethod.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/EqualsMethod.java index b1ce9d8fc58..3c72d91a70e 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/EqualsMethod.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/EqualsMethod.java @@ -36,7 +36,6 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; import java.util.*; @@ -401,16 +400,6 @@ public int getRequiredVariablePadding() { @HashCodeAndEqualsPlugin.Enhance class UsingJump implements NullValueGuard { - /** - * An empty array. - */ - private static final Object[] EMPTY = new Object[0]; - - /** - * An array containing a single reference value. - */ - private static final Object[] REFERENCE = new Object[]{Type.getInternalName(Object.class)}; - /** * The instrumented method. */ @@ -498,59 +487,18 @@ protected class AfterInstruction extends StackManipulation.AbstractBase { public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitJumpInsn(Opcodes.GOTO, endOfBlock); methodVisitor.visitLabel(secondValueNull); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, REFERENCE.length, REFERENCE); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, - 2, - new Object[]{implementationContext.getInstrumentedType().getInternalName(), Type.getInternalName(Object.class)}, - REFERENCE.length, - REFERENCE); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same1(methodVisitor, + TypeDescription.OBJECT, + Arrays.asList(implementationContext.getInstrumentedType(), TypeDescription.OBJECT)); methodVisitor.visitJumpInsn(Opcodes.IFNULL, endOfBlock); methodVisitor.visitLabel(firstValueNull); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, - 2, - new Object[]{implementationContext.getInstrumentedType().getInternalName(), Type.getInternalName(Object.class)}, - EMPTY.length, - EMPTY); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same(methodVisitor, + Arrays.asList(implementationContext.getInstrumentedType(), TypeDescription.OBJECT)); methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitInsn(Opcodes.IRETURN); methodVisitor.visitLabel(endOfBlock); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, - 2, - new Object[]{implementationContext.getInstrumentedType().getInternalName(), Type.getInternalName(Object.class)}, - EMPTY.length, - EMPTY); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same(methodVisitor, + Arrays.asList(implementationContext.getInstrumentedType(), TypeDescription.OBJECT)); return Size.ZERO; } } @@ -949,22 +897,8 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitInsn(value); methodVisitor.visitInsn(Opcodes.IRETURN); methodVisitor.visitLabel(label); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, - 2, - new Object[]{implementationContext.getInstrumentedType().getInternalName(), Type.getInternalName(Object.class)}, - EMPTY.length, - EMPTY); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same(methodVisitor, + Arrays.asList(implementationContext.getInstrumentedType(), TypeDescription.OBJECT)); return new Size(-1, 1); } } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/HashCodeMethod.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/HashCodeMethod.java index 9d8c31ad563..fbfd792c918 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/HashCodeMethod.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/HashCodeMethod.java @@ -35,6 +35,7 @@ import org.objectweb.asm.Opcodes; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static net.bytebuddy.matcher.ElementMatchers.*; @@ -382,16 +383,6 @@ public int getRequiredVariablePadding() { @HashCodeAndEqualsPlugin.Enhance class UsingJump implements NullValueGuard { - /** - * An empty array. - */ - private static final Object[] EMPTY = new Object[0]; - - /** - * An array that only contains an integer stack map frame. - */ - private static final Object[] INTEGER = new Object[]{Opcodes.INTEGER}; - /** * The instrumented method. */ @@ -462,22 +453,9 @@ protected class AfterInstruction extends StackManipulation.AbstractBase { */ public Size apply(MethodVisitor methodVisitor, Context implementationContext) { methodVisitor.visitLabel(label); - switch (implementationContext.getFrameGeneration()) { - case GENERATE: - methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, INTEGER.length, INTEGER); - break; - case EXPAND: - methodVisitor.visitFrame(Opcodes.F_NEW, - 1, - new Object[]{implementationContext.getInstrumentedType().getInternalName()}, - INTEGER.length, - INTEGER); - break; - case DISABLED: - break; - default: - throw new IllegalStateException(); - } + implementationContext.getFrameGeneration().same1(methodVisitor, + TypeDescription.ForLoadedType.of(int.class), + Arrays.asList(implementationContext.getInstrumentedType(), TypeDescription.OBJECT)); return Size.ZERO; } } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java index 0e194662bac..8622b2dbb52 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java @@ -554,17 +554,58 @@ enum FrameGeneration { /** * Indicates that frames should be generated. */ - GENERATE(true), + GENERATE(true) { + @Override + public void generate(MethodVisitor methodVisitor, + int type, + int stackCount, + @MaybeNull Object[] stack, + int changedLocalVariableCount, + @MaybeNull Object[] changedLocalVariable, + int fullLocalVariableCount, + @MaybeNull Object[] fullLocalVariable) { + methodVisitor.visitFrame(type, changedLocalVariableCount, changedLocalVariable, stackCount, stack); + } + }, /** * Indicates that frames should be generated and expanded. */ - EXPAND(true), + EXPAND(true) { + @Override + public void generate(MethodVisitor methodVisitor, + int type, + int stackCount, + @MaybeNull Object[] stack, + int changedLocalVariableCount, + @MaybeNull Object[] changedLocalVariable, + int fullLocalVariableCount, + @MaybeNull Object[] fullLocalVariable) { + methodVisitor.visitFrame(Opcodes.F_NEW, fullLocalVariableCount, fullLocalVariable, stackCount, stack); + } + }, /** * Indicates that no frames should be generated. */ - DISABLED(false); + DISABLED(false) { + @Override + public void generate(MethodVisitor methodVisitor, + int type, + int stackCount, + @MaybeNull Object[] stack, + int changedLocalVariableCount, + @MaybeNull Object[] changedLocalVariable, + int fullLocalVariableCount, + @MaybeNull Object[] fullLocalVariable) { + /* do nothing */ + } + }; + + /** + * An empty array to reuse for empty frames. + */ + private static final Object[] EMPTY = new Object[0]; /** * {@code true} if frames should be generated. @@ -588,6 +629,153 @@ enum FrameGeneration { public boolean isActive() { return active; } + + /** + * Inserts a {@link Opcodes#F_SAME} frame. + * + * @param methodVisitor The method visitor to write to. + * @param localVariables The local variables that are defined at this frame location. + */ + public void same(MethodVisitor methodVisitor, + List localVariables) { + generate(methodVisitor, + Opcodes.F_SAME, + EMPTY.length, + EMPTY, + EMPTY.length, + EMPTY, + localVariables.size(), + toStackMapFrames(localVariables)); + } + + /** + * Inserts a {@link Opcodes#F_SAME1} frame. + * + * @param methodVisitor The method visitor to write to. + * @param stackValue The single stack value. + * @param localVariables The local variables that are defined at this frame location. + */ + public void same1(MethodVisitor methodVisitor, + TypeDefinition stackValue, + List localVariables) { + generate(methodVisitor, + Opcodes.F_SAME1, + 1, + new Object[]{toStackMapFrame(stackValue)}, + EMPTY.length, + EMPTY, + localVariables.size(), + toStackMapFrames(localVariables)); + } + + /** + * Inserts a {@link Opcodes#F_APPEND} frame. + * + * @param methodVisitor The method visitor to write to. + * @param appended The appended local variables. + * @param localVariables The local variables that are defined at this frame location, excluding the ones appended. + */ + public void append(MethodVisitor methodVisitor, + List appended, + List localVariables) { + generate(methodVisitor, + Opcodes.F_APPEND, + EMPTY.length, + EMPTY, + appended.size(), + toStackMapFrames(appended), + localVariables.size() + appended.size(), + toStackMapFrames(CompoundList.of(localVariables, appended))); + } + + /** + * Inserts a {@link Opcodes#F_CHOP} frame. + * + * @param methodVisitor The method visitor to write to. + * @param chopped The number of chopped values. + * @param localVariables The local variables that are defined at this frame location, excluding the chopped variables. + */ + public void chop(MethodVisitor methodVisitor, + int chopped, + List localVariables) { + generate(methodVisitor, + Opcodes.F_CHOP, + EMPTY.length, + EMPTY, + chopped, + EMPTY, + localVariables.size(), + toStackMapFrames(localVariables)); + } + + /** + * Inserts a {@link Opcodes#F_FULL} frame. + * + * @param methodVisitor The method visitor to write to. + * @param stackValues The values on the operand stack. + * @param localVariables The local variables that are defined at this frame location. + */ + public void full(MethodVisitor methodVisitor, + List stackValues, + List localVariables) { + generate(methodVisitor, + Opcodes.F_FULL, + stackValues.size(), + toStackMapFrames(stackValues), + localVariables.size(), + toStackMapFrames(localVariables), + localVariables.size(), + toStackMapFrames(localVariables)); + } + + /** + * Writes frames to a {@link MethodVisitor}, if applicable. + * + * @param methodVisitor The method visitor to use + * @param type The frame type. + * @param stackCount The number of values on the operand stack. + * @param stack The values on the operand stack up to {@code stackCount}, or {@link null}, if none. + * @param changedLocalVariableCount The number of local variables that were changed. + * @param changedLocalVariable The values added to the local variable array up to {@code changedLocalVariableCount} + * or {@link null}, if none or not applicable. + * @param fullLocalVariableCount The number of local variables. + * @param fullLocalVariable The total number of local variables up to {@code fullLocalVariableCount} or + * {@code null}, if none. + */ + protected abstract void generate(MethodVisitor methodVisitor, + int type, + int stackCount, + @MaybeNull Object[] stack, + int changedLocalVariableCount, + @MaybeNull Object[] changedLocalVariable, + int fullLocalVariableCount, + @MaybeNull Object[] fullLocalVariable); + + private static Object[] toStackMapFrames(List typeDefinitions) { + Object[] value = typeDefinitions.isEmpty() ? EMPTY : new Object[typeDefinitions.size()]; + for (int index = 0; index < typeDefinitions.size(); index++) { + value[index] = toStackMapFrame(typeDefinitions.get(index)); + } + return value; + } + + private static Object toStackMapFrame(TypeDefinition typeDefinition) { + if (typeDefinition.represents(boolean.class) + || typeDefinition.represents(byte.class) + || typeDefinition.represents(short.class) + || typeDefinition.represents(char.class) + || typeDefinition.represents(int.class)) { + return Opcodes.INTEGER; + } else if (typeDefinition.represents(long.class)) { + return Opcodes.LONG; + } else if (typeDefinition.represents(float.class)) { + return Opcodes.FLOAT; + } else if (typeDefinition.represents(double.class)) { + return Opcodes.DOUBLE; + } else { + return typeDefinition.asErasure().getInternalName(); + } + } } /** diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextFrameGenerationTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextFrameGenerationTest.java new file mode 100644 index 00000000000..67d4cad858d --- /dev/null +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextFrameGenerationTest.java @@ -0,0 +1,124 @@ +package net.bytebuddy.implementation; + +import jdk.internal.org.objectweb.asm.Type; +import net.bytebuddy.description.type.TypeDescription; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.MethodRule; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.Collections; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +public class ImplementationContextFrameGenerationTest { + + @Rule + public MethodRule mockitoRule = MockitoJUnit.rule().silent(); + + @Mock + private MethodVisitor methodVisitor; + + @Test + public void testActive() { + assertThat(Implementation.Context.FrameGeneration.GENERATE.isActive(), is(true)); + assertThat(Implementation.Context.FrameGeneration.EXPAND.isActive(), is(true)); + assertThat(Implementation.Context.FrameGeneration.DISABLED.isActive(), is(false)); + } + + @Test + public void testGenerateSame() { + Implementation.Context.FrameGeneration.GENERATE.same(methodVisitor, Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_SAME, 0, new Object[0], 0, new Object[0]); + } + + @Test + public void testExpandSame() { + Implementation.Context.FrameGeneration.EXPAND.same(methodVisitor, Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_NEW, 1, new Object[]{Type.getInternalName(Object.class)}, 0, new Object[0]); + } + + @Test + public void testIgnoreSame() { + Implementation.Context.FrameGeneration.DISABLED.same(methodVisitor, Collections.singletonList(TypeDescription.OBJECT)); + verifyNoMoreInteractions(methodVisitor); + } + + @Test + public void testGenerateSame1() { + Implementation.Context.FrameGeneration.GENERATE.same1(methodVisitor, TypeDescription.OBJECT, Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_SAME1, 0, new Object[0], 1, new Object[]{Type.getInternalName(Object.class)}); + } + + @Test + public void testExpandSame1() { + Implementation.Context.FrameGeneration.EXPAND.same1(methodVisitor, TypeDescription.OBJECT, Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_NEW, 1, new Object[]{Type.getInternalName(Object.class)}, 1, new Object[]{Type.getInternalName(Object.class)}); + } + + @Test + public void testIgnoreSame1() { + Implementation.Context.FrameGeneration.DISABLED.same1(methodVisitor, TypeDescription.OBJECT, Collections.singletonList(TypeDescription.OBJECT)); + verifyNoMoreInteractions(methodVisitor); + } + + @Test + public void testGenerateAppend() { + Implementation.Context.FrameGeneration.GENERATE.append(methodVisitor, Collections.singletonList(TypeDescription.OBJECT), Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_APPEND, 1, new Object[]{Type.getInternalName(Object.class)}, 0, new Object[0]); + } + + @Test + public void testExpandAppend() { + Implementation.Context.FrameGeneration.EXPAND.append(methodVisitor, Collections.singletonList(TypeDescription.OBJECT), Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_NEW, 2, new Object[]{Type.getInternalName(Object.class), Type.getInternalName(Object.class)}, 0, new Object[0]); + } + + @Test + public void testIgnoreAppend() { + Implementation.Context.FrameGeneration.DISABLED.append(methodVisitor, Collections.singletonList(TypeDescription.OBJECT), Collections.singletonList(TypeDescription.OBJECT)); + verifyNoMoreInteractions(methodVisitor); + } + + @Test + public void testGenerateChop() { + Implementation.Context.FrameGeneration.GENERATE.chop(methodVisitor, 1, Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_CHOP, 1, new Object[0], 0, new Object[0]); + } + + @Test + public void testExpandChop() { + Implementation.Context.FrameGeneration.EXPAND.chop(methodVisitor, 1, Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_NEW, 1, new Object[]{Type.getInternalName(Object.class)}, 0, new Object[0]); + } + + @Test + public void testIgnoreChop() { + Implementation.Context.FrameGeneration.DISABLED.chop(methodVisitor, 1, Collections.singletonList(TypeDescription.OBJECT)); + verifyNoMoreInteractions(methodVisitor); + } + + @Test + public void testGenerateFull() { + Implementation.Context.FrameGeneration.GENERATE.full(methodVisitor, Collections.singletonList(TypeDescription.OBJECT), Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_FULL, 1, new Object[]{Type.getInternalName(Object.class)}, 1, new Object[]{Type.getInternalName(Object.class)}); + } + + @Test + public void testExpandFull() { + Implementation.Context.FrameGeneration.EXPAND.full(methodVisitor, Collections.singletonList(TypeDescription.OBJECT), Collections.singletonList(TypeDescription.OBJECT)); + verify(methodVisitor).visitFrame(Opcodes.F_NEW, 1, new Object[]{Type.getInternalName(Object.class)}, 1, new Object[]{Type.getInternalName(Object.class)}); + } + + @Test + public void testIgnoreFull() { + Implementation.Context.FrameGeneration.DISABLED.full(methodVisitor, Collections.singletonList(TypeDescription.OBJECT), Collections.singletonList(TypeDescription.OBJECT)); + verifyNoMoreInteractions(methodVisitor); + } +}