Skip to content

Commit

Permalink
Start work with size handler refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphw committed May 15, 2018
1 parent f3ec858 commit 186c96d
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 76 deletions.
132 changes: 57 additions & 75 deletions byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java
Expand Up @@ -4124,10 +4124,9 @@ interface ForInstrumentedMethod extends MethodSizeHandler {
* Binds the method size handler for the exit advice. * Binds the method size handler for the exit advice.
* *
* @param adviceMethod The method representing the exit advice. * @param adviceMethod The method representing the exit advice.
* @param skipThrowable {@code true} if the exit advice is not invoked on an exception.
* @return A method size handler for the exit advice. * @return A method size handler for the exit advice.
*/ */
ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod, boolean skipThrowable); ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod);


/** /**
* Computes a compound stack size for the advice and the translated instrumented method. * Computes a compound stack size for the advice and the translated instrumented method.
Expand All @@ -4151,6 +4150,13 @@ interface ForInstrumentedMethod extends MethodSizeHandler {
*/ */
interface ForAdvice extends MethodSizeHandler { interface ForAdvice extends MethodSizeHandler {


/**
* Records a minimum padding additionally to the computed stack size that is required for implementing this advice method.
*
* @param padding The minimum required padding.
*/
void requireStackPadding(int padding);

/** /**
* Records the maximum values for stack size and local variable array which are required by the advice method * Records the maximum values for stack size and local variable array which are required by the advice method
* for its individual execution without translation. * for its individual execution without translation.
Expand All @@ -4159,13 +4165,6 @@ interface ForAdvice extends MethodSizeHandler {
* @param localVariableLength The minimum required length of the local variable array. * @param localVariableLength The minimum required length of the local variable array.
*/ */
void recordMaxima(int stackSize, int localVariableLength); void recordMaxima(int stackSize, int localVariableLength);

/**
* Records a minimum padding additionally to the computed stack size that is required for implementing this advice method.
*
* @param padding The minimum required padding.
*/
void recordPadding(int padding);
} }


/** /**
Expand All @@ -4184,7 +4183,7 @@ public ForAdvice bindEnter(MethodDescription.InDefinedShape adviceMethod) {
} }


@Override @Override
public ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod, boolean skipThrowable) { public ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod) {
return this; return this;
} }


Expand All @@ -4209,12 +4208,12 @@ public void requireStackSize(int stackSize) {
} }


@Override @Override
public void recordMaxima(int stackSize, int localVariableLength) { public void requireStackPadding(int padding) {
/* do nothing */ /* do nothing */
} }


@Override @Override
public void recordPadding(int padding) { public void recordMaxima(int stackSize, int localVariableLength) {
/* do nothing */ /* do nothing */
} }
} }
Expand Down Expand Up @@ -4270,7 +4269,6 @@ protected Default(MethodDescription instrumentedMethod,
this.initialTypes = initialTypes; this.initialTypes = initialTypes;
this.enterTypes = enterTypes; this.enterTypes = enterTypes;
this.exitTypes = exitTypes; this.exitTypes = exitTypes;
localVariableLength = instrumentedMethod.getStackSize() + StackSize.of(initialTypes);
} }


