diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java b/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java index bb519e1cc22..84b406c155d 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java @@ -4798,12 +4798,12 @@ protected Appender(List declaredFields) { public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { List fieldAssignments = new ArrayList(declaredFields.size() * 3); for (ParameterDescription parameterDescription : instrumentedMethod.getParameters()) { - fieldAssignments.add(MethodVariableAccess.REFERENCE.loadOffset(0)); - fieldAssignments.add(MethodVariableAccess.of(parameterDescription.getType()).loadOffset(parameterDescription.getOffset())); + fieldAssignments.add(MethodVariableAccess.REFERENCE.loadFrom(0)); + fieldAssignments.add(MethodVariableAccess.of(parameterDescription.getType()).loadFrom(parameterDescription.getOffset())); fieldAssignments.add(FieldAccess.forField(declaredFields.get(parameterDescription.getIndex())).putter()); } return new Size(new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(INSTANCE.objectConstructor), new StackManipulation.Compound(fieldAssignments), MethodReturn.VOID @@ -5011,12 +5011,12 @@ protected Appender(MethodDescription targetMethod, public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { List fieldAccess = new ArrayList(declaredFields.size() * 2); for (FieldDescription.InDefinedShape fieldDescription : declaredFields) { - fieldAccess.add(MethodVariableAccess.REFERENCE.loadOffset(0)); + fieldAccess.add(MethodVariableAccess.REFERENCE.loadFrom(0)); fieldAccess.add(FieldAccess.forField(fieldDescription).getter()); } List parameterAccess = new ArrayList(instrumentedMethod.getParameters().size() * 2); for (ParameterDescription parameterDescription : instrumentedMethod.getParameters()) { - parameterAccess.add(MethodVariableAccess.of(parameterDescription.getType()).loadOffset(parameterDescription.getOffset())); + parameterAccess.add(MethodVariableAccess.of(parameterDescription.getType()).loadFrom(parameterDescription.getOffset())); parameterAccess.add(Assigner.DEFAULT.assign(parameterDescription.getType(), specializedLambdaMethod.getParameterTypes().get(parameterDescription.getIndex()).asGenericType(), Assigner.Typing.DYNAMIC)); @@ -5127,7 +5127,7 @@ public ByteCodeAppender appender(Target implementationTarget) { } List lambdaArguments = new ArrayList(implementationTarget.getInstrumentedType().getDeclaredFields().size()); for (FieldDescription.InDefinedShape fieldDescription : implementationTarget.getInstrumentedType().getDeclaredFields()) { - lambdaArguments.add(new StackManipulation.Compound(MethodVariableAccess.REFERENCE.loadOffset(0), + lambdaArguments.add(new StackManipulation.Compound(MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(fieldDescription).getter(), Assigner.DEFAULT.assign(fieldDescription.getType(), TypeDescription.Generic.OBJECT, Assigner.Typing.STATIC))); } 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 e900c18f10b..ca1fdd9615b 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 @@ -15,8 +15,10 @@ import net.bytebuddy.dynamic.scaffold.InstrumentedType; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.SuperMethodCall; -import net.bytebuddy.implementation.bytecode.ByteCodeAppender; -import net.bytebuddy.implementation.bytecode.StackSize; +import net.bytebuddy.implementation.bytecode.*; +import net.bytebuddy.implementation.bytecode.constant.*; +import net.bytebuddy.implementation.bytecode.member.FieldAccess; +import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.pool.TypePool; import net.bytebuddy.utility.CompoundList; @@ -26,7 +28,8 @@ import net.bytebuddy.utility.visitor.StackAwareMethodVisitor; import org.objectweb.asm.*; -import java.io.*; +import java.io.IOException; +import java.io.Serializable; import java.lang.annotation.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -433,7 +436,7 @@ public MethodVisitor wrap(TypeDescription instrumentedType, int readerFlags) { return instrumentedMethod.isAbstract() || instrumentedMethod.isNative() ? methodVisitor - : doWrap(instrumentedType, instrumentedMethod, methodVisitor, implementationContext.getClassFileVersion(), writerFlags, readerFlags); + : doWrap(instrumentedType, instrumentedMethod, methodVisitor, implementationContext, writerFlags, readerFlags); } /** @@ -442,7 +445,6 @@ public MethodVisitor wrap(TypeDescription instrumentedType, * @param instrumentedType The instrumented type. * @param instrumentedMethod The instrumented method. * @param methodVisitor The method visitor to write to. - * @param classFileVersion The current class file version. * @param writerFlags The ASM writer flags to use. * @param readerFlags The ASM reader flags to use. * @return A method visitor that applies this advice. @@ -450,7 +452,7 @@ public MethodVisitor wrap(TypeDescription instrumentedType, protected MethodVisitor doWrap(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, - ClassFileVersion classFileVersion, + Implementation.Context implementationContext, int writerFlags, int readerFlags) { methodVisitor = methodEnter.isPrependLineNumber() @@ -458,30 +460,30 @@ protected MethodVisitor doWrap(TypeDescription instrumentedType, : methodVisitor; if (!methodExit.isAlive()) { return new AdviceVisitor.WithoutExitAdvice(methodVisitor, + implementationContext, instrumentedType, instrumentedMethod, methodEnter, - classFileVersion, writerFlags, readerFlags); } else if (methodExit.getTriggeringThrowable().represents(NoExceptionHandler.class)) { return new AdviceVisitor.WithExitAdvice.WithoutExceptionHandling(methodVisitor, + implementationContext, instrumentedType, instrumentedMethod, methodEnter, methodExit, - classFileVersion, writerFlags, readerFlags); } else if (instrumentedMethod.isConstructor()) { throw new IllegalStateException("Cannot catch exception during constructor call for " + instrumentedMethod); } else { return new AdviceVisitor.WithExitAdvice.WithExceptionHandling(methodVisitor, + implementationContext, instrumentedType, instrumentedMethod, methodEnter, methodExit, - classFileVersion, writerFlags, readerFlags, methodExit.getTriggeringThrowable()); @@ -1706,1695 +1708,267 @@ public String toString() { */ interface Target { - /** - * Indicates that applying this target does not require any additional padding. - */ - int NO_PADDING = 0; - - /** - * Applies this offset mapping for a {@link MethodVisitor#visitVarInsn(int, int)} instruction. - * - * @param methodVisitor The method visitor onto which this offset mapping is to be applied. - * @param opcode The opcode of the original instruction. - * @return The required padding to the advice's total stack size. - */ - int resolveAccess(MethodVisitor methodVisitor, int opcode); - - /** - * Applies this offset mapping for a {@link MethodVisitor#visitIincInsn(int, int)} instruction. - * - * @param methodVisitor The method visitor onto which this offset mapping is to be applied. - * @param increment The value with which to increment the targeted value. - * @return The required padding to the advice's total stack size. - */ - int resolveIncrement(MethodVisitor methodVisitor, int increment); - - /** - * A dispatcher for boxing a primitive value. - */ - enum PrimitiveDispatcher { - - /** - * A boxing dispatcher for the {@code boolean} type. - */ - BOOLEAN(Opcodes.ICONST_0, Opcodes.ILOAD, Opcodes.ISTORE, Boolean.class, boolean.class, "booleanValue"), - - /** - * A boxing dispatcher for the {@code byte} type. - */ - BYTE(Opcodes.ICONST_0, Opcodes.ILOAD, Opcodes.ISTORE, Byte.class, byte.class, "byteValue"), - - /** - * A boxing dispatcher for the {@code short} type. - */ - SHORT(Opcodes.ICONST_0, Opcodes.ILOAD, Opcodes.ISTORE, Short.class, short.class, "shortValue"), - - /** - * A boxing dispatcher for the {@code char} type. - */ - CHARACTER(Opcodes.ICONST_0, Opcodes.ILOAD, Opcodes.ISTORE, Character.class, char.class, "charValue"), - - /** - * A boxing dispatcher for the {@code int} type. - */ - INTEGER(Opcodes.ICONST_0, Opcodes.ILOAD, Opcodes.ISTORE, Integer.class, int.class, "intValue"), - - /** - * A boxing dispatcher for the {@code long} type. - */ - LONG(Opcodes.LCONST_0, Opcodes.LLOAD, Opcodes.LSTORE, Long.class, long.class, "longValue"), - - /** - * A boxing dispatcher for the {@code float} type. - */ - FLOAT(Opcodes.FCONST_0, Opcodes.FLOAD, Opcodes.FSTORE, Float.class, float.class, "floatValue"), - - /** - * A boxing dispatcher for the {@code double} type. - */ - DOUBLE(Opcodes.DCONST_0, Opcodes.DLOAD, Opcodes.DSTORE, Double.class, double.class, "doubleValue"); - - /** - * The name of the boxing method of a wrapper type. - */ - private static final String VALUE_OF = "valueOf"; - - /** - * The opcode for loading the default value for this type onto the operand stack. - */ - private final int defaultValue; - - /** - * The opcode to use for loading a value of this type. - */ - private final int load; - - /** - * The opcode to use for loading a value of this type. - */ - private final int store; - - /** - * The name of the method used for unboxing a primitive type. - */ - private final String unboxingMethod; - - /** - * The name of the wrapper type. - */ - private final String owner; - - /** - * The descriptor of the boxing method. - */ - private final String boxingDescriptor; - - /** - * The descriptor of the unboxing method. - */ - private final String unboxingDescriptor; - - /** - * The required stack size of the unboxed value. - */ - private final StackSize stackSize; - - /** - * Creates a new boxing dispatcher. - * - * @param defaultValue The opcode for loading the default value for this type onto the operand stack. - * @param load The opcode to use for loading a value of this type. - * @param store The opcode to use for storing a value of this type. - * @param wrapperType The represented wrapper type. - * @param primitiveType The represented primitive type. - * @param unboxingMethod The name of the method used for unboxing a primitive type. - */ - PrimitiveDispatcher(int defaultValue, int load, int store, Class wrapperType, Class primitiveType, String unboxingMethod) { - this.defaultValue = defaultValue; - this.load = load; - this.store = store; - this.unboxingMethod = unboxingMethod; - owner = Type.getInternalName(wrapperType); - boxingDescriptor = Type.getMethodDescriptor(Type.getType(wrapperType), Type.getType(primitiveType)); - unboxingDescriptor = Type.getMethodDescriptor(Type.getType(primitiveType)); - stackSize = StackSize.of(primitiveType); - } - - /** - * Resolves a boxing dispatcher for the supplied primitive type. - * - * @param typeDefinition A description of a primitive type. - * @return An appropriate boxing dispatcher. - */ - protected static PrimitiveDispatcher of(TypeDefinition typeDefinition) { - if (typeDefinition.represents(boolean.class)) { - return BOOLEAN; - } else if (typeDefinition.represents(byte.class)) { - return BYTE; - } else if (typeDefinition.represents(short.class)) { - return SHORT; - } else if (typeDefinition.represents(char.class)) { - return CHARACTER; - } else if (typeDefinition.represents(int.class)) { - return INTEGER; - } else if (typeDefinition.represents(long.class)) { - return LONG; - } else if (typeDefinition.represents(float.class)) { - return FLOAT; - } else if (typeDefinition.represents(double.class)) { - return DOUBLE; - } else { - throw new IllegalArgumentException("Cannot box: " + typeDefinition); - } - } - - /** - * Loads a primitive integer value onto the operand stack. - * - * @param methodVisitor The method visitor to use. - * @param value The value to load onto the operand stack. - */ - protected static void loadInteger(MethodVisitor methodVisitor, int value) { - switch (value) { - case 0: - methodVisitor.visitInsn(Opcodes.ICONST_0); - break; - case 1: - methodVisitor.visitInsn(Opcodes.ICONST_1); - break; - case 2: - methodVisitor.visitInsn(Opcodes.ICONST_2); - break; - case 3: - methodVisitor.visitInsn(Opcodes.ICONST_3); - break; - case 4: - methodVisitor.visitInsn(Opcodes.ICONST_4); - break; - case 5: - methodVisitor.visitInsn(Opcodes.ICONST_5); - break; - default: - if (value < Byte.MAX_VALUE) { - methodVisitor.visitIntInsn(Opcodes.BIPUSH, value); - } else if (value < Short.MAX_VALUE) { - methodVisitor.visitIntInsn(Opcodes.SIPUSH, value); - } else { - methodVisitor.visitLdcInsn(value); - } - } - } - - /** - * Loads the value as a boxed version onto the stack. - * - * @param methodVisitor the method visitor for which to load the value. - * @param offset The offset of the primitive value. - * @return The additional padding required on the operand stack. - */ - protected int loadBoxed(MethodVisitor methodVisitor, int offset) { - methodVisitor.visitVarInsn(load, offset); - return box(methodVisitor); - } - - /** - * Boxes the current value on top of the operand stack. - * - * @param methodVisitor The method visitor to apply the boxing to. - * @return The additional padding required on the operand stack. - */ - protected int box(MethodVisitor methodVisitor) { - methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, VALUE_OF, boxingDescriptor, false); - return stackSize.getSize() - 1; - } - - /** - * Stores the value as a unboxed version onto the stack. - * - * @param methodVisitor the method visitor for which to store the value. - * @param offset The offset of the primitive value. - * @return The additional padding required on the operand stack. - */ - protected int storeUnboxed(MethodVisitor methodVisitor, int offset) { - methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, owner); - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, unboxingMethod, unboxingDescriptor, false); - methodVisitor.visitVarInsn(store, offset); - return stackSize.getSize() - 1; - } - - /** - * Pushes the represented default value as a boxed value onto the operand stack. - * - * @param methodVisitor The method visitor to apply the changes to. - * @return The additional padding required on the operand stack. - */ - protected int pushBoxedDefault(MethodVisitor methodVisitor) { - methodVisitor.visitInsn(defaultValue); - methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, VALUE_OF, boxingDescriptor, false); - return stackSize.getSize() - 1; - } - - /** - * Loads this instance's type constant onto the operand stack. - * - * @param methodVisitor The method visitor to use. - */ - protected void loadType(MethodVisitor methodVisitor) { - methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, owner, "TYPE", Type.getDescriptor(Class.class)); - } - - /** - * Returns the stack size of the primitive value. - * - * @return The stack size of the primitive value. - */ - protected StackSize getStackSize() { - return stackSize; - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.PrimitiveDispatcher." + name(); - } - } - - /** - * Loads a default value onto the stack or pops the accessed value off it. - */ - enum ForDefaultValue implements Target { - - /** - * The singleton instance. - */ - INSTANCE; - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - methodVisitor.visitInsn(Opcodes.ACONST_NULL); - break; - case Opcodes.ILOAD: - methodVisitor.visitInsn(Opcodes.ICONST_0); - break; - case Opcodes.LLOAD: - methodVisitor.visitInsn(Opcodes.LCONST_0); - break; - case Opcodes.FLOAD: - methodVisitor.visitInsn(Opcodes.FCONST_0); - break; - case Opcodes.DLOAD: - methodVisitor.visitInsn(Opcodes.DCONST_0); - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - methodVisitor.visitInsn(Opcodes.POP); - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - methodVisitor.visitInsn(Opcodes.POP2); - break; - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); - } - return NO_PADDING; - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - return NO_PADDING; - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForDefaultValue." + name(); - } - } - - /** - * Loads a boxed default value onto the operand stack. - */ - class ForBoxedDefaultValue implements Target { - - /** - * The boxing dispatcher to use. - */ - private final PrimitiveDispatcher primitiveDispatcher; - - /** - * Creates a new target for a boxing dispatcher. - * - * @param primitiveDispatcher The boxing dispatcher to use. - */ - protected ForBoxedDefaultValue(PrimitiveDispatcher primitiveDispatcher) { - this.primitiveDispatcher = primitiveDispatcher; - } - - /** - * Creates a new target for loading a value of the given primitve type onto the operand stack. - * - * @param typeDefinition The primitive type to push boxed onto the operand stack. - * @return An appropriate target. - */ - protected static Target of(TypeDefinition typeDefinition) { - return new Target.ForBoxedDefaultValue(PrimitiveDispatcher.of(typeDefinition)); - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - return primitiveDispatcher.pushBoxedDefault(methodVisitor); - case Opcodes.ASTORE: - methodVisitor.visitInsn(Opcodes.POP); - return NO_PADDING; - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); - } - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Unexpected incrementation for boxed default value"); - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForBoxedDefaultValue that = (ForBoxedDefaultValue) other; - return primitiveDispatcher == that.primitiveDispatcher; - } - - @Override - public int hashCode() { - return primitiveDispatcher.hashCode(); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForBoxedDefaultValue{" + - "primitiveDispatcher=" + primitiveDispatcher + - '}'; - } - } - - /** - * A read-only target mapping. - */ - abstract class ForParameter implements Target { - - /** - * The mapped offset. - */ - protected final int offset; - - /** - * Creates a new read-only target mapping. - * - * @param offset The mapped offset. - */ - protected ForParameter(int offset) { - this.offset = offset; - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ISTORE: - case Opcodes.LSTORE: - case Opcodes.FSTORE: - case Opcodes.DSTORE: - case Opcodes.ASTORE: - onWrite(methodVisitor, opcode); - break; - case Opcodes.ILOAD: - case Opcodes.LLOAD: - case Opcodes.FLOAD: - case Opcodes.DLOAD: - case Opcodes.ALOAD: - methodVisitor.visitVarInsn(opcode, offset); - break; - default: - throw new IllegalArgumentException("Did not expect opcode: " + opcode); - } - return NO_PADDING; - } - - /** - * Invoked upon attempting to write to a parameter. - * - * @param methodVisitor The method visitor onto which this offset mapping is to be applied. - * @param opcode The applied opcode. - */ - protected abstract void onWrite(MethodVisitor methodVisitor, int opcode); - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForParameter forParameter = (ForParameter) other; - return offset == forParameter.offset; - } - - @Override - public int hashCode() { - return offset; - } - - /** - * A read-only parameter mapping. - */ - protected static class ReadOnly extends ForParameter { - - /** - * Creates a new parameter mapping that is only readable. - * - * @param offset The mapped offset. - */ - protected ReadOnly(int offset) { - super(offset); - } - - @Override - protected void onWrite(MethodVisitor methodVisitor, int opcode) { - throw new IllegalStateException("Cannot write to read-only value"); - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot write to read-only parameter at offset " + offset); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForParameter.ReadOnly{" + - "offset=" + offset + - "}"; - } - } - - /** - * A parameter mapping that is both readable and writable. - */ - protected static class ReadWrite extends ForParameter { - - /** - * Creates a new parameter mapping that is both readable and writable. - * - * @param offset The mapped offset. - */ - protected ReadWrite(int offset) { - super(offset); - } - - @Override - protected void onWrite(MethodVisitor methodVisitor, int opcode) { - methodVisitor.visitVarInsn(opcode, offset); - } - - /** - * Resolves a parameter mapping where the value is casted to the given type prior to assignment. - * - * @param targetType The type to which the target value is cased. - * @return An appropriate target mapping. - */ - protected Target casted(TypeDescription targetType) { - return targetType.represents(Object.class) - ? this - : new WithCasting(offset, targetType); - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - methodVisitor.visitIincInsn(offset, increment); - return NO_PADDING; - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForParameter.ReadWrite{" + - "offset=" + offset + - "}"; - } - - /** - * A readable and writable parameter mapping where the assigned value is casted to another type prior to assignment. - */ - protected static class WithCasting extends ReadWrite { - - /** - * The type to which the written value is casted prior to assignment. - */ - private final TypeDescription targetType; - - /** - * Creates a new parameter mapping with casting prior to assignment. - * - * @param offset The mapped offset. - * @param targetType The type to which the written value is casted prior to assignment. - */ - protected WithCasting(int offset, TypeDescription targetType) { - super(offset); - this.targetType = targetType; - } - - @Override - protected void onWrite(MethodVisitor methodVisitor, int opcode) { - methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, targetType.getInternalName()); - super.onWrite(methodVisitor, opcode); - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - if (!super.equals(other)) return false; - WithCasting that = (WithCasting) other; - return targetType.equals(that.targetType); - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + targetType.hashCode(); - return result; - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForParameter.ReadWrite.WithCasting{" + - "offset=" + offset + - ", targetType=" + targetType + - "}"; - } - } - } - } - - /** - * An offset mapping for a field. - */ - abstract class ForField implements Target { - - /** - * The field being read. - */ - protected final FieldDescription.InDefinedShape fieldDescription; - - /** - * Creates a new offset mapping for a field. - * - * @param fieldDescription The field being read. - */ - protected ForField(FieldDescription.InDefinedShape fieldDescription) { - this.fieldDescription = fieldDescription; - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ISTORE: - case Opcodes.ASTORE: - case Opcodes.FSTORE: - return onWriteSingle(methodVisitor); - case Opcodes.LSTORE: - case Opcodes.DSTORE: - return onWriteDouble(methodVisitor); - case Opcodes.ILOAD: - case Opcodes.FLOAD: - case Opcodes.ALOAD: - case Opcodes.LLOAD: - case Opcodes.DLOAD: - if (fieldDescription.isStatic()) { - accessField(methodVisitor, Opcodes.GETSTATIC); - } else { - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - accessField(methodVisitor, Opcodes.GETFIELD); - } - return NO_PADDING; - default: - throw new IllegalArgumentException("Did not expect opcode: " + opcode); - } - } - - /** - * Writes a value to a field which type occupies a single slot on the operand stack. - * - * @param methodVisitor The method visitor onto which this offset mapping is to be applied. - * @return The required padding to the advice's total stack size. - */ - protected abstract int onWriteSingle(MethodVisitor methodVisitor); - - /** - * Writes a value to a field which type occupies two slots on the operand stack. - * - * @param methodVisitor The method visitor onto which this offset mapping is to be applied. - * @return The required padding to the advice's total stack size. - */ - protected abstract int onWriteDouble(MethodVisitor methodVisitor); - - /** - * Accesses a field. - * - * @param methodVisitor The method visitor for which to access the field. - * @param opcode The opcode for accessing the field. - */ - protected void accessField(MethodVisitor methodVisitor, int opcode) { - methodVisitor.visitFieldInsn(opcode, - fieldDescription.getDeclaringType().asErasure().getInternalName(), - fieldDescription.getInternalName(), - fieldDescription.getDescriptor()); - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForField forField = (ForField) other; - return fieldDescription.equals(forField.fieldDescription); - } - - @Override - public int hashCode() { - return fieldDescription.hashCode(); - } - - /** - * A target mapping for a field that is only readable. - */ - protected static class ReadOnly extends ForField { - - /** - * Creates a new field mapping for a field that is only readable. - * - * @param fieldDescription The field which is mapped by this target mapping. - */ - protected ReadOnly(FieldDescription.InDefinedShape fieldDescription) { - super(fieldDescription); - } - - @Override - protected int onWriteSingle(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only field " + fieldDescription); - } - - @Override - protected int onWriteDouble(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only field " + fieldDescription); - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot write to read-only field " + fieldDescription); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForField.ReadOnly{" + - "fieldDescription=" + fieldDescription + - "}"; - } - } - - /** - * A target mapping for a field that is both readable and writable. - */ - protected static class ReadWrite extends ForField { - - /** - * Creates a new field mapping for a field that is readable and writable. - * - * @param fieldDescription The field which is mapped by this target mapping. - */ - protected ReadWrite(FieldDescription.InDefinedShape fieldDescription) { - super(fieldDescription); - } - - @Override - protected int onWriteSingle(MethodVisitor methodVisitor) { - if (!fieldDescription.isStatic()) { - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitInsn(Opcodes.DUP_X1); - methodVisitor.visitInsn(Opcodes.POP); - accessField(methodVisitor, Opcodes.PUTFIELD); - return 2; - } else { - accessField(methodVisitor, Opcodes.PUTSTATIC); - return NO_PADDING; - } - } - - @Override - protected int onWriteDouble(MethodVisitor methodVisitor) { - if (!fieldDescription.isStatic()) { - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitInsn(Opcodes.DUP_X2); - methodVisitor.visitInsn(Opcodes.POP); - accessField(methodVisitor, Opcodes.PUTFIELD); - return 2; - } else { - accessField(methodVisitor, Opcodes.PUTSTATIC); - return NO_PADDING; - } - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - if (fieldDescription.isStatic()) { - accessField(methodVisitor, Opcodes.GETSTATIC); - methodVisitor.visitInsn(Opcodes.ICONST_1); - methodVisitor.visitInsn(Opcodes.IADD); - accessField(methodVisitor, Opcodes.PUTSTATIC); - return NO_PADDING; - } else { - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitInsn(Opcodes.DUP); - accessField(methodVisitor, Opcodes.GETFIELD); - methodVisitor.visitInsn(Opcodes.ICONST_1); - methodVisitor.visitInsn(Opcodes.IADD); - accessField(methodVisitor, Opcodes.PUTFIELD); - return 2; - } - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForField.ReadWrite{" + - "fieldDescription=" + fieldDescription + - "}"; - } - } - - /** - * A target for reading a field where the final value is boxed after reading. - */ - protected static class ReadBoxed extends ForField { - - /** - * Creates a new field mapping for a field that is readable and gets boxed. - * - * @param fieldDescription The field which is mapped by this target mapping. - */ - protected ReadBoxed(FieldDescription.InDefinedShape fieldDescription) { - super(fieldDescription); - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - return super.resolveAccess(methodVisitor, opcode) + PrimitiveDispatcher.of(fieldDescription.getType()).box(methodVisitor); - } - - @Override - protected int onWriteSingle(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only field " + fieldDescription); - } - - @Override - protected int onWriteDouble(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only field " + fieldDescription); - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot write to read-only field " + fieldDescription); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForField.ReadBoxed{" + - "fieldDescription=" + fieldDescription + - "}"; - } - } - } - - /** - * An offset mapping for a constant pool value. - */ - class ForConstantPoolValue implements Target { - - /** - * The constant pool value. - */ - private final Object value; - - /** - * Creates a mapping for a constant pool value. - * - * @param value The constant pool value. - */ - protected ForConstantPoolValue(Object value) { - this.value = value; - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ISTORE: - case Opcodes.ASTORE: - case Opcodes.FSTORE: - case Opcodes.LSTORE: - case Opcodes.DSTORE: - throw new IllegalStateException("Cannot write to fixed value: " + value); - case Opcodes.ILOAD: - case Opcodes.FLOAD: - case Opcodes.ALOAD: - case Opcodes.LLOAD: - case Opcodes.DLOAD: - methodVisitor.visitLdcInsn(value); - return NO_PADDING; - default: - throw new IllegalArgumentException("Did not expect opcode: " + opcode); - } - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot write to fixed value: " + value); - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForConstantPoolValue that = (ForConstantPoolValue) other; - return value.equals(that.value); - } - - @Override - public int hashCode() { - return value.hashCode(); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForConstantPoolValue{" + - "value=" + value + - '}'; - } - - /** - * A binding for a constant pool value that is a primitive value and is boxed after loading. - */ - protected static class WithBoxing extends ForConstantPoolValue { - - /** - * The primitive dispatcher to use. - */ - private final PrimitiveDispatcher primitiveDispatcher; - - /** - * Creates a primitive dispatcher that also applied boxing. - * - * @param value The constant pool value. - * @param primitiveDispatcher The primitive dispatcher to use. - */ - protected WithBoxing(Object value, PrimitiveDispatcher primitiveDispatcher) { - super(value); - this.primitiveDispatcher = primitiveDispatcher; - } + StackManipulation resolveRead(); - /** - * Creates a new binding for a constant pool value with a boxed value. - * - * @param value The primitive value to bind. - * @return An appropriate binding target. - */ - protected static Target of(Object value) { - return new WithBoxing(value, PrimitiveDispatcher.of(new TypeDescription.ForLoadedType(value.getClass()).asUnboxed())); - } + StackManipulation resolveWrite(); - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - try { - return super.resolveAccess(methodVisitor, opcode); - } finally { - primitiveDispatcher.box(methodVisitor); - } - } + StackManipulation resolveIncrement(int value); - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - if (!super.equals(other)) return false; - WithBoxing that = (WithBoxing) other; - return primitiveDispatcher == that.primitiveDispatcher; - } + enum ForThis implements Target { + READ_ONLY { @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + primitiveDispatcher.hashCode(); - return result; + public StackManipulation resolveWrite() { + throw new IllegalStateException("Cannot write to read-only this reference"); } + }, + READ_WRITE { @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForConstantPoolValue.WithBoxing{" + - "primitiveDispatcher=" + primitiveDispatcher + - '}'; - } - } - } - - /** - * A target for an offset mapping to load a type constant onto the operand stack. - */ - class ForType implements Target { - - /** - * The type to load onto the operand stack. - */ - private final TypeDescription typeDescription; - - /** - * Creates a new target for an offset mapping for a type constant. - * - * @param typeDescription The type to load onto the operand stack. - */ - public ForType(TypeDescription typeDescription) { - this.typeDescription = typeDescription; - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - load(methodVisitor, typeDescription); - return NO_PADDING; - default: - throw new IllegalStateException("Cannot write to fixed value: " + typeDescription); - } - } - - /** - * Loads a type constant onto the operand stack. - * - * @param methodVisitor The method visitor to use. - * @param typeDescription The type to load into the operand stack. - */ - protected static void load(MethodVisitor methodVisitor, TypeDescription typeDescription) { - methodVisitor.visitLdcInsn(typeDescription.getName()); - methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - TypeDescription.CLASS.getInternalName(), - "forName", - Type.getMethodDescriptor(Type.getType(Class.class), Type.getType(String.class)), - false); - } - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Unexpected increment"); - } - - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForType forType = (ForType) other; - return typeDescription.equals(forType.typeDescription); - } - - @Override - public int hashCode() { - return typeDescription.hashCode(); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForType{" + - "typeDescription=" + typeDescription + - '}'; - } - } - - /** - * A target for an offset mapping that boxes a primitive parameter value. - */ - abstract class ForBoxedArgument implements Target { - - /** - * The parameters offset. - */ - protected final int offset; - - /** - * A dispatcher for boxing the primitive value. - */ - protected final PrimitiveDispatcher primitiveDispatcher; - - /** - * Creates a new offset mapping for boxing a primitive parameter value. - * - * @param offset The parameters offset. - * @param primitiveDispatcher A dispatcher for boxing the primitive value. - */ - protected ForBoxedArgument(int offset, PrimitiveDispatcher primitiveDispatcher) { - this.offset = offset; - this.primitiveDispatcher = primitiveDispatcher; - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - return primitiveDispatcher.loadBoxed(methodVisitor, offset); - case Opcodes.ASTORE: - return onStore(methodVisitor); - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); + public StackManipulation resolveWrite() { + return MethodVariableAccess.REFERENCE.storeAt(0); } - } - - /** - * Handles writing the boxed value if applicable. - * - * @param methodVisitor The method visitor for which to apply the writing. - * @return The additional required stack size. - */ - protected abstract int onStore(MethodVisitor methodVisitor); - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot increment a boxed parameter"); - } + }; @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForBoxedArgument that = (ForBoxedArgument) other; - return offset == that.offset && primitiveDispatcher == that.primitiveDispatcher; + public StackManipulation resolveRead() { + return MethodVariableAccess.REFERENCE.loadFrom(0); } @Override - public int hashCode() { - int result = offset; - result = 31 * result + primitiveDispatcher.hashCode(); - return result; - } - - /** - * A target mapping for a boxed parameter that only allows reading the boxed value. - */ - protected static class ReadOnly extends ForBoxedArgument { - - /** - * Creates a new read-only target offset mapping for a boxed parameter. - * - * @param offset The parameters offset. - * @param primitiveDispatcher A dispatcher for boxing the primitive value. - */ - protected ReadOnly(int offset, PrimitiveDispatcher primitiveDispatcher) { - super(offset, primitiveDispatcher); - } - - /** - * Creates an appropriate target mapping. - * - * @param offset The parameters offset. - * @param type The primitive type that is boxed or unboxed. - * @return An appropriate target mapping. - */ - protected static Target of(int offset, TypeDefinition type) { - return new ReadOnly(offset, PrimitiveDispatcher.of(type)); - } - - @Override - protected int onStore(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only boxed parameter"); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForBoxedArgument.ReadOnly{" + - "offset=" + offset + - ", primitiveDispatcher=" + primitiveDispatcher + - '}'; - } - } - - /** - * A target mapping for a boxed parameter that allows reading and writing the boxed value. - */ - protected static class ReadWrite extends ForBoxedArgument { - - /** - * Creates a new read-write target offset mapping for a boxed parameter. - * - * @param offset The parameters offset. - * @param primitiveDispatcher A dispatcher for boxing the primitive value. - */ - protected ReadWrite(int offset, PrimitiveDispatcher primitiveDispatcher) { - super(offset, primitiveDispatcher); - } - - /** - * Creates an appropriate target mapping. - * - * @param offset The parameters offset. - * @param type The primitive type that is boxed or unboxed. - * @return An appropriate target mapping. - */ - protected static Target of(int offset, TypeDefinition type) { - return new ReadWrite(offset, PrimitiveDispatcher.of(type)); - } - - @Override - protected int onStore(MethodVisitor methodVisitor) { - return primitiveDispatcher.storeUnboxed(methodVisitor, offset); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForBoxedArgument.ReadWrite{" + - "offset=" + offset + - ", primitiveDispatcher=" + primitiveDispatcher + - '}'; - } + public StackManipulation resolveIncrement(int value) { + throw new IllegalStateException("Cannot increment this variable"); } } - /** - * A target for an offset mapping of an array containing all (boxed) arguments of the instrumented method. - */ - abstract class ForBoxedArguments implements Target { - - /** - * The parameters of the instrumented method. - */ - protected final List parameters; - - /** - * Creates a mapping for a boxed array containing all arguments of the instrumented method. - * - * @param parameters The parameters of the instrumented method. - */ - protected ForBoxedArguments(List parameters) { - this.parameters = parameters; - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - PrimitiveDispatcher.loadInteger(methodVisitor, parameters.size()); - methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, TypeDescription.OBJECT.getInternalName()); - StackSize stackSize = StackSize.ZERO; - for (ParameterDescription parameter : parameters) { - methodVisitor.visitInsn(Opcodes.DUP); - PrimitiveDispatcher.loadInteger(methodVisitor, parameter.getIndex()); - if (parameter.getType().isPrimitive()) { - PrimitiveDispatcher.of(parameter.getType()).loadBoxed(methodVisitor, parameter.getOffset()); - } else { - methodVisitor.visitVarInsn(Opcodes.ALOAD, parameter.getOffset()); - } - methodVisitor.visitInsn(Opcodes.AASTORE); - stackSize = stackSize.maximum(parameter.getType().getStackSize()); - } - return stackSize.getSize() + (parameters.isEmpty() - ? 0 - : 2); - case Opcodes.ASTORE: - return onStore(methodVisitor); - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); - } - } - - /** - * Invoked when the parsed code indicates an attempt to replace the existing parameters. - * - * @param methodVisitor The method visitor to use. - * @return The required padding to the advice's total stack size. - */ - protected abstract int onStore(MethodVisitor methodVisitor); + abstract class ForDefaultValue implements Target { - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot increment a boxed argument"); - } + protected final TypeDefinition typeDefinition; - @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForBoxedArguments that = (ForBoxedArguments) other; - return parameters.equals(that.parameters); + protected ForDefaultValue(TypeDefinition typeDefinition) { + this.typeDefinition = typeDefinition; } @Override - public int hashCode() { - return parameters.hashCode(); + public StackManipulation resolveRead() { + return DefaultValue.of(typeDefinition); } - /** - * A mapping for a method's arguments which does not allow for replacing the arguments. - */ - protected static class ReadOnly extends ForBoxedArguments { + protected static class ReadOnly extends ForDefaultValue { - /** - * Creates a new mapping for a method's boxed arguments which does not allow for replacing those arguments. - * - * @param parameters The parameters of the instrumented method. - */ - protected ReadOnly(List parameters) { - super(parameters); + protected ReadOnly(TypeDefinition typeDefinition) { + super(typeDefinition); } @Override - protected int onStore(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only parameter"); + public StackManipulation resolveWrite() { + throw new IllegalStateException(); } @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForBoxedArguments.ReadOnly{" + - "parameters=" + parameters + - '}'; + public StackManipulation resolveIncrement(int value) { + throw new IllegalStateException(); } } - /** - * A mapping for a method's arguments which allows for replacing the arguments. - */ - protected static class ReadWrite extends ForBoxedArguments { + protected static class ReadWrite extends ForDefaultValue { - /** - * Creates a new mapping for a method's boxed arguments which allows for replacing those arguments. - * - * @param parameters The parameters of the instrumented method. - */ - protected ReadWrite(List parameters) { - super(parameters); + protected ReadWrite(TypeDefinition typeDefinition) { + super(typeDefinition); } @Override - protected int onStore(MethodVisitor methodVisitor) { - StackSize stackSize = StackSize.ZERO; - for (ParameterDescription parameter : parameters) { - methodVisitor.visitInsn(Opcodes.DUP); - PrimitiveDispatcher.loadInteger(methodVisitor, parameter.getIndex()); - methodVisitor.visitInsn(Opcodes.AALOAD); - if (parameter.getType().isPrimitive()) { - PrimitiveDispatcher.of(parameter.getType()).storeUnboxed(methodVisitor, parameter.getOffset()); - } else { - if (!parameter.getType().represents(Object.class)) { - methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, parameter.getType().asErasure().getInternalName()); - } - methodVisitor.visitVarInsn(Opcodes.ASTORE, parameter.getOffset()); - } - stackSize = stackSize.maximum(parameter.getType().getStackSize()); - } - methodVisitor.visitInsn(Opcodes.POP); - return stackSize.getSize() + (parameters.isEmpty() - ? 0 - : 2); + public StackManipulation resolveWrite() { + return Removal.pop(typeDefinition); } @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForBoxedArguments.ReadWrite{" + - "parameters=" + parameters + - '}'; + public StackManipulation resolveIncrement(int value) { + return StackManipulation.Trivial.INSTANCE; } } } - /** - * A target for an offset mapping representing an executable instance. - */ - abstract class ForExecutable implements Target { - - /** - * The method to represent as a constant. - */ - protected final MethodDescription.InDefinedShape methodDescription; - - /** - * Creates a new offset mapping for an executable constant. - * - * @param methodDescription The method to represent as a constant. - */ - protected ForExecutable(MethodDescription.InDefinedShape methodDescription) { - this.methodDescription = methodDescription; - } - - /** - * Resolves an appropriate target for an offset mapping that represents a constant for a method or constructor. - * - * @param methodDescription The method description to represent as a constant. - * @return An appropriate target. - */ - public static Target of(MethodDescription.InDefinedShape methodDescription) { - if (methodDescription.isMethod()) { - return new ForMethod(methodDescription); - } else if (methodDescription.isConstructor()) { - return new ForConstructor(methodDescription); - } else { - throw new IllegalStateException("Cannot represent type initializer of " + methodDescription.getDeclaringType() + " as constant"); - } - } - - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - ForType.load(methodVisitor, methodDescription.getDeclaringType()); - loadMethodName(methodVisitor); - PrimitiveDispatcher.loadInteger(methodVisitor, methodDescription.getParameters().size()); - methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, TypeDescription.CLASS.getInternalName()); - for (ParameterDescription parameter : methodDescription.getParameters()) { - methodVisitor.visitInsn(Opcodes.DUP); - PrimitiveDispatcher.loadInteger(methodVisitor, parameter.getIndex()); - if (parameter.getType().isPrimitive()) { - PrimitiveDispatcher.of(parameter.getType()).loadType(methodVisitor); - } else { - ForType.load(methodVisitor, parameter.getType().asErasure()); - } - methodVisitor.visitInsn(Opcodes.AASTORE); - } - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - TypeDescription.CLASS.getInternalName(), - getInvokedMethod(), - getInvokedSignature(), - false); - return getAdditionalOffset() + (methodDescription.getParameters().isEmpty() - ? 0 - : 3); - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); - } - } - - /** - * Loads the method's name onto the operand stack if required. - * - * @param methodVisitor The method visitor to use. - */ - protected abstract void loadMethodName(MethodVisitor methodVisitor); - - /** - * Returns the invoked method of the {@link Class} API. - * - * @return The invoked method's name. - */ - protected abstract String getInvokedMethod(); + abstract class ForVariable implements Target { - /** - * Returns the signature of the invoked method. - * - * @return The signature of the invoked method. - */ - protected abstract String getInvokedSignature(); + protected final TypeDefinition typeDefinition; - /** - * Adds the additional required offset. - * - * @return The additional required offset. - */ - protected abstract int getAdditionalOffset(); + protected final int offset; - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Unexpected increment"); + protected ForVariable(TypeDefinition typeDefinition, int offset) { + this.typeDefinition = typeDefinition; + this.offset = offset; } @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForExecutable that = (ForExecutable) other; - return methodDescription.equals(that.methodDescription); + public StackManipulation resolveRead() { + return MethodVariableAccess.of(typeDefinition).loadFrom(offset); } - @Override - public int hashCode() { - return methodDescription.hashCode(); - } + protected static class ReadOnly extends ForVariable { - /** - * A constant for a {@link Method} constant. - */ - protected static class ForMethod extends ForExecutable { + protected ReadOnly(TypeDefinition typeDefinition, int offset) { + super(typeDefinition, offset); + } - /** - * Creates a new offset mapping target for a method constant. - * - * @param methodDescription The method to represent. - */ - protected ForMethod(MethodDescription.InDefinedShape methodDescription) { - super(methodDescription); + protected static Target of(ParameterDescription parameterDescription) { + return new ReadOnly(parameterDescription.getType(), parameterDescription.getOffset()); } @Override - protected void loadMethodName(MethodVisitor methodVisitor) { - methodVisitor.visitLdcInsn(methodDescription.getInternalName()); + public StackManipulation resolveWrite() { + throw new IllegalStateException("Cannot write to read-only parameter " + typeDefinition + " at " + offset); } @Override - protected String getInvokedMethod() { - return "getDeclaredMethod"; + public StackManipulation resolveIncrement(int value) { + throw new IllegalStateException("Cannot write to read-only variable " + typeDefinition + " at " + offset); } + } - @Override - protected String getInvokedSignature() { - return Type.getMethodDescriptor(Type.getType(Method.class), Type.getType(String.class), Type.getType(Class[].class)); + protected static class ReadWrite extends ForVariable { + + protected ReadWrite(TypeDefinition typeDefinition, int offet) { + super(typeDefinition, offet); + } + + protected static Target of(ParameterDescription parameterDescription) { + return new ReadWrite(parameterDescription.getType(), parameterDescription.getOffset()); } @Override - protected int getAdditionalOffset() { - return 2; + public StackManipulation resolveWrite() { + return MethodVariableAccess.of(typeDefinition).storeAt(offset); } @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForExecutable.ForMethod{" + - "methodDescription=" + methodDescription + - "}"; + public StackManipulation resolveIncrement(int value) { + return MethodVariableAccess.of(typeDefinition).increment(offset, value); } } + } - /** - * A constant for a {@link Constructor} constant. - */ - protected static class ForConstructor extends ForExecutable { + abstract class ForField implements Target { - /** - * Creates a new offset mapping target for a constructor constant. - * - * @param methodDescription The method to represent. - */ - protected ForConstructor(MethodDescription.InDefinedShape methodDescription) { - super(methodDescription); - } + protected final FieldDescription fieldDescription; - @Override - protected void loadMethodName(MethodVisitor methodVisitor) { - /* do nothing */ - } + protected ForField(FieldDescription fieldDescription) { + this.fieldDescription = fieldDescription; + } - @Override - protected String getInvokedMethod() { - return "getDeclaredConstructor"; - } + @Override + public StackManipulation resolveRead() { + return new StackManipulation.Compound(fieldDescription.isStatic() + ? StackManipulation.Trivial.INSTANCE + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(fieldDescription).getter()); + } - @Override - protected String getInvokedSignature() { - return Type.getMethodDescriptor(Type.getType(Constructor.class), Type.getType(Class[].class)); + static class ReadOnly extends ForField { + + public ReadOnly(FieldDescription fieldDescription) { + super(fieldDescription); } @Override - protected int getAdditionalOffset() { - return 1; + public StackManipulation resolveWrite() { + return null; } @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForExecutable.ForConstructor{" + - "methodDescription=" + methodDescription + - "}"; + public StackManipulation resolveIncrement(int value) { + return null; } } - } - /** - * Binds a null constant to the target parameter. - */ - enum ForNullConstant implements Target { + static class ReadWrite extends ForField { - /** - * A null constant that can only be put onto the stack. - */ - READ_ONLY { - @Override - protected void onWrite(MethodVisitor methodVisitor) { - throw new IllegalStateException("Cannot write to read-only value"); + protected ReadWrite(FieldDescription fieldDescription) { + super(fieldDescription); } - }, - /** - * A null constant that also allows virtual writes where the result is simply popped. - */ - READ_WRITE { @Override - protected void onWrite(MethodVisitor methodVisitor) { - methodVisitor.visitInsn(Opcodes.POP); + public StackManipulation resolveWrite() { + StackManipulation preparation; + if (fieldDescription.isStatic()) { + preparation = StackManipulation.Trivial.INSTANCE; + } else { + preparation = new StackManipulation.Compound( + MethodVariableAccess.REFERENCE.loadFrom(0), + Duplication.SINGLE.flipOver(fieldDescription.getType()) + ); + } + return new StackManipulation.Compound(preparation, FieldAccess.forField(fieldDescription).putter()); } - }; - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - methodVisitor.visitInsn(Opcodes.ACONST_NULL); - break; - case Opcodes.ASTORE: - onWrite(methodVisitor); - break; - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); + @Override + public StackManipulation resolveIncrement(int value) { + return new StackManipulation.Compound( + resolveRead(), + IntegerConstant.forValue(value), + Addition.INTEGER, + resolveWrite() + ); } - return NO_PADDING; - } - - /** - * Determines the behavior when writing to the target. - * - * @param methodVisitor The method visitor to which to write the result of the mapping. - */ - protected abstract void onWrite(MethodVisitor methodVisitor); - - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot increment a null constant"); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForNullConstant." + name(); } } - /** - * Creates a target that represents a value in form of a serialized field. - */ - class ForSerializedObject implements Target { - - /** - * A charset that does not change the supplied byte array upon encoding or decoding. - */ - private static final String CHARSET = "ISO-8859-1"; + class ForStackManipulation implements Target { - /** - * The target type. - */ - private final TypeDescription target; + private final StackManipulation stackManipulation; - /** - * The serialized form of the supplied form encoded as a string to be stored in the constant pool. - */ - private final String serialized; + protected ForStackManipulation(StackManipulation stackManipulation) { + this.stackManipulation = stackManipulation; + } - /** - * Creates a target for an offset mapping that references a serialized value. - * - * @param target The target type. - * @param serialized The serialized form of the supplied form encoded as a string to be stored in the constant pool. - */ - protected ForSerializedObject(TypeDescription target, String serialized) { - this.target = target; - this.serialized = serialized; + protected static Target of(MethodDescription.InDefinedShape methodDescription) { + return new ForStackManipulation(MethodConstant.forMethod(methodDescription)); } - /** - * Resolves a serializable value to a target that reads a value from reconstructing a serializable string representation. - * - * @param target The target type of the serializable value. - * @param value The value that the mapped field should represent. - * @return A target for deserializing the supplied value on access. - */ - protected static Target of(TypeDescription target, Serializable value) { - try { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); - try { - objectOutputStream.writeObject(value); - } finally { - objectOutputStream.close(); - } - return new ForSerializedObject(target, byteArrayOutputStream.toString(CHARSET)); - } catch (IOException exception) { - throw new IllegalStateException("Cannot serialize " + value, exception); - } + protected static Target of(TypeDescription typeDescription) { + return new ForStackManipulation(ClassConstant.of(typeDescription)); } - @Override - public int resolveAccess(MethodVisitor methodVisitor, int opcode) { - switch (opcode) { - case Opcodes.ALOAD: - methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(ObjectInputStream.class)); - methodVisitor.visitInsn(Opcodes.DUP); - methodVisitor.visitTypeInsn(Opcodes.NEW, Type.getInternalName(ByteArrayInputStream.class)); - methodVisitor.visitInsn(Opcodes.DUP); - methodVisitor.visitLdcInsn(serialized); - methodVisitor.visitLdcInsn(CHARSET); - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - Type.getInternalName(String.class), - "getBytes", - Type.getMethodType(Type.getType(byte[].class), Type.getType(String.class)).toString(), - false); - methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, - Type.getInternalName(ByteArrayInputStream.class), - MethodDescription.CONSTRUCTOR_INTERNAL_NAME, - Type.getMethodType(Type.VOID_TYPE, Type.getType(byte[].class)).toString(), - false); - methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, - Type.getInternalName(ObjectInputStream.class), - MethodDescription.CONSTRUCTOR_INTERNAL_NAME, - Type.getMethodType(Type.VOID_TYPE, Type.getType(InputStream.class)).toString(), - false); - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - Type.getInternalName(ObjectInputStream.class), - "readObject", - Type.getMethodType(Type.getType(Object.class)).toString(), - false); - methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, target.getInternalName()); - return 5; - default: - throw new IllegalStateException("Unexpected opcode: " + opcode); - } + protected static Target of(String value) { + return new ForStackManipulation(new TextConstant(value)); } - @Override - public int resolveIncrement(MethodVisitor methodVisitor, int increment) { - throw new IllegalStateException("Cannot increment serialized object"); + protected static Target of(Object value) { + if (value instanceof Boolean) { + return new ForStackManipulation(IntegerConstant.forValue((Boolean) value)); + } else if (value instanceof Byte) { + return new ForStackManipulation(IntegerConstant.forValue((Byte) value)); + } else if (value instanceof Short) { + return new ForStackManipulation(IntegerConstant.forValue((Short) value)); + } else if (value instanceof Character) { + return new ForStackManipulation(IntegerConstant.forValue((Character) value)); + } else if (value instanceof Integer) { + return new ForStackManipulation(IntegerConstant.forValue((Integer) value)); + } else if (value instanceof Long) { + return new ForStackManipulation(LongConstant.forValue((Long) value)); + } else if (value instanceof Float) { + return new ForStackManipulation(FloatConstant.forValue((Float) value)); + } else if (value instanceof Double) { + return new ForStackManipulation(DoubleConstant.forValue((Double) value)); + } else if (value instanceof String) { + return new ForStackManipulation(new TextConstant((String) value)); + } else { + throw new IllegalArgumentException(); + } } @Override - public boolean equals(Object other) { - if (this == other) return true; - if (other == null || getClass() != other.getClass()) return false; - ForSerializedObject that = (ForSerializedObject) other; - return target.equals(that.target) && serialized.equals(that.serialized); + public StackManipulation resolveRead() { + return stackManipulation; } @Override - public int hashCode() { - int result = target.hashCode(); - result = 31 * result + serialized.hashCode(); - return result; + public StackManipulation resolveWrite() { + throw new IllegalStateException("Cannot write to constant value: " + stackManipulation); } @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.Target.ForSerializedObject{" + - "target=" + target + - ", serialized='" + serialized + '\'' + - '}'; + public StackManipulation resolveIncrement(int value) { + throw new IllegalStateException("Cannot write to constant value: " + stackManipulation); } } } @@ -3472,8 +2046,8 @@ public Target resolve(TypeDescription instrumentedType, MethodDescription instru throw new IllegalStateException(targetType + " is not assignable to " + parameters.get(index)); } return readOnly - ? new Target.ForParameter.ReadOnly(parameters.get(index).getOffset()) - : new Target.ForParameter.ReadWrite(parameters.get(index).getOffset()); + ? Target.ForVariable.ReadOnly.of(parameters.get(index)) + : Target.ForVariable.ReadWrite.of(parameters.get(index)); } @Override @@ -3556,11 +2130,6 @@ public String toString() { */ class ForThisReference implements OffsetMapping { - /** - * The offset of the this reference in a Java method. - */ - private static final int THIS_REFERENCE = 0; - /** * Determines if the parameter is to be treated as read-only. */ @@ -3597,16 +2166,16 @@ public Target resolve(TypeDescription instrumentedType, MethodDescription instru throw new IllegalStateException("Declaring type of " + instrumentedMethod + " is not assignable to " + targetType); } else if (instrumentedMethod.isStatic() && optional) { return readOnly - ? Target.ForNullConstant.READ_ONLY - : Target.ForNullConstant.READ_WRITE; + ? new Target.ForDefaultValue.ReadOnly(instrumentedType.getDeclaringType()) + : new Target.ForDefaultValue.ReadWrite(instrumentedType.getDeclaringType()); } else if (instrumentedMethod.isStatic() && !optional) { throw new IllegalStateException("Cannot map this reference for static method " + instrumentedMethod); } else if (!context.isInitialized()) { throw new IllegalStateException("Cannot access this reference before calling constructor: " + instrumentedMethod); } return readOnly - ? new Target.ForParameter.ReadOnly(THIS_REFERENCE) - : new Target.ForParameter.ReadWrite(THIS_REFERENCE); + ? Target.ForThis.READ_ONLY + : Target.ForThis.READ_WRITE; } @Override @@ -3698,7 +2267,7 @@ enum ForInstrumentedType implements OffsetMapping { @Override public Target resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Context context) { - return new Target.ForType(instrumentedType); + return Target.ForStackManipulation.of(instrumentedType); } @Override @@ -3747,7 +2316,7 @@ public Target resolve(TypeDescription instrumentedType, MethodDescription instru if (!isRepresentable(instrumentedMethod)) { throw new IllegalStateException("Cannot represent " + instrumentedMethod + " as given method constant"); } - return Target.ForExecutable.of(instrumentedMethod.asDefined()); + return Target.ForStackManipulation.of(instrumentedMethod.asDefined()); } /** @@ -4084,7 +2653,7 @@ public Target resolve(TypeDescription instrumentedType, MethodDescription instru for (Renderer renderer : renderers) { stringBuilder.append(renderer.apply(instrumentedType, instrumentedMethod)); } - return new Target.ForConstantPoolValue(stringBuilder.toString()); + return Target.ForStackManipulation.of(stringBuilder.toString()); } @Override @@ -4368,28 +2937,29 @@ public String toString() { /** * An offset mapping for a parameter where assignments are fully ignored and that always return the parameter type's default value. */ - enum ForUnusedValue implements OffsetMapping, Factory { + class ForUnusedValue implements OffsetMapping { - /** - * The singleton instance. - */ - INSTANCE; + private final TypeDefinition typeDefinition; - @Override - public Target resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Context context) { - return Target.ForDefaultValue.INSTANCE; + ForUnusedValue(TypeDefinition typeDefinition) { + this.typeDefinition = typeDefinition; } @Override - public OffsetMapping make(ParameterDescription.InDefinedShape parameterDescription) { - return parameterDescription.getDeclaredAnnotations().isAnnotationPresent(Unused.class) - ? this - : UNDEFINED; + public Target resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Context context) { + return new Target.ForDefaultValue.ReadWrite(typeDefinition); } - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.ForUnusedValue." + name(); + enum Factory implements OffsetMapping.Factory { + + INSTANCE; + + @Override + public OffsetMapping make(ParameterDescription.InDefinedShape parameterDescription) { + return parameterDescription.getDeclaredAnnotations().isAnnotationPresent(Unused.class) + ? new ForUnusedValue(parameterDescription.getType()) + : UNDEFINED; + } } } @@ -4431,54 +3001,17 @@ public String toString() { /** * An offset mapping that provides access to the value that is returned by the enter advice. */ - enum ForEnterValue implements OffsetMapping { - - /** - * Enables writing to the mapped offset. - */ - WRITABLE(false), - - /** - * Only allows for reading the mapped offset. - */ - READ_ONLY(true); - - /** - * Determines if the parameter is to be treated as read-only. - */ - private final boolean readOnly; + class ForEnterValue implements OffsetMapping { - /** - * Creates a new offset mapping for an enter value. - * - * @param readOnly Determines if the parameter is to be treated as read-only. - */ - ForEnterValue(boolean readOnly) { - this.readOnly = readOnly; - } + private final TypeDescription typeDescription; - /** - * Resolves an offset mapping for an enter value. - * - * @param readOnly {@code true} if the value is to be treated as read-only. - * @return An appropriate offset mapping. - */ - public static OffsetMapping of(boolean readOnly) { - return readOnly - ? READ_ONLY - : WRITABLE; + protected ForEnterValue(TypeDescription typeDescription) { + this.typeDescription = typeDescription; } @Override public Target resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Context context) { - return readOnly - ? new Target.ForParameter.ReadOnly(instrumentedMethod.getStackSize()) - : new Target.ForParameter.ReadWrite(instrumentedMethod.getStackSize()); - } - - @Override - public String toString() { - return "Advice.Dispatcher.OffsetMapping.ForEnterValue." + name(); + return new Target.ForVariable.ReadOnly(typeDescription, instrumentedMethod.getStackSize()); } /** @@ -4519,7 +3052,7 @@ public OffsetMapping make(ParameterDescription.InDefinedShape parameterDescripti } else if (this.readOnly && !readOnly) { throw new IllegalStateException("Cannot write to enter value field for " + parameterDescription + " in read only context"); } - return ForEnterValue.of(readOnly); + return new ForEnterValue(enterType); // TODO: Merge factory with target } else { return UNDEFINED; } @@ -4584,8 +3117,8 @@ public Target resolve(TypeDescription instrumentedType, MethodDescription instru throw new IllegalStateException("Cannot assign return type of " + instrumentedMethod + " to " + targetType); } return readOnly - ? new Target.ForParameter.ReadOnly(instrumentedMethod.getStackSize() + context.getPadding()) - : new Target.ForParameter.ReadWrite(instrumentedMethod.getStackSize() + context.getPadding()); + ? new Target.ForVariable.ReadOnly(instrumentedMethod.getReturnType(), instrumentedMethod.getStackSize() + context.getPadding()) + : new Target.ForVariable.ReadWrite(instrumentedMethod.getReturnType(), instrumentedMethod.getStackSize() + context.getPadding()); } @Override @@ -4890,8 +3423,8 @@ protected ForThrowable(TypeDescription targetType, TypeDescription triggeringThr public Target resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, Context context) { int offset = instrumentedMethod.getStackSize() + context.getPadding() + instrumentedMethod.getReturnType().getStackSize().getSize(); return readOnly - ? new Target.ForParameter.ReadOnly(offset) - : new Target.ForParameter.ReadWrite(offset); + ? new Target.ForVariable.ReadOnly(TypeDescription.THROWABLE, offset) + : new Target.ForVariable.ReadWrite(TypeDescription.THROWABLE, offset); } @Override @@ -5523,6 +4056,7 @@ interface Resolved extends Dispatcher { Bound bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler); @@ -5550,6 +4084,7 @@ interface ForMethodEnter extends Resolved { Bound.ForMethodEnter bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler); @@ -5930,6 +4465,7 @@ interface ForMethodExit extends Resolved { Bound.ForMethodExit bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler); } @@ -6051,6 +4587,7 @@ public void apply(SkipHandler skipHandler) { public Inactive bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler) { return this; @@ -6202,6 +4739,7 @@ public boolean isAlive() { * @return A method visitor for visiting the advice method's byte code. */ protected abstract MethodVisitor apply(MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, TypeDescription instrumentedType, @@ -6244,6 +4782,8 @@ protected abstract class AdviceMethodInliner extends ClassVisitor implements Bou */ protected final MethodVisitor methodVisitor; + protected final Implementation.Context implementationContext; + /** * A handler for computing the method size requirements. */ @@ -6283,6 +4823,7 @@ protected abstract class AdviceMethodInliner extends ClassVisitor implements Bou protected AdviceMethodInliner(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, SuppressionHandler.Bound suppressionHandler, @@ -6291,6 +4832,7 @@ protected AdviceMethodInliner(TypeDescription instrumentedType, this.instrumentedType = instrumentedType; this.instrumentedMethod = instrumentedMethod; this.methodVisitor = methodVisitor; + this.implementationContext = implementationContext; this.methodSizeHandler = methodSizeHandler; this.stackMapFrameHandler = stackMapFrameHandler; this.suppressionHandler = suppressionHandler; @@ -6314,7 +4856,7 @@ protected void doApply() { @Override public MethodVisitor visitMethod(int modifiers, String internalName, String descriptor, String signature, String[] exception) { return adviceMethod.getInternalName().equals(internalName) && adviceMethod.getDescriptor().equals(descriptor) - ? new ExceptionTableSubstitutor(Inlining.Resolved.this.apply(methodVisitor, methodSizeHandler, stackMapFrameHandler, instrumentedType, instrumentedMethod, suppressionHandler)) + ? new ExceptionTableSubstitutor(Inlining.Resolved.this.apply(methodVisitor, implementationContext, methodSizeHandler, stackMapFrameHandler, instrumentedType, instrumentedMethod, suppressionHandler)) : IGNORE_METHOD; } @@ -6518,7 +5060,7 @@ protected ForMethodEnter(MethodDescription.InDefinedShape adviceMethod, OffsetMapping.ForThisReference.Factory.READ_WRITE, OffsetMapping.ForField.Factory.READ_WRITE, OffsetMapping.ForOrigin.Factory.INSTANCE, - OffsetMapping.ForUnusedValue.INSTANCE, + OffsetMapping.ForUnusedValue.Factory.INSTANCE, OffsetMapping.ForStubValue.INSTANCE, new OffsetMapping.Illegal(Thrown.class, Enter.class, Return.class, BoxedReturn.class)), userFactories), classReader, @@ -6531,11 +5073,13 @@ protected ForMethodEnter(MethodDescription.InDefinedShape adviceMethod, public Bound.ForMethodEnter bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler) { return new AdviceMethodInliner(instrumentedType, instrumentedMethod, methodVisitor, + implementationContext, methodSizeHandler, stackMapFrameHandler, suppressionHandler.bind(), @@ -6555,6 +5099,7 @@ public boolean isPrependLineNumber() { @Override protected MethodVisitor apply(MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, TypeDescription instrumentedType, @@ -6567,6 +5112,7 @@ protected MethodVisitor apply(MethodVisitor methodVisitor, OffsetMapping.Context.ForMethodEntry.of(instrumentedMethod))); } return new CodeTranslationVisitor.ForMethodEnter(methodVisitor, + implementationContext, methodSizeHandler.bindEntry(adviceMethod), stackMapFrameHandler.bindEntry(adviceMethod), instrumentedMethod, @@ -6627,12 +5173,20 @@ protected class AdviceMethodInliner extends Inlining.Resolved.AdviceMethodInline public AdviceMethodInliner(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, SuppressionHandler.Bound suppressionHandler, ClassReader classReader, SkipDispatcher skipDispatcher) { - super(instrumentedType, instrumentedMethod, methodVisitor, methodSizeHandler, stackMapFrameHandler, suppressionHandler, classReader); + super(instrumentedType, + instrumentedMethod, + methodVisitor, + implementationContext, + methodSizeHandler, + stackMapFrameHandler, + suppressionHandler, + classReader); this.skipDispatcher = skipDispatcher; } @@ -6692,7 +5246,7 @@ protected ForMethodExit(MethodDescription.InDefinedShape adviceMethod, OffsetMapping.ForThisReference.Factory.READ_WRITE, OffsetMapping.ForField.Factory.READ_WRITE, OffsetMapping.ForOrigin.Factory.INSTANCE, - OffsetMapping.ForUnusedValue.INSTANCE, + OffsetMapping.ForUnusedValue.Factory.INSTANCE, OffsetMapping.ForStubValue.INSTANCE, new OffsetMapping.ForEnterValue.Factory(enterType, false), OffsetMapping.ForReturnValue.Factory.READ_WRITE, @@ -6728,6 +5282,7 @@ protected static Resolved.ForMethodExit of(MethodDescription.InDefinedShape advi @Override protected MethodVisitor apply(MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, TypeDescription instrumentedType, @@ -6740,6 +5295,7 @@ protected MethodVisitor apply(MethodVisitor methodVisitor, OffsetMapping.Context.ForMethodExit.of(enterType))); } return new CodeTranslationVisitor.ForMethodExit(methodVisitor, + implementationContext, methodSizeHandler.bindExit(adviceMethod, getTriggeringThrowable().represents(NoExceptionHandler.class)), stackMapFrameHandler.bindExit(adviceMethod), instrumentedMethod, @@ -6754,11 +5310,13 @@ protected MethodVisitor apply(MethodVisitor methodVisitor, public Bound.ForMethodExit bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler) { return new AdviceMethodInliner(instrumentedType, instrumentedMethod, methodVisitor, + implementationContext, methodSizeHandler, stackMapFrameHandler, suppressionHandler.bind(), @@ -6805,11 +5363,19 @@ protected class AdviceMethodInliner extends Inlining.Resolved.AdviceMethodInline public AdviceMethodInliner(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler, SuppressionHandler.Bound suppressionHandler, ClassReader classReader) { - super(instrumentedType, instrumentedMethod, methodVisitor, methodSizeHandler, stackMapFrameHandler, suppressionHandler, classReader); + super(instrumentedType, + instrumentedMethod, + methodVisitor, + implementationContext, + methodSizeHandler, + stackMapFrameHandler, + suppressionHandler, + classReader); } @Override @@ -6933,6 +5499,8 @@ protected abstract static class CodeTranslationVisitor extends MethodVisitor imp */ protected final MethodVisitor methodVisitor; + protected final Implementation.Context implementationContext; + /** * A handler for computing the method size requirements. */ @@ -6971,23 +5539,26 @@ protected abstract static class CodeTranslationVisitor extends MethodVisitor imp /** * Creates a new code translation visitor. * - * @param methodVisitor A method visitor for writing the instrumented method's byte code. - * @param methodSizeHandler A handler for computing the method size requirements. - * @param stackMapFrameHandler A handler for translating and injecting stack map frames. - * @param instrumentedMethod The instrumented method. - * @param adviceMethod The advice method. - * @param offsetMappings A mapping of offsets to resolved target offsets in the instrumented method. - * @param suppressionHandler The suppression handler to use. + * @param methodVisitor A method visitor for writing the instrumented method's byte code. + * @param implementationContext + * @param methodSizeHandler A handler for computing the method size requirements. + * @param stackMapFrameHandler A handler for translating and injecting stack map frames. + * @param instrumentedMethod The instrumented method. + * @param adviceMethod The advice method. + * @param offsetMappings A mapping of offsets to resolved target offsets in the instrumented method. + * @param suppressionHandler The suppression handler to use. */ protected CodeTranslationVisitor(MethodVisitor methodVisitor, + Context implementationContext, MethodSizeHandler.ForAdvice methodSizeHandler, StackMapFrameHandler.ForAdvice stackMapFrameHandler, MethodDescription instrumentedMethod, MethodDescription.InDefinedShape adviceMethod, - Map offsetMappings, + Map offsetMappings, SuppressionHandler.Bound suppressionHandler) { super(Opcodes.ASM5, new StackAwareMethodVisitor(methodVisitor, instrumentedMethod)); this.methodVisitor = methodVisitor; + this.implementationContext = implementationContext; this.methodSizeHandler = methodSizeHandler; this.stackMapFrameHandler = stackMapFrameHandler; this.instrumentedMethod = instrumentedMethod; @@ -7064,19 +5635,44 @@ public void visitMaxs(int stackSize, int localVariableLength) { public void visitVarInsn(int opcode, int offset) { Resolved.OffsetMapping.Target target = offsetMappings.get(offset); if (target != null) { - methodSizeHandler.recordPadding(target.resolveAccess(mv, opcode)); + StackManipulation stackManipulation; + StackSize expectedGrowth; + switch (opcode) { + case Opcodes.ILOAD: + case Opcodes.FLOAD: + case Opcodes.ALOAD: + stackManipulation = target.resolveRead(); + expectedGrowth = StackSize.SINGLE; + break; + case Opcodes.DLOAD: + case Opcodes.LLOAD: + stackManipulation = target.resolveRead(); + expectedGrowth = StackSize.DOUBLE; + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + case Opcodes.LSTORE: + case Opcodes.DSTORE: + stackManipulation = target.resolveWrite(); + expectedGrowth = StackSize.ZERO; + break; + default: + throw new IllegalStateException("Unexpected opcode: " + opcode); + } + methodSizeHandler.recordPadding(stackManipulation.apply(mv, null).getMaximalSize() - expectedGrowth.getSize()); } else { mv.visitVarInsn(opcode, adjust(offset + instrumentedMethod.getStackSize() - adviceMethod.getStackSize())); } } @Override - public void visitIincInsn(int offset, int increment) { + public void visitIincInsn(int offset, int value) { Resolved.OffsetMapping.Target target = offsetMappings.get(offset); if (target != null) { - methodSizeHandler.recordPadding(target.resolveIncrement(mv, increment)); + methodSizeHandler.recordPadding(target.resolveIncrement(value).apply(mv, null).getMaximalSize()); } else { - mv.visitIincInsn(adjust(offset + instrumentedMethod.getStackSize() - adviceMethod.getStackSize()), increment); + mv.visitIincInsn(adjust(offset + instrumentedMethod.getStackSize() - adviceMethod.getStackSize()), value); } } @@ -7119,13 +5715,21 @@ protected static class ForMethodEnter extends CodeTranslationVisitor { * @param suppressionHandler The suppression handler to use. */ protected ForMethodEnter(MethodVisitor methodVisitor, + Context implementationContext, MethodSizeHandler.ForAdvice methodSizeHandler, StackMapFrameHandler.ForAdvice stackMapFrameHandler, MethodDescription instrumentedMethod, MethodDescription.InDefinedShape adviceMethod, Map offsetMappings, SuppressionHandler.Bound suppressionHandler) { - super(methodVisitor, methodSizeHandler, stackMapFrameHandler, instrumentedMethod, adviceMethod, offsetMappings, suppressionHandler); + super(methodVisitor, + implementationContext, + methodSizeHandler, + stackMapFrameHandler, + instrumentedMethod, + adviceMethod, + offsetMappings, + suppressionHandler); doesReturn = false; } @@ -7225,6 +5829,7 @@ protected static class ForMethodExit extends CodeTranslationVisitor { * @param padding The padding after the instrumented method's arguments in the local variable array. */ protected ForMethodExit(MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForAdvice methodSizeHandler, StackMapFrameHandler.ForAdvice stackMapFrameHandler, MethodDescription instrumentedMethod, @@ -7233,6 +5838,7 @@ protected ForMethodExit(MethodVisitor methodVisitor, SuppressionHandler.Bound suppressionHandler, int padding) { super(methodVisitor, + implementationContext, methodSizeHandler, stackMapFrameHandler, instrumentedMethod, @@ -7415,12 +6021,13 @@ public boolean isAlive() { public T bind(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler) { if (!adviceMethod.isVisibleTo(instrumentedType)) { throw new IllegalStateException(adviceMethod + " is not visible to " + instrumentedMethod.getDeclaringType()); } - return resolve(instrumentedType, instrumentedMethod, methodVisitor, methodSizeHandler, stackMapFrameHandler); + return resolve(instrumentedType, instrumentedMethod, methodVisitor, implementationContext, methodSizeHandler, stackMapFrameHandler); } /** @@ -7436,6 +6043,7 @@ public T bind(TypeDescription instrumentedType, protected abstract T resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler); @@ -7541,7 +6149,7 @@ protected void doApply() { for (OffsetMapping.Target offsetMapping : offsetMappings) { Type type = Type.getType(adviceMethod.getParameters().get(index++).getType().asErasure().getDescriptor()); currentStackSize += type.getSize(); - maximumStackSize = Math.max(maximumStackSize, currentStackSize + offsetMapping.resolveAccess(methodVisitor, type.getOpcode(Opcodes.ILOAD))); + maximumStackSize = Math.max(maximumStackSize, currentStackSize + offsetMapping.resolveRead().apply(methodVisitor, null).getMaximalSize()); } methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, adviceMethod.getDeclaringType().getInternalName(), @@ -7753,7 +6361,7 @@ protected ForMethodEnter(MethodDescription.InDefinedShape adviceMethod, List offsetMappings = new ArrayList(this.offsetMappings.size()); @@ -7849,7 +6458,7 @@ protected ForMethodExit(MethodDescription.InDefinedShape adviceMethod, OffsetMapping.ForThisReference.Factory.READ_ONLY, OffsetMapping.ForField.Factory.READ_ONLY, OffsetMapping.ForOrigin.Factory.INSTANCE, - OffsetMapping.ForUnusedValue.INSTANCE, + OffsetMapping.ForUnusedValue.Factory.INSTANCE, OffsetMapping.ForStubValue.INSTANCE, new OffsetMapping.ForEnterValue.Factory(enterType, true), OffsetMapping.ForReturnValue.Factory.READ_ONLY, @@ -7884,6 +6493,7 @@ protected static Resolved.ForMethodExit of(MethodDescription.InDefinedShape advi protected Bound.ForMethodExit resolve(TypeDescription instrumentedType, MethodDescription instrumentedMethod, MethodVisitor methodVisitor, + Implementation.Context implementationContext, MethodSizeHandler.ForInstrumentedMethod methodSizeHandler, StackMapFrameHandler.ForInstrumentedMethod stackMapFrameHandler) { List offsetMappings = new ArrayList(this.offsetMappings.size()); @@ -8049,18 +6659,17 @@ protected abstract static class AdviceVisitor extends ExceptionTableSensitiveMet * @param methodEnter The method enter advice. * @param methodExit The method exit advice. * @param yieldedTypes The types that are expected to be added after the instrumented method returns. - * @param classFileVersion The instrumented type's class file version. * @param writerFlags The ASM writer flags that were set. * @param readerFlags The ASM reader flags that were set. */ protected AdviceVisitor(MethodVisitor methodVisitor, MethodVisitor delegate, + Implementation.Context implementationContext, TypeDescription instrumentedType, MethodDescription instrumentedMethod, Dispatcher.Resolved.ForMethodEnter methodEnter, Dispatcher.Resolved.ForMethodExit methodExit, List yieldedTypes, - ClassFileVersion classFileVersion, int writerFlags, int readerFlags) { super(Opcodes.ASM5, delegate); @@ -8075,11 +6684,11 @@ protected AdviceVisitor(MethodVisitor methodVisitor, instrumentedMethod, requiredTypes, yieldedTypes, - classFileVersion, + implementationContext.getClassFileVersion(), writerFlags, readerFlags); - this.methodEnter = methodEnter.bind(instrumentedType, instrumentedMethod, methodVisitor, methodSizeHandler, stackMapFrameHandler); - this.methodExit = methodExit.bind(instrumentedType, instrumentedMethod, methodVisitor, methodSizeHandler, stackMapFrameHandler); + this.methodEnter = methodEnter.bind(instrumentedType, instrumentedMethod, methodVisitor, implementationContext, methodSizeHandler, stackMapFrameHandler); + this.methodExit = methodExit.bind(instrumentedType, instrumentedMethod, methodVisitor, implementationContext, methodSizeHandler, stackMapFrameHandler); } @Override @@ -8200,26 +6809,26 @@ protected static class WithoutExitAdvice extends AdviceVisitor { * @param instrumentedType A description of the instrumented type. * @param instrumentedMethod A description of the instrumented method. * @param methodEnter The dispatcher to be used for method entry. - * @param classFileVersion The instrumented type's class file version. * @param writerFlags The ASM writer flags that were set. * @param readerFlags The ASM reader flags that were set. */ protected WithoutExitAdvice(MethodVisitor methodVisitor, + Implementation.Context implementationContext, TypeDescription instrumentedType, MethodDescription instrumentedMethod, Dispatcher.Resolved.ForMethodEnter methodEnter, - ClassFileVersion classFileVersion, int writerFlags, int readerFlags) { super(methodVisitor, methodVisitor, + implementationContext, instrumentedType, instrumentedMethod, methodEnter, Dispatcher.Inactive.INSTANCE, Collections.emptyList(), - classFileVersion, - writerFlags, readerFlags); + writerFlags, + readerFlags); } @Override @@ -8295,27 +6904,26 @@ protected abstract static class WithExitAdvice extends AdviceVisitor { * @param methodEnter The dispatcher to be used for method entry. * @param methodExit The dispatcher to be used for method exit. * @param yieldedTypes The types that are expected to be added after the instrumented method returns. - * @param classFileVersion The instrumented type's class file version. * @param writerFlags The ASM writer flags that were set. * @param readerFlags The ASM reader flags that were set. */ protected WithExitAdvice(MethodVisitor methodVisitor, + Implementation.Context implementationContext, TypeDescription instrumentedType, MethodDescription instrumentedMethod, Dispatcher.Resolved.ForMethodEnter methodEnter, Dispatcher.Resolved.ForMethodExit methodExit, List yieldedTypes, - ClassFileVersion classFileVersion, int writerFlags, int readerFlags) { super(methodVisitor, new StackAwareMethodVisitor(methodVisitor, instrumentedMethod), + implementationContext, instrumentedType, instrumentedMethod, methodEnter, methodExit, yieldedTypes, - classFileVersion, writerFlags, readerFlags); returnHandler = new Label(); doesReturn = false; @@ -8415,19 +7023,19 @@ protected static class WithoutExceptionHandling extends WithExitAdvice { * @param instrumentedMethod A description of the instrumented method. * @param methodEnter The dispatcher to be used for method entry. * @param methodExit The dispatcher to be used for method exit. - * @param classFileVersion The instrumented type's class file version. * @param writerFlags The ASM writer flags that were set. * @param readerFlags The ASM reader flags that were set. */ protected WithoutExceptionHandling(MethodVisitor methodVisitor, + Implementation.Context implementationContext, TypeDescription instrumentedType, MethodDescription instrumentedMethod, Dispatcher.Resolved.ForMethodEnter methodEnter, Dispatcher.Resolved.ForMethodExit methodExit, - ClassFileVersion classFileVersion, int writerFlags, int readerFlags) { super(methodVisitor, + implementationContext, instrumentedType, instrumentedMethod, methodEnter, @@ -8435,7 +7043,6 @@ protected WithoutExceptionHandling(MethodVisitor methodVisitor, instrumentedMethod.getReturnType().represents(void.class) ? Collections.emptyList() : Collections.singletonList(instrumentedMethod.getReturnType().asErasure()), - classFileVersion, writerFlags, readerFlags); } @@ -8499,21 +7106,21 @@ protected static class WithExceptionHandling extends WithExitAdvice { * @param instrumentedMethod A description of the instrumented method. * @param methodEnter The dispatcher to be used for method entry. * @param methodExit The dispatcher to be used for method exit. - * @param classFileVersion The instrumented type's class file version. * @param writerFlags The ASM writer flags that were set. * @param readerFlags The ASM reader flags that were set. * @param triggeringThrowable The type of the handled throwable type for which this advice is invoked. */ protected WithExceptionHandling(MethodVisitor methodVisitor, + Implementation.Context implementationContext, TypeDescription instrumentedType, MethodDescription instrumentedMethod, Dispatcher.Resolved.ForMethodEnter methodEnter, Dispatcher.Resolved.ForMethodExit methodExit, - ClassFileVersion classFileVersion, int writerFlags, int readerFlags, TypeDescription triggeringThrowable) { super(methodVisitor, + implementationContext, instrumentedType, instrumentedMethod, methodEnter, @@ -8521,7 +7128,6 @@ protected WithExceptionHandling(MethodVisitor methodVisitor, instrumentedMethod.getReturnType().represents(void.class) ? Collections.singletonList(TypeDescription.THROWABLE) : Arrays.asList(instrumentedMethod.getReturnType().asErasure(), TypeDescription.THROWABLE), - classFileVersion, writerFlags, readerFlags); this.triggeringThrowable = triggeringThrowable; @@ -8645,7 +7251,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me methodVisitor = advice.doWrap(implementationTarget.getInstrumentedType(), instrumentedMethod, emulatingMethodVisitor, - implementationContext.getClassFileVersion(), + implementationContext, AsmVisitorWrapper.NO_FLAGS, AsmVisitorWrapper.NO_FLAGS); return emulatingMethodVisitor.resolve(methodVisitor, implementationContext, instrumentedMethod); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FieldAccessor.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FieldAccessor.java index 2beb1d74592..1af943b7f49 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FieldAccessor.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FieldAccessor.java @@ -125,7 +125,7 @@ protected StackManipulation setter(FieldDescription fieldDescription, ParameterD } return access(fieldDescription, parameterDescription.getDeclaringMethod(), - new StackManipulation.Compound(MethodVariableAccess.of(fieldDescription.getType().asErasure()).loadOffset(parameterDescription.getOffset()), + new StackManipulation.Compound(MethodVariableAccess.of(fieldDescription.getType().asErasure()).loadFrom(parameterDescription.getOffset()), assigner.assign(parameterDescription.getType(), fieldDescription.getType(), typing), FieldAccess.forField(fieldDescription).putter())); } @@ -146,7 +146,7 @@ private StackManipulation access(FieldDescription fieldDescription, MethodDescri } return new StackManipulation.Compound(fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), fieldAccess); + : MethodVariableAccess.REFERENCE.loadFrom(0), fieldAccess); } @Override diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FixedValue.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FixedValue.java index 6b6e54727cc..e45358a1023 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FixedValue.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FixedValue.java @@ -459,7 +459,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me throw new IllegalStateException("Cannot return 'this' from " + instrumentedMethod); } return new ByteCodeAppender.Simple( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), MethodReturn.REFERENCE ).apply(methodVisitor, implementationContext, instrumentedMethod); } @@ -525,7 +525,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me } ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index); StackManipulation stackManipulation = new StackManipulation.Compound( - MethodVariableAccess.of(parameterDescription.getType()).loadOffset(parameterDescription.getOffset()), + MethodVariableAccess.of(parameterDescription.getType()).loadFrom(parameterDescription.getOffset()), assigner.assign(parameterDescription.getType(), instrumentedMethod.getReturnType(), typing), MethodReturn.of(instrumentedMethod.getReturnType()) ); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Forwarding.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Forwarding.java index 22fbcd236bf..d0ec395c59b 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Forwarding.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Forwarding.java @@ -394,7 +394,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me StackManipulation.Size stackSize = new StackManipulation.Compound( fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(fieldDescription).getter(), MethodVariableAccess.allArgumentsOf(instrumentedMethod), MethodInvocation.invoke(instrumentedMethod).virtual(fieldDescription.getType().asErasure()), 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 337069eabd3..b5f97ca63fd 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 @@ -1519,7 +1519,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me StackManipulation.Size stackSize = new StackManipulation.Compound( fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(fieldDescription).getter(), MethodReturn.of(fieldDescription.getType().asErasure()) ).apply(methodVisitor, implementationContext); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvocationHandlerAdapter.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvocationHandlerAdapter.java index 357e77f112b..2e70a9b01c7 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvocationHandlerAdapter.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvocationHandlerAdapter.java @@ -140,7 +140,7 @@ private List argumentValuesOf(MethodDescription instrumentedM int currentIndex = 1; for (TypeDescription.Generic parameterType : parameterTypes) { instruction.add(new StackManipulation.Compound( - MethodVariableAccess.of(parameterType).loadOffset(currentIndex), + MethodVariableAccess.of(parameterType).loadFrom(currentIndex), assigner.assign(parameterType, TypeDescription.Generic.OBJECT, Assigner.Typing.STATIC))); currentIndex += parameterType.getStackSize().getSize(); } @@ -177,7 +177,7 @@ protected ByteCodeAppender.Size apply(MethodVisitor methodVisitor, StackManipulation.Size stackSize = new StackManipulation.Compound( preparingManipulation, FieldAccess.forField(fieldDescription).getter(), - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), cacheMethods ? MethodConstant.forMethod(instrumentedMethod.asDefined()).cached() : MethodConstant.forMethod(instrumentedMethod.asDefined()), @@ -465,7 +465,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me instrumentedMethod, fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), fieldDescription); } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvokeDynamic.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvokeDynamic.java index 5a539182eba..70eb12985a8 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvokeDynamic.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/InvokeDynamic.java @@ -1511,7 +1511,7 @@ public Resolved resolve(TypeDescription instrumentedType, MethodDescription inst } else if (!instrumentedType.isAssignableTo(typeDescription)) { throw new IllegalStateException(instrumentedType + " is not assignable to " + instrumentedType); } - return new Resolved.Simple(MethodVariableAccess.REFERENCE.loadOffset(0), typeDescription); + return new Resolved.Simple(MethodVariableAccess.REFERENCE.loadFrom(0), typeDescription); } @Override @@ -1661,7 +1661,7 @@ public Resolved resolve(TypeDescription instrumentedType, MethodDescription inst } return doResolve(new StackManipulation.Compound(resolution.getField().isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), FieldAccess.forField(resolution.getField()).getter()), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(resolution.getField()).getter()), resolution.getField().getType(), assigner, typing); @@ -1788,7 +1788,7 @@ public Resolved resolve(TypeDescription instrumentedType, MethodDescription inst if (index >= parameters.size()) { throw new IllegalStateException("No parameter " + index + " for " + instrumentedMethod); } - return doResolve(MethodVariableAccess.of(parameters.get(index).getType().asErasure()).loadOffset(parameters.get(index).getOffset()), + return doResolve(MethodVariableAccess.of(parameters.get(index).getType().asErasure()).loadFrom(parameters.get(index).getOffset()), parameters.get(index).getType(), assigner, typing); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodCall.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodCall.java index b36edbdfcdc..75d34b9f262 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodCall.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodCall.java @@ -745,7 +745,7 @@ public StackManipulation resolve(MethodDescription invokedMethod, MethodDescript return new StackManipulation.Compound( invokedMethod.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), invokedMethod.isConstructor() ? Duplication.SINGLE : StackManipulation.Trivial.INSTANCE @@ -898,7 +898,7 @@ public StackManipulation resolve(MethodDescription invokedMethod, MethodDescript return new StackManipulation.Compound( invokedMethod.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(fieldName)).getOnly()).getter()); } @@ -966,7 +966,7 @@ public StackManipulation resolve(MethodDescription invokedMethod, if (!stackManipulation.isValid()) { throw new IllegalStateException("Cannot invoke " + invokedMethod + " on " + parameterDescription.getType()); } - return new StackManipulation.Compound(MethodVariableAccess.of(parameterDescription.getType()).loadOffset(parameterDescription.getOffset()), stackManipulation); + return new StackManipulation.Compound(MethodVariableAccess.of(parameterDescription.getType()).loadFrom(parameterDescription.getOffset()), stackManipulation); } @Override @@ -1088,7 +1088,7 @@ protected ForThisReference(TypeDescription instrumentedType) { @Override public StackManipulation resolve(ParameterDescription target, Assigner assigner, Assigner.Typing typing) { StackManipulation stackManipulation = new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), assigner.assign(instrumentedType.asGenericType(), target.getType(), typing)); if (!stackManipulation.isValid()) { throw new IllegalStateException("Cannot assign " + instrumentedType + " to " + target); @@ -1253,7 +1253,7 @@ protected ForMethodParameter(int index, MethodDescription instrumentedMethod) { public StackManipulation resolve(ParameterDescription target, Assigner assigner, Assigner.Typing typing) { ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index); StackManipulation stackManipulation = new StackManipulation.Compound( - MethodVariableAccess.of(parameterDescription.getType().asErasure()).loadOffset(parameterDescription.getOffset()), + MethodVariableAccess.of(parameterDescription.getType().asErasure()).loadFrom(parameterDescription.getOffset()), assigner.assign(parameterDescription.getType(), target.getType(), typing)); if (!stackManipulation.isValid()) { throw new IllegalStateException("Cannot assign " + parameterDescription + " to " + target + " for " + instrumentedMethod); @@ -1560,7 +1560,7 @@ public StackManipulation resolve(ParameterDescription target, Assigner assigner, StackManipulation stackManipulation = new StackManipulation.Compound( fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(fieldDescription).getter(), assigner.assign(fieldDescription.getType(), target.getType(), typing) ); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodDelegation.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodDelegation.java index c6e1d50902d..16401f22d84 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodDelegation.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/MethodDelegation.java @@ -975,7 +975,7 @@ public Resolution resolve(TypeDescription instrumentedType) { return new Resolution(methodGraphCompiler.compile(resolution.getField().getType(), instrumentedType).listNodes().asMethodList().filter(matcher), new StackManipulation.Compound(resolution.getField().isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), FieldAccess.forField(resolution.getField()).getter()), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(resolution.getField()).getter()), new MethodDelegationBinder.MethodInvoker.Virtual(resolution.getField().getType().asErasure()), resolution.getField().isStatic()); } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/MethodCallProxy.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/MethodCallProxy.java index 12b06350091..74869723751 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/MethodCallProxy.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/MethodCallProxy.java @@ -297,7 +297,7 @@ private Appender(TypeDescription instrumentedType) { @Override public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { - StackManipulation thisReference = MethodVariableAccess.REFERENCE.loadOffset(0); + StackManipulation thisReference = MethodVariableAccess.REFERENCE.loadFrom(0); FieldList fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; @@ -305,7 +305,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me fieldLoading[index] = new StackManipulation.Compound( thisReference, MethodVariableAccess.of(fieldDescription.getType().asErasure()) - .loadOffset(instrumentedMethod.getParameters().get(index).getOffset()), + .loadFrom(instrumentedMethod.getParameters().get(index).getOffset()), FieldAccess.forField(fieldDescription).putter() ); index++; @@ -416,7 +416,7 @@ private Appender(TypeDescription instrumentedType) { public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { - StackManipulation thisReference = MethodVariableAccess.of(instrumentedType).loadOffset(0); + StackManipulation thisReference = MethodVariableAccess.of(instrumentedType).loadFrom(0); FieldList fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/TypeProxy.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/TypeProxy.java index e645acd3299..6e279847642 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/TypeProxy.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/auxiliary/TypeProxy.java @@ -482,7 +482,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa new Compound(constructorValue), MethodInvocation.invoke(proxyType.getDeclaredMethods().filter(isConstructor().and(takesArguments(constructorParameters))).getOnly()), Duplication.SINGLE, - MethodVariableAccess.of(implementationTarget.getInstrumentedType()).loadOffset(0), + MethodVariableAccess.of(implementationTarget.getInstrumentedType()).loadFrom(0), FieldAccess.forField(proxyType.getDeclaredFields().filter((named(INSTANCE_FIELD))).getOnly()).putter() ).apply(methodVisitor, implementationContext); } @@ -584,7 +584,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa MethodInvocation.invoke(proxyType.getDeclaredMethods() .filter(named(REFLECTION_METHOD).and(takesArguments(0))).getOnly()), Duplication.SINGLE, - MethodVariableAccess.of(implementationTarget.getInstrumentedType()).loadOffset(0), + MethodVariableAccess.of(implementationTarget.getInstrumentedType()).loadFrom(0), FieldAccess.forField(proxyType.getDeclaredFields() .filter((named(INSTANCE_FIELD))).getOnly()).putter() ).apply(methodVisitor, implementationContext); @@ -675,7 +675,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa Duplication.SINGLE, MethodInvocation.invoke(proxyType.getDeclaredMethods().filter(isConstructor()).getOnly()), Duplication.SINGLE, - MethodVariableAccess.of(implementationTarget.getInstrumentedType()).loadOffset(0), + MethodVariableAccess.of(implementationTarget.getInstrumentedType()).loadFrom(0), FieldAccess.forField(proxyType.getDeclaredFields() .filter((named(INSTANCE_FIELD))).getOnly()).putter() ).apply(methodVisitor, implementationContext); @@ -863,7 +863,7 @@ public boolean isValid() { public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { MethodDescription.InDefinedShape proxyMethod = methodAccessorFactory.registerAccessorFor(specialMethodInvocation); return new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), fieldLoadingInstruction, MethodVariableAccess.allArgumentsOf(instrumentedMethod).asBridgeOf(proxyMethod), MethodInvocation.invoke(proxyMethod), diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/AllArguments.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/AllArguments.java index 59121a88735..38c54f1eaff 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/AllArguments.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/AllArguments.java @@ -142,7 +142,7 @@ public MethodDelegationBinder.ParameterBinding bind(AnnotationDescription.Loa ? CompoundList.of(implementationTarget.getInstrumentedType().asGenericType(), source.getParameters().asTypeList()) : source.getParameters().asTypeList()) { StackManipulation stackManipulation = new StackManipulation.Compound( - MethodVariableAccess.of(sourceParameter).loadOffset(offset), + MethodVariableAccess.of(sourceParameter).loadFrom(offset), assigner.assign(sourceParameter, arrayFactory.getComponentType(), RuntimeType.Verifier.check(target))); if (stackManipulation.isValid()) { stackManipulations.add(stackManipulation); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Argument.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Argument.java index 7cb18bb0d9b..a833183350d 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Argument.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Argument.java @@ -80,7 +80,7 @@ protected MethodDelegationBinder.ParameterBinding makeBinding(TypeDescription int parameterOffset) { return MethodDelegationBinder.ParameterBinding.Unique.of( new StackManipulation.Compound( - MethodVariableAccess.of(source).loadOffset(parameterOffset), + MethodVariableAccess.of(source).loadFrom(parameterOffset), assigner.assign(source, target, typing)), new ArgumentTypeResolver.ParameterIndexToken(sourceParameterIndex) ); @@ -99,7 +99,7 @@ protected MethodDelegationBinder.ParameterBinding makeBinding(TypeDescription Assigner.Typing typing, int parameterOffset) { return new MethodDelegationBinder.ParameterBinding.Anonymous( - new StackManipulation.Compound(MethodVariableAccess.of(source).loadOffset(parameterOffset), assigner.assign(source, target, typing)) + new StackManipulation.Compound(MethodVariableAccess.of(source).loadFrom(parameterOffset), assigner.assign(source, target, typing)) ); } }; diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldProxy.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldProxy.java index 14b7dcd6302..0c96edcab71 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldProxy.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldProxy.java @@ -754,7 +754,7 @@ public InstrumentedType prepare(InstrumentedType instrumentedType) { @Override public ByteCodeAppender appender(Target implementationTarget) { - return new ByteCodeAppender.Simple(MethodVariableAccess.REFERENCE.loadOffset(0), + return new ByteCodeAppender.Simple(MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(objectTypeDefaultConstructor), MethodReturn.VOID); } @@ -843,7 +843,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { StackManipulation.Size stackSize = new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(StaticFieldConstructor.INSTANCE.objectTypeDefaultConstructor), MethodVariableAccess.allArgumentsOf(instrumentedMethod.asDefined()).prependThisReference(), FieldAccess.forField(fieldDescription).putter(), @@ -972,7 +972,7 @@ public Size apply(MethodVisitor methodVisitor, fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE : new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(typeDescription.getDeclaredFields() .filter((named(AccessorProxy.FIELD_NAME))).getOnly()).getter()), MethodInvocation.invoke(getterMethod), @@ -1115,10 +1115,10 @@ public Size apply(MethodVisitor methodVisitor, fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE : new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(typeDescription.getDeclaredFields() .filter((named(AccessorProxy.FIELD_NAME))).getOnly()).getter()), - MethodVariableAccess.of(parameterType).loadOffset(1), + MethodVariableAccess.of(parameterType).loadFrom(1), assigner.assign(parameterType, setterMethod.getParameters().get(0).getType(), Assigner.Typing.DYNAMIC), MethodInvocation.invoke(setterMethod), MethodReturn.VOID @@ -1242,7 +1242,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa Duplication.SINGLE, fieldDescription.isStatic() ? Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(auxiliaryType.getDeclaredMethods().filter(isConstructor()).getOnly()) ).apply(methodVisitor, implementationContext); } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldValue.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldValue.java index 98646447cc6..f01042f612b 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldValue.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/FieldValue.java @@ -136,7 +136,7 @@ protected MethodDelegationBinder.ParameterBinding bind(FieldDescription field StackManipulation stackManipulation = new StackManipulation.Compound( fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(fieldDescription).getter(), assigner.assign(fieldDescription.getType(), target.getType(), RuntimeType.Verifier.check(target)) ); diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Morph.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Morph.java index d1fc96c0657..d1de0c14b12 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Morph.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Morph.java @@ -409,7 +409,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa Duplication.SINGLE, specialMethodInvocation.getMethodDescription().isStatic() ? Trivial.INSTANCE - : MethodVariableAccess.REFERENCE.loadOffset(0), + : MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(forwardingType.getDeclaredMethods().filter(isConstructor()).getOnly()) ).apply(methodVisitor, implementationContext); } @@ -478,7 +478,7 @@ public InstrumentedType prepare(InstrumentedType instrumentedType) { @Override public ByteCodeAppender appender(Target implementationTarget) { - return new ByteCodeAppender.Simple(MethodVariableAccess.REFERENCE.loadOffset(0), + return new ByteCodeAppender.Simple(MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(objectTypeDefaultConstructor), MethodReturn.VOID); } @@ -565,7 +565,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { StackManipulation.Size stackSize = new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), MethodInvocation.invoke(StaticFieldConstructor.INSTANCE.objectTypeDefaultConstructor), MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(), FieldAccess.forField(fieldDescription).putter(), @@ -673,7 +673,7 @@ protected Appender(Target implementationTarget) { public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { - StackManipulation arrayReference = MethodVariableAccess.REFERENCE.loadOffset(1); + StackManipulation arrayReference = MethodVariableAccess.REFERENCE.loadFrom(1); StackManipulation[] parameterLoading = new StackManipulation[accessorMethod.getParameters().size()]; int index = 0; for (TypeDescription.Generic parameterType : accessorMethod.getParameters().asTypeList()) { @@ -687,7 +687,7 @@ public Size apply(MethodVisitor methodVisitor, accessorMethod.isStatic() ? Trivial.INSTANCE : new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadFrom(0), FieldAccess.forField(typeDescription.getDeclaredFields() .filter((named(RedirectionProxy.FIELD_NAME))) .getOnly()).getter()), diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Pipe.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Pipe.java index 07099b5c12b..fcdf472f034 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Pipe.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Pipe.java @@ -415,7 +415,7 @@ private Appender(TypeDescription instrumentedType) { @Override public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { - StackManipulation thisReference = MethodVariableAccess.REFERENCE.loadOffset(0); + StackManipulation thisReference = MethodVariableAccess.REFERENCE.loadFrom(0); FieldList fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; @@ -423,7 +423,7 @@ public Size apply(MethodVisitor methodVisitor, Context implementationContext, Me fieldLoading[index] = new StackManipulation.Compound( thisReference, MethodVariableAccess.of(fieldDescription.getType().asErasure()) - .loadOffset(instrumentedMethod.getParameters().get(index).getOffset()), + .loadFrom(instrumentedMethod.getParameters().get(index).getOffset()), FieldAccess.forField(fieldDescription).putter() ); index++; @@ -537,7 +537,7 @@ private Appender(TypeDescription instrumentedType) { public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { - StackManipulation thisReference = MethodVariableAccess.of(instrumentedType).loadOffset(0); + StackManipulation thisReference = MethodVariableAccess.of(instrumentedType).loadFrom(0); FieldList fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; @@ -545,7 +545,7 @@ public Size apply(MethodVisitor methodVisitor, fieldLoading[index++] = new StackManipulation.Compound(thisReference, FieldAccess.forField(fieldDescription).getter()); } StackManipulation.Size stackSize = new StackManipulation.Compound( - MethodVariableAccess.REFERENCE.loadOffset(1), + MethodVariableAccess.REFERENCE.loadFrom(1), assigner.assign(TypeDescription.Generic.OBJECT, redirectedMethod.getDeclaringType().asGenericType(), Assigner.Typing.DYNAMIC), new StackManipulation.Compound(fieldLoading), MethodInvocation.invoke(redirectedMethod), diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/This.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/This.java index 6425453b339..dbee215f1eb 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/This.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/This.java @@ -71,7 +71,7 @@ public MethodDelegationBinder.ParameterBinding bind(AnnotationDescription.Loa } return new MethodDelegationBinder.ParameterBinding.Anonymous(source.isStatic() ? NullConstant.INSTANCE - : new StackManipulation.Compound(MethodVariableAccess.REFERENCE.loadOffset(THIS_REFERENCE_INDEX), + : new StackManipulation.Compound(MethodVariableAccess.REFERENCE.loadFrom(THIS_REFERENCE_INDEX), assigner.assign(implementationTarget.getInstrumentedType().asGenericType(), target.getType(), RuntimeType.Verifier.check(target)))); } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Addition.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Addition.java new file mode 100644 index 00000000000..d06d55d51c1 --- /dev/null +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Addition.java @@ -0,0 +1,36 @@ +package net.bytebuddy.implementation.bytecode; + +import net.bytebuddy.implementation.Implementation; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public enum Addition implements StackManipulation { + + INTEGER(Opcodes.IADD, StackSize.SINGLE), + + LONG(Opcodes.LADD, StackSize.DOUBLE), + + FLOAT(Opcodes.FADD, StackSize.SINGLE), + + DOUBLE(Opcodes.DADD, StackSize.DOUBLE); + + private final int opcode; + + private final StackSize stackSize; + + Addition(int opcode, StackSize stackSize) { + this.opcode = opcode; + this.stackSize = stackSize; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { + methodVisitor.visitInsn(opcode); + return stackSize.toDecreasingSize(); + } +} diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Duplication.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Duplication.java index b18663077ef..2bbf7eee6ea 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Duplication.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/Duplication.java @@ -1,6 +1,6 @@ package net.bytebuddy.implementation.bytecode; -import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.implementation.Implementation; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -16,24 +16,53 @@ public enum Duplication implements StackManipulation { ZERO(StackSize.ZERO, Opcodes.NOP) { @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { - return new Size(0, 0); + return size; + } + + @Override + public StackManipulation flipOver(TypeDefinition typeDefinition) { + throw new IllegalStateException("Cannot flip zero duplication"); } }, /** * A duplication of a single-sized stack values. */ - SINGLE(StackSize.SINGLE, Opcodes.DUP), + SINGLE(StackSize.SINGLE, Opcodes.DUP) { + @Override + public StackManipulation flipOver(TypeDefinition typeDefinition) { + switch (typeDefinition.getStackSize()) { + case SINGLE: + return FlipDuplication.SINGLE_SINGLE; + case DOUBLE: + return FlipDuplication.SINGLE_DOUBLE; + default: + throw new IllegalArgumentException(); + } + } + }, /** * A duplication of a double-sized stack value. */ - DOUBLE(StackSize.DOUBLE, Opcodes.DUP2); + DOUBLE(StackSize.DOUBLE, Opcodes.DUP2) { + @Override + public StackManipulation flipOver(TypeDefinition typeDefinition) { + switch (typeDefinition.getStackSize()) { + case SINGLE: + return FlipDuplication.DOUBLE_SINGLE; + case DOUBLE: + return FlipDuplication.DOUBLE_DOUBLE; + default: + throw new IllegalArgumentException(); + } + } + }; /** * The size representing the impact of applying the duplication onto the operand stack. */ - private final Size size; + protected final Size size; /** * The opcode that represents the manipulation. @@ -57,8 +86,8 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa * @param typeDescription The type to be duplicated. * @return A stack manipulation that duplicates the given type. */ - public static StackManipulation duplicate(TypeDescription typeDescription) { - switch (typeDescription.getStackSize()) { + public static Duplication duplicate(TypeDefinition typeDefinition) { + switch (typeDefinition.getStackSize()) { case SINGLE: return SINGLE; case DOUBLE: @@ -66,10 +95,12 @@ public static StackManipulation duplicate(TypeDescription typeDescription) { case ZERO: return ZERO; default: - throw new AssertionError(); + throw new AssertionError("Unexpected type: " + typeDefinition); } } + public abstract StackManipulation flipOver(TypeDefinition typeDefinition); + @Override public boolean isValid() { return true; @@ -85,4 +116,35 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa public String toString() { return "Duplication." + name(); } + + protected enum FlipDuplication implements StackManipulation { + + SINGLE_SINGLE(Opcodes.DUP_X1, StackSize.SINGLE), + + SINGLE_DOUBLE(Opcodes.DUP_X2, StackSize.SINGLE), + + DOUBLE_SINGLE(Opcodes.DUP2_X1, StackSize.DOUBLE), + + DOUBLE_DOUBLE(Opcodes.DUP2_X2, StackSize.DOUBLE); + + private final int opcode; + + private final StackSize stackSize; + + FlipDuplication(int opcode, StackSize stackSize) { + this.opcode = opcode; + this.stackSize = stackSize; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { + methodVisitor.visitInsn(opcode); + return stackSize.toIncreasingSize(); + } + } } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccess.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccess.java index 48d43f498f7..e44fe360633 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccess.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccess.java @@ -22,33 +22,35 @@ public enum MethodVariableAccess { /** * The accessor handler for a JVM-integer. */ - INTEGER(Opcodes.ILOAD, StackSize.SINGLE), + INTEGER(Opcodes.ILOAD, Opcodes.ISTORE, StackSize.SINGLE), /** * The accessor handler for a {@code long}. */ - LONG(Opcodes.LLOAD, StackSize.DOUBLE), + LONG(Opcodes.LLOAD, Opcodes.LSTORE, StackSize.DOUBLE), /** * The accessor handler for a {@code float}. */ - FLOAT(Opcodes.FLOAD, StackSize.SINGLE), + FLOAT(Opcodes.FLOAD, Opcodes.FSTORE, StackSize.SINGLE), /** * The accessor handler for a {@code double}. */ - DOUBLE(Opcodes.DLOAD, StackSize.DOUBLE), + DOUBLE(Opcodes.DLOAD, Opcodes.DSTORE, StackSize.DOUBLE), /** * The accessor handler for a reference type. */ - REFERENCE(Opcodes.ALOAD, StackSize.SINGLE); + REFERENCE(Opcodes.ALOAD, Opcodes.ASTORE, StackSize.SINGLE); /** * The opcode for loading this variable. */ private final int loadOpcode; + private final int storeOpcode; + /** * The size impact of this stack manipulation. */ @@ -56,13 +58,14 @@ public enum MethodVariableAccess { /** * Creates a new method variable access for a given JVM type. - * - * @param loadOpcode The opcode for loading this variable. + * @param loadOpcode The opcode for loading this variable. * @param stackSize The size of the JVM type. + * @param storeOpcode */ - MethodVariableAccess(int loadOpcode, StackSize stackSize) { + MethodVariableAccess(int loadOpcode, int storeOpcode, StackSize stackSize) { this.loadOpcode = loadOpcode; this.size = stackSize.toIncreasingSize(); + this.storeOpcode = storeOpcode; } /** @@ -108,8 +111,20 @@ public static MethodLoading allArgumentsOf(MethodDescription methodDescription) * count two slots. * @return A stack manipulation representing the method retrieval. */ - public StackManipulation loadOffset(int variableOffset) { - return new OffsetLoading(variableOffset); + public StackManipulation loadFrom(int offset) { + return new OffsetLoading(offset); + } + + public StackManipulation storeAt(int offset) { + return new OffsetWriting(offset); + } + + + public StackManipulation increment(int offset, int value) { + if (this != INTEGER) { + throw new IllegalArgumentException("Cannot increment: " + this); + } + return new OffsetIncrementing(offset, value); } @Override @@ -153,7 +168,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa List stackManipulations = new ArrayList(); for (ParameterDescription parameterDescription : methodDescription.getParameters()) { TypeDescription parameterType = parameterDescription.getType().asErasure(); - stackManipulations.add(of(parameterType).loadOffset(parameterDescription.getOffset())); + stackManipulations.add(of(parameterType).loadFrom(parameterDescription.getOffset())); stackManipulations.add(typeCastingHandler.ofIndex(parameterType, parameterDescription.getIndex())); } return new Compound(stackManipulations).apply(methodVisitor, implementationContext); @@ -168,7 +183,7 @@ public Size apply(MethodVisitor methodVisitor, Implementation.Context implementa public StackManipulation prependThisReference() { return methodDescription.isStatic() ? this - : new Compound(MethodVariableAccess.REFERENCE.loadOffset(0), this); + : new Compound(MethodVariableAccess.REFERENCE.loadFrom(0), this); } /** @@ -349,5 +364,92 @@ public String toString() { " ,offset=" + offset + '}'; } } + protected class OffsetWriting implements StackManipulation { + + /** + * The index of the local variable array from which the variable should be loaded. + */ + private final int offset; + + /** + * Creates a new argument loading stack manipulation. + * + * @param offset The index of the local variable array from which the variable should be loaded. + */ + protected OffsetWriting(int offset) { + this.offset = offset; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { + methodVisitor.visitVarInsn(storeOpcode, offset); + return size; + } + + /** + * Returns the outer instance. + * + * @return The outer instance. + */ + private MethodVariableAccess getMethodVariableAccess() { + return MethodVariableAccess.this; + } + + @Override + public boolean equals(Object other) { + return this == other || !(other == null || getClass() != other.getClass()) + && MethodVariableAccess.this == ((OffsetWriting) other).getMethodVariableAccess() + && offset == ((OffsetWriting) other).offset; + } + + @Override + public int hashCode() { + return MethodVariableAccess.this.hashCode() + 31 * offset; + } + + @Override + public String toString() { + return "MethodVariableAccess.OffsetWriting{" + + "methodVariableAccess=" + MethodVariableAccess.this + + " ,offset=" + offset + '}'; + } + } + + protected static class OffsetIncrementing implements StackManipulation { + + /** + * The index of the local variable array from which the variable should be loaded. + */ + private final int offset; + + private final int value; + + /** + * Creates a new argument loading stack manipulation. + * + * @param offset The index of the local variable array from which the variable should be loaded. + * @param value + */ + protected OffsetIncrementing(int offset, int value) { + this.offset = offset; + this.value = value; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { + methodVisitor.visitIincInsn(offset, value); + return new Size(0, 0); + } + } } diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccessTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccessTest.java index 9bbe9b51345..6e3a6d0b502 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccessTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/bytecode/member/MethodVariableAccessTest.java @@ -69,7 +69,7 @@ public void setUp() throws Exception { @Test public void testLoading() throws Exception { - StackManipulation stackManipulation = MethodVariableAccess.of(typeDescription).loadOffset(4); + StackManipulation stackManipulation = MethodVariableAccess.of(typeDescription).loadFrom(4); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(this.size));