@Override
 public Size apply(
     MethodVisitor methodVisitor,
     Context implementationContext,
     MethodDescription instrumentedMethod) {
   StackManipulation thisReference = MethodVariableAccess.REFERENCE.loadOffset(0);
   FieldList<?> fieldList = instrumentedType.getDeclaredFields();
   StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()];
   int index = 0;
   for (FieldDescription fieldDescription : fieldList) {
     fieldLoading[index] =
         new StackManipulation.Compound(
             thisReference,
             MethodVariableAccess.forType(fieldDescription.getType().asErasure())
                 .loadOffset(instrumentedMethod.getParameters().get(index).getOffset()),
             FieldAccess.forField(fieldDescription).putter());
     index++;
   }
   StackManipulation.Size stackSize =
       new StackManipulation.Compound(
               thisReference,
               MethodInvocation.invoke(ConstructorCall.INSTANCE.objectTypeDefaultConstructor),
               new StackManipulation.Compound(fieldLoading),
               MethodReturn.VOID)
           .apply(methodVisitor, implementationContext);
   return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
 }
 @Override
 public Size apply(
     MethodVisitor methodVisitor,
     Context implementationContext,
     MethodDescription instrumentedMethod) {
   StackManipulation thisReference =
       MethodVariableAccess.forType(instrumentedType).loadOffset(0);
   FieldList<?> fieldList = instrumentedType.getDeclaredFields();
   StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()];
   int index = 0;
   for (FieldDescription fieldDescription : fieldList) {
     fieldLoading[index++] =
         new StackManipulation.Compound(
             thisReference, FieldAccess.forField(fieldDescription).getter());
   }
   StackManipulation.Size stackSize =
       new StackManipulation.Compound(
               new StackManipulation.Compound(fieldLoading),
               MethodInvocation.invoke(accessorMethod),
               assigner.assign(
                   accessorMethod.getReturnType().asErasure(),
                   instrumentedMethod.getReturnType().asErasure(),
                   Assigner.Typing.DYNAMIC),
               MethodReturn.returning(instrumentedMethod.getReturnType().asErasure()))
           .apply(methodVisitor, implementationContext);
   return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
 }
  private void buildCopyStack(
      List<StackManipulation> stack,
      int iterations,
      Method getMethod,
      Method putMethod,
      long stride)
      throws NoSuchFieldException, NoSuchMethodException {

    final Field unsafeField = UnsafeCopier.class.getDeclaredField("unsafe");

    final StackManipulation copyStack =
        new StackManipulation.Compound(
            // unsafe.putLong(dest, destOffset, unsafe.getLong(src));
            MethodVariableAccess.REFERENCE.loadOffset(0), // ALOAD 0 this
            FieldAccess.forField(new FieldDescription.ForLoadedField(unsafeField))
                .getter(), // GETFIELD
            MethodVariableAccess.REFERENCE.loadOffset(1), // ALOAD 1 dest
            MethodVariableAccess.LONG.loadOffset(4), // LLOAD 4 destOffset
            MethodVariableAccess.REFERENCE.loadOffset(0), // ALOAD 0 this
            FieldAccess.forField(new FieldDescription.ForLoadedField(unsafeField))
                .getter(), // GETFIELD
            MethodVariableAccess.LONG.loadOffset(2), // LLOAD 2 src
            MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(getMethod)),
            MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(putMethod)));

    final StackManipulation incrementStack =
        new StackManipulation.Compound(
            // destOffset += 8; src += 8;
            MethodVariableAccess.LONG.loadOffset(4), // LLOAD 4 destOffset
            LongConstant.forValue(stride), // LDC 8 strideWidth
            LongAdd.INSTANCE, // LADD
            MethodVariableStore.LONG.storeOffset(4), // LSTORE 4
            MethodVariableAccess.LONG.loadOffset(2), // LLOAD 2 src
            LongConstant.forValue(stride), // LDC 8 strideWidth
            LongAdd.INSTANCE, // LADD
            MethodVariableStore.LONG.storeOffset(2) // LSTORE 2
            );

    for (int i = 0; i < iterations; i++) {
      stack.add(copyStack);
      stack.add(incrementStack);
    }
  }
 @Override
 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
   TypeDescription auxiliaryType =
       implementationContext.register(
           new MethodCallProxy(specialMethodInvocation, serializable));
   return new Compound(
           TypeCreation.forType(auxiliaryType),
           Duplication.SINGLE,
           MethodVariableAccess.allArgumentsOf(specialMethodInvocation.getMethodDescription())
               .prependThisReference(),
           MethodInvocation.invoke(
               auxiliaryType.getDeclaredMethods().filter(isConstructor()).getOnly()))
       .apply(methodVisitor, implementationContext);
 }