/** /**
Expand Down Expand Up @@ -4301,20 +4299,7 @@ protected static MethodSizeHandler.ForInstrumentedMethod of(MethodDescription in


@Override @Override
public MethodSizeHandler.ForAdvice bindEnter(MethodDescription.InDefinedShape adviceMethod) { public MethodSizeHandler.ForAdvice bindEnter(MethodDescription.InDefinedShape adviceMethod) {
stackSize = Math.max(stackSize, adviceMethod.getReturnType().getStackSize().getSize()); return new ForAdvice(adviceMethod, instrumentedMethod.getStackSize() + StackSize.of(initialTypes));
localVariableLength = Math.max(localVariableLength, instrumentedMethod.getStackSize()
+ StackSize.of(initialTypes)
+ adviceMethod.getReturnType().getStackSize().getSize());
return new ForAdvice(adviceMethod, Collections.<TypeDescription>emptyList(), enterTypes);
}

@Override
public MethodSizeHandler.ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod, boolean skipThrowable) {
stackSize = Math.max(stackSize, adviceMethod.getReturnType().getStackSize().maximum(skipThrowable
? StackSize.ZERO
: StackSize.SINGLE).getSize());
stackSize = Math.max(stackSize, adviceMethod.getReturnType().getStackSize().getSize());
return new ForAdvice(adviceMethod, CompoundList.of(initialTypes, enterTypes, exitTypes), Collections.<TypeDescription>emptyList());
} }


@Override @Override
Expand All @@ -4325,14 +4310,14 @@ public int compoundStackSize(int stackSize) {
@Override @Override
public int compoundLocalVariableLength(int localVariableLength) { public int compoundLocalVariableLength(int localVariableLength) {
return Math.max(this.localVariableLength, localVariableLength return Math.max(this.localVariableLength, localVariableLength
+ StackSize.of(exitTypes)
+ StackSize.of(initialTypes) + StackSize.of(initialTypes)
+ StackSize.of(enterTypes) + StackSize.of(enterTypes));
+ StackSize.of(exitTypes));
} }


@Override @Override
public void requireStackSize(int stackSize) { public void requireStackSize(int stackSize) {
Default.this.stackSize = Math.max(Default.this.stackSize, stackSize); Default.this.stackSize = Math.max(this.stackSize, stackSize);
} }


@Override @Override
Expand Down Expand Up @@ -4360,12 +4345,20 @@ protected WithRetainedArguments(MethodDescription instrumentedMethod,
super(instrumentedMethod, initialTypes, enterTypes, exitTypes); super(instrumentedMethod, initialTypes, enterTypes, exitTypes);
} }


@Override
public MethodSizeHandler.ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod) {
return new ForAdvice(adviceMethod, instrumentedMethod.getStackSize()
+ StackSize.of(exitTypes)
+ StackSize.of(initialTypes)
+ StackSize.of(enterTypes));
}

@Override @Override
public int compoundLocalVariableLength(int localVariableLength) { public int compoundLocalVariableLength(int localVariableLength) {
return Math.max(this.localVariableLength, localVariableLength return Math.max(this.localVariableLength, localVariableLength
+ StackSize.of(exitTypes)
+ StackSize.of(initialTypes) + StackSize.of(initialTypes)
+ StackSize.of(enterTypes) + StackSize.of(enterTypes));
+ StackSize.of(exitTypes));
} }
} }


Expand All @@ -4390,12 +4383,20 @@ protected WithCopiedArguments(MethodDescription instrumentedMethod,
} }


@Override @Override
public int compoundLocalVariableLength(int localVariableLength) { public MethodSizeHandler.ForAdvice bindExit(MethodDescription.InDefinedShape adviceMethod) {
return Math.max(this.localVariableLength, localVariableLength return new ForAdvice(adviceMethod, 2 * instrumentedMethod.getStackSize()
+ StackSize.of(initialTypes) + StackSize.of(initialTypes)
+ StackSize.of(enterTypes) + StackSize.of(enterTypes)
+ StackSize.of(exitTypes));
}

@Override
public int compoundLocalVariableLength(int localVariableLength) {
return Math.max(this.localVariableLength, localVariableLength
+ instrumentedMethod.getStackSize()
+ StackSize.of(exitTypes) + StackSize.of(exitTypes)
+ instrumentedMethod.getStackSize()); + StackSize.of(initialTypes)
+ StackSize.of(enterTypes));
} }
} }


Expand All @@ -4409,59 +4410,37 @@ protected class ForAdvice implements MethodSizeHandler.ForAdvice {
*/ */
private final MethodDescription.InDefinedShape adviceMethod; private final MethodDescription.InDefinedShape adviceMethod;


/** private final int localVariablePadding;
* The types provided before execution of the advice code.
*/
private final List<? extends TypeDescription> startTypes;

/**
* The types provided after execution of the advice code.
*/
private final List<? extends TypeDescription> endTypes;


/** /**
* The padding that this advice method requires additionally to its computed size. * The stack padding that this advice method requires additionally to its computed size.
*/ */
private int padding; private int stackPadding;


/** protected ForAdvice(MethodDescription.InDefinedShape adviceMethod, int localVariablePadding) {
* Creates a new method size handler for an advice method.
*
* @param adviceMethod The advice method.
* @param startTypes The types provided before execution of the advice code.
* @param endTypes The types provided after execution of the advice code.
*/
protected ForAdvice(MethodDescription.InDefinedShape adviceMethod,
List<? extends TypeDescription> startTypes,
List<? extends TypeDescription> endTypes) {
this.adviceMethod = adviceMethod; this.adviceMethod = adviceMethod;
this.startTypes = startTypes; this.localVariablePadding = localVariablePadding;
this.endTypes = endTypes;
} }


