diff --git a/byte-buddy-agent/pom.xml b/byte-buddy-agent/pom.xml index 3dbfafa2ff8..068c287a26d 100644 --- a/byte-buddy-agent/pom.xml +++ b/byte-buddy-agent/pom.xml @@ -5,7 +5,7 @@ byte-buddy-parent net.bytebuddy - 1.11.20 + 1.11.21 byte-buddy-agent @@ -68,7 +68,7 @@ net.bytebuddy byte-buddy - 1.11.19 + 1.11.20 test diff --git a/byte-buddy-android-test/pom.xml b/byte-buddy-android-test/pom.xml index cf745a79299..4eb0633f4f9 100644 --- a/byte-buddy-android-test/pom.xml +++ b/byte-buddy-android-test/pom.xml @@ -5,7 +5,7 @@ net.bytebuddy byte-buddy-parent - 1.11.20 + 1.11.21 byte-buddy-android-test diff --git a/byte-buddy-android/pom.xml b/byte-buddy-android/pom.xml index 7bbacb4e758..3df8f5a8823 100644 --- a/byte-buddy-android/pom.xml +++ b/byte-buddy-android/pom.xml @@ -5,7 +5,7 @@ byte-buddy-parent net.bytebuddy - 1.11.20 + 1.11.21 byte-buddy-android diff --git a/byte-buddy-benchmark/pom.xml b/byte-buddy-benchmark/pom.xml index c1c8662e2bc..5886cb1976c 100644 --- a/byte-buddy-benchmark/pom.xml +++ b/byte-buddy-benchmark/pom.xml @@ -5,7 +5,7 @@ byte-buddy-parent net.bytebuddy - 1.11.20 + 1.11.21 byte-buddy-benchmark diff --git a/byte-buddy-dep/pom.xml b/byte-buddy-dep/pom.xml index bd55478c582..4bf7935910b 100644 --- a/byte-buddy-dep/pom.xml +++ b/byte-buddy-dep/pom.xml @@ -5,7 +5,7 @@ net.bytebuddy byte-buddy-parent - 1.11.20 + 1.11.21 byte-buddy-dep @@ -113,7 +113,7 @@ net.bytebuddy byte-buddy-maven-plugin - 1.11.19 + 1.11.20 compile @@ -128,19 +128,19 @@ net.bytebuddy byte-buddy - 1.11.19 + 1.11.20 net.bytebuddy.build.HashCodeAndEqualsPlugin$WithNonNullableFields net.bytebuddy byte-buddy - 1.11.19 + 1.11.20 net.bytebuddy.build.CachedReturnPlugin net.bytebuddy byte-buddy - 1.11.19 + 1.11.20 net.bytebuddy.build.AccessControllerPlugin @@ -152,13 +152,13 @@ net.bytebuddy byte-buddy - 1.11.19 + 1.11.20 net.bytebuddy.build.DispatcherAnnotationPlugin net.bytebuddy byte-buddy - 1.11.19 + 1.11.20 net.bytebuddy.build.RepeatedAnnotationPlugin diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java b/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java index 078e7ec016e..2e4d7c0bf98 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java @@ -4887,16 +4887,20 @@ public interface PostProcessor { /** * Resolves this post processor for a given instrumented method. * - * @param instrumentedType The instrumented type. - * @param instrumentedMethod The instrumented method. - * @param assigner The assigner to use. - * @param argumentHandler The argument handler for the instrumented method. + * @param instrumentedType The instrumented type. + * @param instrumentedMethod The instrumented method. + * @param assigner The assigner to use. + * @param argumentHandler The argument handler to use. + * @param stackMapFrameHandler The argument handler for the instrumented method. + * @param exceptionHandler The exception handler that is resolved for the instrumented method. * @return The stack manipulation to apply. */ StackManipulation resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Assigner assigner, - ArgumentHandler argumentHandler); + ArgumentHandler argumentHandler, + StackMapFrameHandler.ForPostProcessor stackMapFrameHandler, + StackManipulation exceptionHandler); /** * A factory for creating a {@link PostProcessor}. @@ -4977,7 +4981,9 @@ enum NoOp implements PostProcessor, Factory { public StackManipulation resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Assigner assigner, - ArgumentHandler argumentHandler) { + ArgumentHandler argumentHandler, + StackMapFrameHandler.ForPostProcessor stackMapFrameHandler, + StackManipulation exceptionHandler) { return StackManipulation.Trivial.INSTANCE; } @@ -5015,10 +5021,17 @@ protected Compound(List postProcessors) { public StackManipulation resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Assigner assigner, - ArgumentHandler argumentHandler) { + ArgumentHandler argumentHandler, + StackMapFrameHandler.ForPostProcessor stackMapFrameHandler, + StackManipulation exceptionHandler) { List stackManipulations = new ArrayList(postProcessors.size()); for (PostProcessor postProcessor : postProcessors) { - stackManipulations.add(postProcessor.resolve(instrumentedType, instrumentedMethod, assigner, argumentHandler)); + stackManipulations.add(postProcessor.resolve(instrumentedType, + instrumentedMethod, + assigner, + argumentHandler, + stackMapFrameHandler, + exceptionHandler)); } return new StackManipulation.Compound(stackManipulations); } @@ -5597,7 +5610,7 @@ public void recordMaxima(int stackSize, int localVariableLength) { /** * A handler for computing and translating stack map frames. */ - protected interface StackMapFrameHandler { + public interface StackMapFrameHandler { /** * Translates a frame. @@ -5632,6 +5645,21 @@ protected interface StackMapFrameHandler { */ void injectCompletionFrame(MethodVisitor methodVisitor); + /** + * A stack map frame handler that can be used within a post processor. Emitting frames via this + * handler is the only legal way for a post processor to produce frames. + */ + interface ForPostProcessor { + + /** + * Injects a frame that represents the current state. + * + * @param methodVisitor The method visitor onto which to apply the stack map frame. + * @param stack A list of types that are currently on the stack. + */ + void injectIntermediateFrame(MethodVisitor methodVisitor, List stack); + } + /** * A stack map frame handler for an instrumented method. */ @@ -5685,7 +5713,7 @@ interface ForInstrumentedMethod extends StackMapFrameHandler { /** * A stack map frame handler for an advice method. */ - interface ForAdvice extends StackMapFrameHandler { + interface ForAdvice extends StackMapFrameHandler, ForPostProcessor { /* marker interface */ } @@ -5773,6 +5801,13 @@ public void injectStartFrame(MethodVisitor methodVisitor) { public void injectPostCompletionFrame(MethodVisitor methodVisitor) { /* do nothing */ } + + /** + * {@inheritDoc} + */ + public void injectIntermediateFrame(MethodVisitor methodVisitor, List stack) { + /* do nothing */ + } } /** @@ -5800,6 +5835,11 @@ abstract class Default implements ForInstrumentedMethod { */ protected final List initialTypes; + /** + * A list of virtual arguments that are available after the enter advice method is executed. + */ + protected final List latentTypes; + /** * A list of virtual method arguments that are available before the instrumented method is executed. */ @@ -5826,6 +5866,7 @@ abstract class Default implements ForInstrumentedMethod { * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. * @param initialTypes A list of virtual method arguments that are explicitly added before any code execution. + * @param latentTypes A list of virtual arguments that are available after the enter advice method is executed. * @param preMethodTypes A list of virtual method arguments that are available before the instrumented method is executed. * @param postMethodTypes A list of virtual method arguments that are available after the instrumented method has completed. * @param expandFrames {@code true} if the meta data handler is expected to expand its frames. @@ -5833,12 +5874,14 @@ abstract class Default implements ForInstrumentedMethod { protected Default(TypeDescription instrumentedType, MethodDescription instrumentedMethod, List initialTypes, + List latentTypes, List preMethodTypes, List postMethodTypes, boolean expandFrames) { this.instrumentedType = instrumentedType; this.instrumentedMethod = instrumentedMethod; this.initialTypes = initialTypes; + this.latentTypes = latentTypes; this.preMethodTypes = preMethodTypes; this.postMethodTypes = postMethodTypes; this.expandFrames = expandFrames; @@ -5850,6 +5893,7 @@ protected Default(TypeDescription instrumentedType, * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. * @param initialTypes A list of virtual method arguments that are explicitly added before any code execution. + * @param latentTypes A list of virtual arguments that are available after the enter advice method is executed. * @param preMethodTypes A list of virtual method arguments that are available before the instrumented method is executed. * @param postMethodTypes A list of virtual method arguments that are available after the instrumented method has completed. * @param exitAdvice {@code true} if the current advice implies exit advice. @@ -5862,6 +5906,7 @@ protected Default(TypeDescription instrumentedType, protected static ForInstrumentedMethod of(TypeDescription instrumentedType, MethodDescription instrumentedMethod, List initialTypes, + List latentTypes, List preMethodTypes, List postMethodTypes, boolean exitAdvice, @@ -5874,11 +5919,13 @@ protected static ForInstrumentedMethod of(TypeDescription instrumentedType, } else if (!exitAdvice && initialTypes.isEmpty()) { return new Trivial(instrumentedType, instrumentedMethod, + latentTypes, (readerFlags & ClassReader.EXPAND_FRAMES) != 0); } else if (copyArguments) { return new WithPreservedArguments.WithArgumentCopy(instrumentedType, instrumentedMethod, initialTypes, + latentTypes, preMethodTypes, postMethodTypes, (readerFlags & ClassReader.EXPAND_FRAMES) != 0); @@ -5886,6 +5933,7 @@ protected static ForInstrumentedMethod of(TypeDescription instrumentedType, return new WithPreservedArguments.WithoutArgumentCopy(instrumentedType, instrumentedMethod, initialTypes, + latentTypes, preMethodTypes, postMethodTypes, (readerFlags & ClassReader.EXPAND_FRAMES) != 0, @@ -5897,7 +5945,7 @@ protected static ForInstrumentedMethod of(TypeDescription instrumentedType, * {@inheritDoc} */ public StackMapFrameHandler.ForAdvice bindEnter(MethodDescription.InDefinedShape adviceMethod) { - return new ForAdvice(adviceMethod, initialTypes, preMethodTypes, TranslationMode.ENTER, instrumentedMethod.isConstructor() + return new ForAdvice(adviceMethod, initialTypes, latentTypes, preMethodTypes, TranslationMode.ENTER, instrumentedMethod.isConstructor() ? Initialization.UNITIALIZED : Initialization.INITIALIZED); } @@ -6146,6 +6194,9 @@ protected enum Initialization { * {@inheritDoc} */ protected Object toFrame(TypeDescription typeDescription) { + if (typeDescription.isPrimitive()) { + throw new IllegalArgumentException("Cannot assume primitive uninitialized value: " + typeDescription); + } return Opcodes.UNINITIALIZED_THIS; } }, @@ -6195,12 +6246,14 @@ protected static class Trivial extends Default { * * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. + * @param latentTypes A list of virtual arguments that are available after the enter advice method is executed. * @param expandFrames {@code true} if the meta data handler is expected to expand its frames. */ - protected Trivial(TypeDescription instrumentedType, MethodDescription instrumentedMethod, boolean expandFrames) { + protected Trivial(TypeDescription instrumentedType, MethodDescription instrumentedMethod, List latentTypes, boolean expandFrames) { super(instrumentedType, instrumentedMethod, Collections.emptyList(), + latentTypes, Collections.emptyList(), Collections.emptyList(), expandFrames); @@ -6284,6 +6337,7 @@ protected abstract static class WithPreservedArguments extends Default { * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. * @param initialTypes A list of virtual method arguments that are explicitly added before any code execution. + * @param latentTypes A list of virtual arguments that are available after the enter advice method is executed. * @param preMethodTypes A list of virtual method arguments that are available before the instrumented method is executed. * @param postMethodTypes A list of virtual method arguments that are available after the instrumented method has completed. * @param expandFrames {@code true} if the meta data handler is expected to expand its frames. @@ -6292,11 +6346,12 @@ protected abstract static class WithPreservedArguments extends Default { protected WithPreservedArguments(TypeDescription instrumentedType, MethodDescription instrumentedMethod, List initialTypes, + List latentTypes, List preMethodTypes, List postMethodTypes, boolean expandFrames, boolean allowCompactCompletionFrame) { - super(instrumentedType, instrumentedMethod, initialTypes, preMethodTypes, postMethodTypes, expandFrames); + super(instrumentedType, instrumentedMethod, initialTypes, latentTypes, preMethodTypes, postMethodTypes, expandFrames); this.allowCompactCompletionFrame = allowCompactCompletionFrame; } @@ -6324,6 +6379,7 @@ public StackMapFrameHandler.ForAdvice bindExit(MethodDescription.InDefinedShape return new ForAdvice(adviceMethod, CompoundList.of(initialTypes, preMethodTypes, postMethodTypes), Collections.emptyList(), + Collections.emptyList(), TranslationMode.EXIT, Initialization.INITIALIZED); } @@ -6435,6 +6491,7 @@ protected static class WithoutArgumentCopy extends WithPreservedArguments { * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. * @param initialTypes A list of virtual method arguments that are explicitly added before any code execution. + * @param latentTypes A list of virtual arguments that are available after the enter advice method is executed. * @param preMethodTypes A list of virtual method arguments that are available before the instrumented method is executed. * @param postMethodTypes A list of virtual method arguments that are available after the instrumented method has completed. * @param expandFrames {@code true} if the meta data handler is expected to expand its frames. @@ -6443,11 +6500,12 @@ protected static class WithoutArgumentCopy extends WithPreservedArguments { protected WithoutArgumentCopy(TypeDescription instrumentedType, MethodDescription instrumentedMethod, List initialTypes, + List latentTypes, List preMethodTypes, List postMethodTypes, boolean expandFrames, boolean allowCompactCompletionFrame) { - super(instrumentedType, instrumentedMethod, initialTypes, preMethodTypes, postMethodTypes, expandFrames, allowCompactCompletionFrame); + super(instrumentedType, instrumentedMethod, initialTypes, latentTypes, preMethodTypes, postMethodTypes, expandFrames, allowCompactCompletionFrame); } /** @@ -6489,6 +6547,7 @@ protected static class WithArgumentCopy extends WithPreservedArguments { * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. * @param initialTypes A list of virtual method arguments that are explicitly added before any code execution. + * @param latentTypes The types that are given post execution of a possible enter advice. * @param preMethodTypes A list of virtual method arguments that are available before the instrumented method is executed. * @param postMethodTypes A list of virtual method arguments that are available after the instrumented method has completed. * @param expandFrames {@code true} if the meta data handler is expected to expand its frames. @@ -6496,10 +6555,11 @@ protected static class WithArgumentCopy extends WithPreservedArguments { protected WithArgumentCopy(TypeDescription instrumentedType, MethodDescription instrumentedMethod, List initialTypes, + List latentTypes, List preMethodTypes, List postMethodTypes, boolean expandFrames) { - super(instrumentedType, instrumentedMethod, initialTypes, preMethodTypes, postMethodTypes, expandFrames, true); + super(instrumentedType, instrumentedMethod, initialTypes, latentTypes, preMethodTypes, postMethodTypes, expandFrames, true); } /** @@ -6632,6 +6692,11 @@ protected class ForAdvice implements StackMapFrameHandler.ForAdvice { */ protected final List startTypes; + /** + * The types that are given post execution of the advice. + */ + private final List intermediateTypes; + /** * The types provided after execution of the advice code. */ @@ -6647,26 +6712,35 @@ protected class ForAdvice implements StackMapFrameHandler.ForAdvice { */ private final Initialization initialization; + /** + * {@code true} if an intermediate frame was yielded. + */ + private boolean intermedate; + /** * Creates a new meta data handler for an advice method. * - * @param adviceMethod The method description for which frames are translated. - * @param startTypes The types provided before execution of the advice code. - * @param endTypes The types provided after execution of the advice code. - * @param translationMode The translation mode to apply for this advice method. Should be - * either {@link TranslationMode#ENTER} or {@link TranslationMode#EXIT}. - * @param initialization The initialization to apply when resolving a reference to the instance on which a non-static method is invoked. + * @param adviceMethod The method description for which frames are translated. + * @param startTypes The types provided before execution of the advice code. + * @param intermediateTypes The types that are given post execution of the advice. + * @param endTypes The types provided after execution of the advice code. + * @param translationMode The translation mode to apply for this advice method. Should be + * either {@link TranslationMode#ENTER} or {@link TranslationMode#EXIT}. + * @param initialization The initialization to apply when resolving a reference to the instance on which a non-static method is invoked. */ protected ForAdvice(MethodDescription.InDefinedShape adviceMethod, List startTypes, + List intermediateTypes, List endTypes, TranslationMode translationMode, Initialization initialization) { this.adviceMethod = adviceMethod; this.startTypes = startTypes; + this.intermediateTypes = intermediateTypes; this.endTypes = endTypes; this.translationMode = translationMode; this.initialization = initialization; + intermedate = false; } /** @@ -6727,8 +6801,8 @@ public void injectExceptionFrame(MethodVisitor methodVisitor) { public void injectCompletionFrame(MethodVisitor methodVisitor) { if (expandFrames) { injectFullFrame(methodVisitor, initialization, CompoundList.of(startTypes, endTypes), Collections.emptyList()); - } else if (currentFrameDivergence == 0 && endTypes.size() < 4) { - if (endTypes.isEmpty()) { + } else if (currentFrameDivergence == 0 && (intermedate || endTypes.size() < 4)) { + if (intermedate || endTypes.isEmpty()) { methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); } else { Object[] local = new Object[endTypes.size()]; @@ -6740,10 +6814,49 @@ public void injectCompletionFrame(MethodVisitor methodVisitor) { } } else if (currentFrameDivergence < 3 && endTypes.isEmpty()) { methodVisitor.visitFrame(Opcodes.F_CHOP, currentFrameDivergence, EMPTY, EMPTY.length, EMPTY); + currentFrameDivergence = 0; } else { injectFullFrame(methodVisitor, initialization, CompoundList.of(startTypes, endTypes), Collections.emptyList()); } } + + /** + * {@inheritDoc} + */ + public void injectIntermediateFrame(MethodVisitor methodVisitor, List stack) { + if (expandFrames) { + injectFullFrame(methodVisitor, initialization, CompoundList.of(startTypes, intermediateTypes), stack); + } else if (intermedate && stack.size() < 2) { + if (stack.isEmpty()) { + methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); + } else { + methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, 1, new Object[]{Initialization.INITIALIZED.toFrame(stack.get(0))}); + } + } else if (currentFrameDivergence == 0 + && intermediateTypes.size() < 4 + && (stack.isEmpty() || stack.size() < 2 && intermediateTypes.isEmpty())) { + if (intermediateTypes.isEmpty()) { + if (stack.isEmpty()) { + methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY); + } else { + methodVisitor.visitFrame(Opcodes.F_SAME1, EMPTY.length, EMPTY, 1, new Object[]{Initialization.INITIALIZED.toFrame(stack.get(0))}); + } + } else { + Object[] local = new Object[intermediateTypes.size()]; + int index = 0; + for (TypeDescription typeDescription : intermediateTypes) { + local[index++] = Initialization.INITIALIZED.toFrame(typeDescription); + } + methodVisitor.visitFrame(Opcodes.F_APPEND, local.length, local, EMPTY.length, EMPTY); + } + } else if (currentFrameDivergence < 3 && intermediateTypes.isEmpty() && stack.isEmpty()) { + methodVisitor.visitFrame(Opcodes.F_CHOP, currentFrameDivergence, EMPTY, EMPTY.length, EMPTY); + } else { + injectFullFrame(methodVisitor, initialization, CompoundList.of(startTypes, intermediateTypes), stack); + } + currentFrameDivergence = intermediateTypes.size() - endTypes.size(); + intermedate = true; + } } } } @@ -7608,6 +7721,13 @@ interface ForMethodEnter extends Resolved { * @return {@code true} if the first discovered line number information should be prepended to the advice code. */ boolean isPrependLineNumber(); + + /** + * Returns the actual advice type, even if it is not required post advice processing. + * + * @return The actual advice type, even if it is not required post advice processing. + */ + TypeDefinition getActualAdviceType(); } /** @@ -7777,6 +7897,13 @@ public boolean isPrependLineNumber() { return false; } + /** + * {@inheritDoc} + */ + public TypeDefinition getActualAdviceType() { + return TypeDescription.VOID; + } + /** * {@inheritDoc} */ @@ -8004,6 +8131,7 @@ protected Resolved(MethodDescription.InDefinedShape adviceMethod, * @param instrumentedMethod A description of the instrumented method. * @param suppressionHandler A bound suppression handler that is used for suppressing exceptions of this advice method. * @param relocationHandler A bound relocation handler that is responsible for considering a non-standard control flow. + * @param exceptionHandler The exception handler that is resolved for the instrumented method. * @return A method visitor for visiting the advice method's byte code. */ protected abstract MethodVisitor apply(MethodVisitor methodVisitor, @@ -8015,7 +8143,8 @@ protected abstract MethodVisitor apply(MethodVisitor methodVisitor, TypeDescription instrumentedType, MethodDescription instrumentedMethod, SuppressionHandler.Bound suppressionHandler, - RelocationHandler.Bound relocationHandler); + RelocationHandler.Bound relocationHandler, + StackManipulation exceptionHandler); /** * A bound advice method that copies the code by first extracting the exception table and later appending the @@ -8073,6 +8202,11 @@ protected class AdviceMethodInliner extends ClassVisitor implements Bound { */ protected final RelocationHandler.Bound relocationHandler; + /** + * The exception handler that is resolved for the instrumented method. + */ + protected final StackManipulation exceptionHandler; + /** * A class reader for parsing the class file containing the represented advice method. */ @@ -8096,6 +8230,7 @@ protected class AdviceMethodInliner extends ClassVisitor implements Bound { * @param stackMapFrameHandler A handler for translating and injecting stack map frames. * @param suppressionHandler A bound suppression handler that is used for suppressing exceptions of this advice method. * @param relocationHandler A bound relocation handler that is responsible for considering a non-standard control flow. + * @param exceptionHandler The exception handler that is resolved for the instrumented method. * @param classReader A class reader for parsing the class file containing the represented advice method. */ protected AdviceMethodInliner(TypeDescription instrumentedType, @@ -8108,6 +8243,7 @@ protected AdviceMethodInliner(TypeDescription instrumentedType, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, SuppressionHandler.Bound suppressionHandler, RelocationHandler.Bound relocationHandler, + StackManipulation exceptionHandler, ClassReader classReader) { super(OpenedClassReader.ASM_API); this.instrumentedType = instrumentedType; @@ -8119,8 +8255,9 @@ protected AdviceMethodInliner(TypeDescription instrumentedType, this.methodSizeHandler = methodSizeHandler; this.stackMapFrameHandler = stackMapFrameHandler; this.suppressionHandler = suppressionHandler; - this.classReader = classReader; this.relocationHandler = relocationHandler; + this.exceptionHandler = exceptionHandler; + this.classReader = classReader; labels = new ArrayList