@Override
 public MethodDelegationBinder.ParameterBinding<?> bind(
     AnnotationDescription.Loadable<FieldValue> annotation,
     MethodDescription source,
     ParameterDescription target,
     Implementation.Target implementationTarget,
     Assigner assigner) {
   FieldLocator.Resolution resolution =
       FieldLocator.of(
               annotation.getValue(DEFINING_TYPE, TypeDescription.class),
               implementationTarget.getTypeDescription())
           .resolve(annotation.getValue(FIELD_NAME, String.class), source.isStatic());
   if (resolution.isResolved()) {
     StackManipulation stackManipulation =
         new StackManipulation.Compound(
             resolution.getFieldDescription().isStatic()
                 ? StackManipulation.Trivial.INSTANCE
                 : MethodVariableAccess.REFERENCE.loadOffset(0),
             FieldAccess.forField(resolution.getFieldDescription()).getter(),
             assigner.assign(
                 resolution.getFieldDescription().getType().asErasure(),
                 target.getType().asErasure(),
                 RuntimeType.Verifier.check(target)));
     return stackManipulation.isValid()
         ? new MethodDelegationBinder.ParameterBinding.Anonymous(stackManipulation)
         : MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
   } else {
     return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
   }
 }
 @Test
 public void testBoxing() throws Exception {
   StackManipulation boxingStackManipulation =
       PrimitiveBoxingDelegate.forPrimitive(primitiveTypeDescription)
           .assignBoxedTo(targetType, chainedAssigner, Assigner.Typing.STATIC);
   assertThat(boxingStackManipulation.isValid(), is(true));
   StackManipulation.Size size =
       boxingStackManipulation.apply(methodVisitor, implementationContext);
   assertThat(size.getSizeImpact(), is(sizeChange));
   assertThat(size.getMaximalSize(), is(0));
   verify(primitiveTypeDescription).represents(primitiveType);
   verify(primitiveTypeDescription, atLeast(1)).represents(any(Class.class));
   verifyNoMoreInteractions(primitiveTypeDescription);
   verify(chainedAssigner)
       .assign(referenceTypeDescription.asGenericType(), targetType, Assigner.Typing.STATIC);
   verifyNoMoreInteractions(chainedAssigner);
   verify(methodVisitor)
       .visitMethodInsn(
           Opcodes.INVOKESTATIC,
           referenceTypeDescription.getInternalName(),
           VALUE_OF,
           boxingMethodDescriptor,
           false);
   verifyNoMoreInteractions(methodVisitor);
   verify(stackManipulation, atLeast(1)).isValid();
   verify(stackManipulation).apply(methodVisitor, implementationContext);
   verifyNoMoreInteractions(stackManipulation);
 }
 @Test(expected = IllegalStateException.class)
 public void testTargetToSourceAssignable() throws Exception {
   defineAssignability(false, true);
   StackManipulation stackManipulation =
       ReferenceTypeAwareAssigner.INSTANCE.assign(
           sourceTypeDescription, targetTypeDescription, false);
   assertThat(stackManipulation.isValid(), is(false));
   stackManipulation.apply(methodVisitor, implementationContext);
 }
 @Test
 public void testAssignmentEqual() throws Exception {
   StackManipulation stackManipulation =
       Assigner.EqualTypesOnly.INSTANCE.assign(first, first, dynamicallyTyped);
   assertThat(stackManipulation.isValid(), is(true));
   StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext);
   assertThat(size.getSizeImpact(), is(0));
   assertThat(size.getMaximalSize(), is(0));
 }
 @Test(expected = IllegalStateException.class)
 public void testPrimitiveAssignabilityWhenNotEqual() throws Exception {
   TypeDescription primitiveType =
       new TypeDescription.ForLoadedType(int.class); // Note: cannot mock equals
   TypeDescription otherPrimitiveType =
       new TypeDescription.ForLoadedType(long.class); // Note: cannot mock equals
   StackManipulation stackManipulation =
       ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, otherPrimitiveType, true);
   assertThat(stackManipulation.isValid(), is(false));
   stackManipulation.apply(methodVisitor, implementationContext);
 }
 @Before
 public void setUp() throws Exception {
   when(chainedAssigner.assign(
           any(TypeDescription.Generic.class),
           any(TypeDescription.Generic.class),
           any(Assigner.Typing.class)))
       .thenReturn(stackManipulation);
   when(stackManipulation.isValid()).thenReturn(true);
   when(stackManipulation.apply(any(MethodVisitor.class), any(Implementation.Context.class)))
       .thenReturn(StackSize.ZERO.toIncreasingSize());
 }
 @Test
 public void testPrimitiveAssignabilityWhenEqual() throws Exception {
   TypeDescription primitiveType =
       new TypeDescription.ForLoadedType(int.class); // Note: cannot mock equals
   StackManipulation stackManipulation =
       ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, primitiveType, true);
   assertThat(stackManipulation.isValid(), is(true));
   StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext);
   assertThat(size.getSizeImpact(), is(0));
   assertThat(size.getMaximalSize(), is(0));
   verifyZeroInteractions(methodVisitor);
 }
 @Test
 public void testSourceToTargetAssignable() throws Exception {
   defineAssignability(true, false);
   StackManipulation stackManipulation =
       ReferenceTypeAwareAssigner.INSTANCE.assign(
           sourceTypeDescription, targetTypeDescription, false);
   assertThat(stackManipulation.isValid(), is(true));
   StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext);
   assertThat(size.getSizeImpact(), is(0));
   assertThat(size.getMaximalSize(), is(0));
   verifyZeroInteractions(methodVisitor);
 }
 @Test
 public void testTargetToSourceAssignableRuntimeType() throws Exception {
   defineAssignability(false, false);
   when(targetTypeDescription.getInternalName()).thenReturn(FOO);
   StackManipulation stackManipulation =
       ReferenceTypeAwareAssigner.INSTANCE.assign(
           sourceTypeDescription, targetTypeDescription, true);
   assertThat(stackManipulation.isValid(), is(true));
   StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext);
   assertThat(size.getSizeImpact(), is(0));
   assertThat(size.getMaximalSize(), is(0));
   verify(methodVisitor).visitTypeInsn(Opcodes.CHECKCAST, FOO);
   verifyNoMoreInteractions(methodVisitor);
 }
 @Override
 public int hashCode() {
   int result = super.hashCode();
   result = 31 * result + valueLoadInstruction.hashCode();
   result = 31 * result + loadedType.hashCode();
   return result;
 }
 @Override
 public boolean equals(Object other) {
   return this == other
       || !(other == null || getClass() != other.getClass())
           && super.equals(other)
           && loadedType.equals(((ForPoolValue) other).loadedType)
           && valueLoadInstruction.equals(((ForPoolValue) other).valueLoadInstruction);
 }
  public Size apply(
      MethodVisitor methodVisitor,
      Implementation.Context implementationContext,
      MethodDescription instrumentedMethod) {

    checkMethodSignature(instrumentedMethod);

    try {
      StackManipulation stack = buildStack();
      StackManipulation.Size finalStackSize = stack.apply(methodVisitor, implementationContext);

      return new Size(
          finalStackSize.getMaximalSize(),
          instrumentedMethod.getStackSize() + 2); // 2 stack slots for a single local variable

    } catch (NoSuchMethodException | NoSuchFieldException e) {
      throw new RuntimeException(e);
    }
  }
 @Override
 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
   methodVisitor.visitMethodInsn(
       Opcodes.INVOKESTATIC,
       wrapperType.getInternalName(),
       boxingMethodName,
       boxingMethodDescriptor,
       false);
   return size.aggregate(stackManipulation.apply(methodVisitor, implementationContext));
 }
 /**
  * Blueprint method that for applying the actual implementation.
  *
  * @param methodVisitor The method visitor to which the implementation is applied to.
  * @param implementationContext The implementation context for the given implementation.
  * @param instrumentedMethod The instrumented method that is target of the implementation.
  * @param fixedValueType A description of the type of the fixed value that is loaded by the {@code
  *     valueLoadingInstruction}.
  * @param valueLoadingInstruction A stack manipulation that represents the loading of the fixed
  *     value onto the operand stack.
  * @return A representation of the stack and variable array sized that are required for this
  *     implementation.
  */
 protected ByteCodeAppender.Size apply(
     MethodVisitor methodVisitor,
     Context implementationContext,
     MethodDescription instrumentedMethod,
     TypeDescription.Generic fixedValueType,
     StackManipulation valueLoadingInstruction) {
   StackManipulation assignment =
       assigner.assign(fixedValueType, instrumentedMethod.getReturnType(), typing);
   if (!assignment.isValid()) {
     throw new IllegalArgumentException(
         "Cannot return value of type " + fixedValueType + " for " + instrumentedMethod);
   }
   StackManipulation.Size stackSize =
       new StackManipulation.Compound(
               valueLoadingInstruction,
               assignment,
               MethodReturn.returning(instrumentedMethod.getReturnType().asErasure()))
           .apply(methodVisitor, implementationContext);
   return new ByteCodeAppender.Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
 }
 @Test
 public void testBoxingAssignment() {
   StackManipulation stackManipulation =
       primitiveAssigner.assign(
           sourceTypeDescription, targetTypeDescription, Assigner.Typing.STATIC);
   assertThat(stackManipulation.isValid(), is(assignable));
   verify(chainedStackManipulation).isValid();
   verifyNoMoreInteractions(chainedStackManipulation);
   verify(sourceTypeDescription, atLeast(0)).represents(any(Class.class));
   verify(sourceTypeDescription).represents(sourceType);
   verify(sourceTypeDescription, atLeast(1)).isPrimitive();
   verifyNoMoreInteractions(sourceTypeDescription);
   verify(targetTypeDescription, atLeast(1)).isPrimitive();
   verifyNoMoreInteractions(targetTypeDescription);
   verify(chainedAssigner)
       .assign(
           new TypeDescription.ForLoadedType(targetType),
           targetTypeDescription,
           Assigner.Typing.STATIC);
   verifyNoMoreInteractions(chainedAssigner);
 }
 @Before
 public void setUp() throws Exception {
   when(sourceTypeDescription.represents(sourceType)).thenReturn(true);
   when(sourceTypeDescription.isPrimitive()).thenReturn(true);
   when(targetTypeDescription.represents(targetType)).thenReturn(true);
   when(targetTypeDescription.isPrimitive()).thenReturn(false);
   when(chainedStackManipulation.isValid()).thenReturn(true);
   when(chainedAssigner.assign(
           any(TypeDescription.class), any(TypeDescription.class), any(Assigner.Typing.class)))
       .thenReturn(chainedStackManipulation);
   primitiveAssigner = new PrimitiveTypeAwareAssigner(chainedAssigner);
 }
 @Test
 public void testAssignmentNotEqual() throws Exception {
   StackManipulation stackManipulation =
       Assigner.EqualTypesOnly.INSTANCE.assign(first, second, dynamicallyTyped);
   assertThat(stackManipulation.isValid(), is(false));
 }
 @Override
 public boolean equals(Object other) {
   return this == other
       || !(other == null || getClass() != other.getClass())
           && fieldGetAccess.equals(((StaticFieldByteCodeAppender) other).fieldGetAccess);
 }
 @Override
 public boolean isValid() {
   return stackManipulation.isValid();
 }
 @Override
 public int hashCode() {
   return fieldGetAccess.hashCode();
 }