@Override @Override
public void requireLocalVariableLength(int localVariableLength) { public void requireStackSize(int stackSize) {
Default.this.requireLocalVariableLength(localVariableLength); Default.this.requireStackSize(stackSize);
} }


@Override @Override
public void requireStackSize(int stackSize) { public void requireLocalVariableLength(int localVariableLength) {
Default.this.requireStackSize(stackSize); Default.this.requireLocalVariableLength(localVariableLength);
} }


@Override @Override
public void recordMaxima(int stackSize, int localVariableLength) { public void requireStackPadding(int stackPadding) {
Default.this.stackSize = Math.max(Default.this.stackSize, stackSize) + padding; this.stackPadding = Math.max(this.stackPadding, stackPadding);
Default.this.localVariableLength = Math.max(Default.this.localVariableLength, localVariableLength
- adviceMethod.getStackSize()
+ instrumentedMethod.getStackSize()
+ StackSize.of(startTypes)
+ StackSize.of(endTypes));
} }


@Override @Override
public void recordPadding(int padding) { public void recordMaxima(int stackSize, int localVariableLength) {
this.padding = Math.max(this.padding, padding); Default.this.requireStackSize(stackSize + stackPadding);
Default.this.requireLocalVariableLength(localVariableLength - adviceMethod.getStackSize() + localVariablePadding);
} }
} }
} }
Expand Down Expand Up @@ -7197,7 +7176,7 @@ protected MethodVisitor apply(MethodVisitor methodVisitor,
return new CodeTranslationVisitor.ForMethodExit(methodVisitor, return new CodeTranslationVisitor.ForMethodExit(methodVisitor,
implementationContext, implementationContext,
argumentHandler.bindExit(adviceMethod, getThrowable().represents(NoExceptionHandler.class)), argumentHandler.bindExit(adviceMethod, getThrowable().represents(NoExceptionHandler.class)),
methodSizeHandler.bindExit(adviceMethod, getThrowable().represents(NoExceptionHandler.class)), methodSizeHandler.bindExit(adviceMethod),
stackMapFrameHandler.bindExit(adviceMethod), stackMapFrameHandler.bindExit(adviceMethod),
instrumentedMethod, instrumentedMethod,
adviceMethod, adviceMethod,
Expand Down Expand Up @@ -7518,7 +7497,7 @@ public void visitVarInsn(int opcode, int offset) {
default: default:
throw new IllegalStateException("Unexpected opcode: " + opcode); throw new IllegalStateException("Unexpected opcode: " + opcode);
} }
methodSizeHandler.recordPadding(stackManipulation.apply(mv, implementationContext).getMaximalSize() - expectedGrowth.getSize()); methodSizeHandler.requireStackPadding(stackManipulation.apply(mv, implementationContext).getMaximalSize() - expectedGrowth.getSize());
} else { } else {
mv.visitVarInsn(opcode, argumentHandler.mapped(offset)); mv.visitVarInsn(opcode, argumentHandler.mapped(offset));
} }
Expand All @@ -7528,7 +7507,7 @@ public void visitVarInsn(int opcode, int offset) {
public void visitIincInsn(int offset, int value) { public void visitIincInsn(int offset, int value) {
OffsetMapping.Target target = offsetMappings.get(offset); OffsetMapping.Target target = offsetMappings.get(offset);
if (target != null) { if (target != null) {
methodSizeHandler.recordPadding(target.resolveIncrement(value).apply(mv, implementationContext).getMaximalSize()); methodSizeHandler.requireStackPadding(target.resolveIncrement(value).apply(mv, implementationContext).getMaximalSize());
} else { } else {
mv.visitIincInsn(argumentHandler.mapped(offset), value); mv.visitIincInsn(argumentHandler.mapped(offset), value);
} }
Expand Down Expand Up @@ -8053,6 +8032,7 @@ public void initialize() {
methodVisitor.visitInsn(Opcodes.ACONST_NULL); methodVisitor.visitInsn(Opcodes.ACONST_NULL);
methodVisitor.visitVarInsn(Opcodes.ASTORE, argumentHandler.exit()); methodVisitor.visitVarInsn(Opcodes.ASTORE, argumentHandler.exit());
} }
methodSizeHandler.requireStackSize(adviceMethod.getReturnType().getStackSize().getSize());
} }


@Override @Override
Expand Down Expand Up @@ -8297,7 +8277,7 @@ protected Bound resolve(TypeDescription instrumentedType,
methodVisitor, methodVisitor,
implementationContext, implementationContext,
argumentHandler.bindExit(adviceMethod, getThrowable().represents(NoExceptionHandler.class)), argumentHandler.bindExit(adviceMethod, getThrowable().represents(NoExceptionHandler.class)),
methodSizeHandler.bindExit(adviceMethod, getThrowable().represents(NoExceptionHandler.class)), methodSizeHandler.bindExit(adviceMethod),
stackMapFrameHandler.bindExit(adviceMethod), stackMapFrameHandler.bindExit(adviceMethod),
suppressionHandler.bind(exceptionHandler), suppressionHandler.bind(exceptionHandler),
relocationHandler.bind(instrumentedMethod, relocation)); relocationHandler.bind(instrumentedMethod, relocation));
Expand Down Expand Up @@ -8787,6 +8767,7 @@ protected void onUserEnd() {
} else { } else {
methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitInsn(Opcodes.RETURN);
} }
methodSizeHandler.requireStackSize(instrumentedMethod.getReturnType().getStackSize().getSize());
} }


/** /**
Expand Down Expand Up @@ -9003,6 +8984,7 @@ protected void onUserReturn() {
methodVisitor.visitVarInsn(Opcodes.ASTORE, argumentHandler.returned()); methodVisitor.visitVarInsn(Opcodes.ASTORE, argumentHandler.returned());
} }
methodVisitor.visitLabel(endOfHandler); methodVisitor.visitLabel(endOfHandler);
methodSizeHandler.requireStackSize(StackSize.SINGLE.getSize());
} }


@Override @Override
Expand Down
Expand Up @@ -15,7 +15,7 @@ public class AdviceLocalValueTest {
private static final String ENTER = "enter", EXIT = "exit"; private static final String ENTER = "enter", EXIT = "exit";


@Test @Test
public void testAdviceWithEnterValue() throws Exception { public void testAdviceWithLocalValue() throws Exception {
Class<?> type = new ByteBuddy() Class<?> type = new ByteBuddy()
.redefine(Sample.class) .redefine(Sample.class)
.visit(Advice.to(LocalValueAdvice.class).on(named(FOO))) .visit(Advice.to(LocalValueAdvice.class).on(named(FOO)))
Expand All @@ -27,6 +27,19 @@ public void testAdviceWithEnterValue() throws Exception {
assertThat(type.getDeclaredField(EXIT).get(null), is((Object) 1)); assertThat(type.getDeclaredField(EXIT).get(null), is((Object) 1));
} }


@Test
public void testAdviceWithTwoLocalValues() throws Exception {
Class<?> type = new ByteBuddy()
.redefine(Sample.class)
.visit(Advice.to(LocalValueTwoParametersAdvice.class).on(named(FOO)))
.make()
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO));
assertThat(type.getDeclaredField(ENTER).get(null), is((Object) 1));
assertThat(type.getDeclaredField(EXIT).get(null), is((Object) 1));
}

@SuppressWarnings("unused") @SuppressWarnings("unused")
public static class Sample { public static class Sample {


Expand Down Expand Up @@ -65,4 +78,34 @@ private static void exit(@Advice.Local(FOO) Object foo) {
} }
} }


@SuppressWarnings("unused")
public static class LocalValueTwoParametersAdvice {

@Advice.OnMethodEnter
private static void enter(@Advice.Local(FOO) Object foo, @Advice.Local(BAR) Object bar) {
if (foo != null || bar != null) {
throw new AssertionError();
}
foo = FOO;
bar = BAR;
if (!foo.equals(FOO) || !bar.equals(BAR)) {
throw new AssertionError();
}
Sample.enter++;
}

@Advice.OnMethodExit
private static void exit(@Advice.Local(FOO) Object foo, @Advice.Local(BAR) Object bar) {
if (!foo.equals(FOO) || !bar.equals(BAR)) {
throw new AssertionError();
}
foo = BAR;
bar = FOO;
if (!foo.equals(BAR) || !bar.equals(FOO)) {
throw new AssertionError();
}
Sample.exit++;
}
}

} }

0 comments on commit 186c96d

Please sign in to comment.