private void writeGroovyMethods(ClassVisitor visitor, Class<?> managedTypeClass) {
    // Object propertyMissing(String name)
    MethodVisitor methodVisitor =
        declareMethod(
            visitor, "propertyMissing", GET_PROPERTY_MISSING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);

    // throw new MissingPropertyException(name, <managed-type>.class)
    methodVisitor.visitTypeInsn(NEW, MISSING_PROPERTY_EXCEPTION_TYPE);
    methodVisitor.visitInsn(DUP);
    putFirstMethodArgumentOnStack(methodVisitor);
    putClassOnStack(methodVisitor, managedTypeClass);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        MISSING_PROPERTY_EXCEPTION_TYPE,
        "<init>",
        MISSING_PROPERTY_CONSTRUCTOR_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ATHROW);

    // Object propertyMissing(String name, Object value)

    methodVisitor =
        declareMethod(
            visitor, "propertyMissing", SET_PROPERTY_MISSING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);

    // throw new MissingPropertyException(name, <managed-type>.class)
    methodVisitor.visitTypeInsn(NEW, MISSING_PROPERTY_EXCEPTION_TYPE);
    methodVisitor.visitInsn(DUP);
    putFirstMethodArgumentOnStack(methodVisitor);
    putClassOnStack(methodVisitor, managedTypeClass);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        MISSING_PROPERTY_EXCEPTION_TYPE,
        "<init>",
        MISSING_PROPERTY_CONSTRUCTOR_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ATHROW);

    // Object methodMissing(String name, Object args)
    methodVisitor =
        declareMethod(
            visitor, "methodMissing", METHOD_MISSING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);

    // throw new MissingMethodException(name, <managed-type>.class, args)
    methodVisitor.visitTypeInsn(NEW, MISSING_METHOD_EXCEPTION_TYPE);
    methodVisitor.visitInsn(DUP);
    putMethodArgumentOnStack(methodVisitor, 1);
    putClassOnStack(methodVisitor, managedTypeClass);
    putMethodArgumentOnStack(methodVisitor, 2);
    methodVisitor.visitTypeInsn(CHECKCAST, OBJECT_ARRAY_TYPE);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        MISSING_METHOD_EXCEPTION_TYPE,
        "<init>",
        MISSING_METHOD_EXCEPTION_CONSTRUCTOR_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ATHROW);
  }
 private void castFirstStackElement(MethodVisitor methodVisitor, Class<?> returnType) {
   if (returnType.isPrimitive()) {
     unboxType(methodVisitor, returnType);
   } else {
     methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(returnType));
   }
 }
  protected void injectGetByIndex(
      ClassWriter classWriter, String targetClassName, List<Field> fields) {
    MethodVisitor methodVisitor =
        classWriter.visitMethod(
            ACC_PUBLIC,
            "get",
            "(Ljava/lang/Object;I)Ljava/lang/Object;",
            null,
            new String[] {getInternalName(ILLEGAL_ACCESS_EXCEPTION.getCanonicalName())});

    Boxer boxer = new Boxer(methodVisitor);

    methodVisitor.visitCode();
    methodVisitor.visitVarInsn(ILOAD, 2);

    int maxStack = 6;

    Label[] labels = new Label[fields.size()];
    Label errorLabel = new Label();

    for (int i = 0; i < fields.size(); i++) {
      labels[i] = new Label();
    }

    methodVisitor.visitTableSwitchInsn(0, labels.length - 1, errorLabel, labels);

    if (!fields.isEmpty()) {
      maxStack--;

      for (int i = 0; i < fields.size(); i++) {
        Field field = fields.get(i);
        Class<?> type = field.getType();
        String fieldDescriptor = Type.getDescriptor(type);

        methodVisitor.visitLabel(labels[i]);

        if (i == 0) methodVisitor.visitFrame(F_APPEND, 1, new Object[] {targetClassName}, 0, null);
        else methodVisitor.visitFrame(F_SAME, 0, null, 0, null);

        if (isPublic(field)) {
          methodVisitor.visitVarInsn(ALOAD, 1);
          methodVisitor.visitTypeInsn(CHECKCAST, targetClassName);
          methodVisitor.visitFieldInsn(GETFIELD, targetClassName, field.getName(), fieldDescriptor);

          boxer.box(Type.getType(type));
        } else {
          injectReflectiveGetter(methodVisitor);
        }

        methodVisitor.visitInsn(ARETURN);
      }

      methodVisitor.visitLabel(errorLabel);
      methodVisitor.visitFrame(F_SAME, 0, null, 0, null);
    }

    injectException(methodVisitor, IllegalAccessException.class);
    methodVisitor.visitMaxs(maxStack, 3);
    methodVisitor.visitEnd();
  }
  private void throwExceptionBecauseCalledOnItself(MethodVisitor methodVisitor) {
    String exceptionInternalName = Type.getInternalName(UnsupportedOperationException.class);
    methodVisitor.visitTypeInsn(NEW, exceptionInternalName);
    methodVisitor.visitInsn(DUP);
    putConstantOnStack(methodVisitor, "Calling setters of a managed type on itself is not allowed");

    String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, STRING_TYPE);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL, exceptionInternalName, CONSTRUCTOR_NAME, constructorDescriptor, false);
    methodVisitor.visitInsn(ATHROW);
  }
 protected void injectException(
     MethodVisitor methodVisitor, Class<? extends Throwable> throwable) {
   methodVisitor.visitTypeInsn(NEW, getInternalName(throwable.getCanonicalName()));
   methodVisitor.visitInsn(DUP);
   methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
   methodVisitor.visitInsn(DUP);
   methodVisitor.visitLdcInsn("Invalid index: ");
   methodVisitor.visitMethodInsn(
       INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
   methodVisitor.visitVarInsn(ILOAD, 2);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
   methodVisitor.visitMethodInsn(
       INVOKESPECIAL,
       getInternalName(throwable.getCanonicalName()),
       "<init>",
       "(Ljava/lang/String;)V");
   methodVisitor.visitInsn(ATHROW);
 }
  // the overload of type Object for Groovy coercions:  public void setFoo(Object foo)
  private void createTypeConvertingSetter(
      ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (!property.isWritable() || !(property.getSchema() instanceof ScalarValueSchema)) {
      return;
    }

    Class<?> propertyClass = property.getType().getConcreteClass();
    Type propertyType = Type.getType(propertyClass);
    Class<?> boxedClass =
        propertyClass.isPrimitive() ? BOXED_TYPES.get(propertyClass) : propertyClass;
    Type boxedType = Type.getType(boxedClass);

    Method setter = property.getSetter().getMethod();
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            setter.getName(),
            SET_OBJECT_PROPERTY_DESCRIPTOR,
            SET_OBJECT_PROPERTY_DESCRIPTOR);

    putThisOnStack(methodVisitor);
    putTypeConverterFieldValueOnStack(methodVisitor, generatedType);

    // Object converted = $typeConverter.convert(foo, Float.class, false);
    methodVisitor.visitVarInsn(ALOAD, 1); // put var #1 ('foo') on the stack
    methodVisitor.visitLdcInsn(boxedType); // push the constant Class onto the stack
    methodVisitor.visitInsn(
        propertyClass.isPrimitive()
            ? ICONST_1
            : ICONST_0); // push int 1 or 0 (interpreted as true or false) onto the stack
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        TYPE_CONVERTER_TYPE.getInternalName(),
        "convert",
        COERCE_TO_SCALAR_DESCRIPTOR,
        true);
    methodVisitor.visitTypeInsn(CHECKCAST, boxedType.getInternalName());

    if (propertyClass.isPrimitive()) {
      unboxType(methodVisitor, propertyClass);
    }

    // invoke the typed setter, popping 'this' and 'converted' from the stack
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        setter.getName(),
        Type.getMethodDescriptor(Type.VOID_TYPE, propertyType),
        false);
    finishVisitingMethod(methodVisitor);
  }
 private void writeEqualsMethod(ClassVisitor cw, Type generatedType) {
   MethodVisitor methodVisitor =
       cw.visitMethod(Opcodes.ACC_PUBLIC, "equals", EQUALS_METHOD_DESCRIPTOR, null, null);
   methodVisitor.visitCode();
   methodVisitor.visitVarInsn(ALOAD, 0);
   methodVisitor.visitVarInsn(ALOAD, 1);
   Label notSameLabel = new Label();
   methodVisitor.visitJumpInsn(IF_ACMPNE, notSameLabel);
   methodVisitor.visitInsn(ICONST_1);
   methodVisitor.visitInsn(IRETURN);
   methodVisitor.visitLabel(notSameLabel);
   methodVisitor.visitVarInsn(ALOAD, 1);
   methodVisitor.visitTypeInsn(INSTANCEOF, MANAGED_INSTANCE_TYPE);
   Label notManagedInstanceLabel = new Label();
   methodVisitor.visitJumpInsn(IFNE, notManagedInstanceLabel);
   methodVisitor.visitInsn(ICONST_0);
   methodVisitor.visitInsn(IRETURN);
   methodVisitor.visitLabel(notManagedInstanceLabel);
   methodVisitor.visitVarInsn(ALOAD, 0);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       generatedType.getInternalName(),
       "getBackingNode",
       GET_BACKING_NODE_METHOD_DESCRIPTOR,
       false);
   methodVisitor.visitVarInsn(ALOAD, 1);
   methodVisitor.visitTypeInsn(CHECKCAST, MANAGED_INSTANCE_TYPE);
   methodVisitor.visitMethodInsn(
       INVOKEINTERFACE,
       MANAGED_INSTANCE_TYPE,
       "getBackingNode",
       GET_BACKING_NODE_METHOD_DESCRIPTOR,
       true);
   methodVisitor.visitMethodInsn(
       INVOKEINTERFACE, MUTABLE_MODEL_NODE_TYPE, "equals", EQUALS_METHOD_DESCRIPTOR, true);
   finishVisitingMethod(methodVisitor, Opcodes.IRETURN);
 }
 private void unboxType(MethodVisitor methodVisitor, Class<?> primitiveClass) {
   // Float f = (Float) tmp
   // f==null?0:f.floatValue()
   Class<?> boxedType = BOXED_TYPES.get(primitiveClass);
   Type primitiveType = Type.getType(primitiveClass);
   methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(boxedType));
   methodVisitor.visitInsn(DUP);
   Label exit = new Label();
   Label elseValue = new Label();
   methodVisitor.visitJumpInsn(IFNONNULL, elseValue);
   methodVisitor.visitInsn(POP);
   pushDefaultValue(methodVisitor, primitiveClass);
   methodVisitor.visitJumpInsn(GOTO, exit);
   methodVisitor.visitLabel(elseValue);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       Type.getInternalName(boxedType),
       primitiveClass.getSimpleName() + "Value",
       Type.getMethodDescriptor(primitiveType),
       false);
   methodVisitor.visitLabel(exit);
 }
  public static byte[] createTargetSetterFactory(String factoryName, String className, Type target)
      throws Exception {

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    MethodVisitor mv;

    String factoryType = AsmUtils.toType(factoryName);
    String classType = AsmUtils.toType(className);
    String targetType = AsmUtils.toType(target);

    cw.visit(
        V1_6,
        ACC_FINAL + ACC_PUBLIC + ACC_SUPER,
        factoryType,
        "L" + CELL_HANDLER_FACTORY_TYPE + "<L" + targetType + ";>;",
        CELL_HANDLER_FACTORY_TYPE,
        null);

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "<init>",
              "("
                  + AsmUtils.toDeclaredLType(Instantiator.class)
                  + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
                  + AsmUtils.toDeclaredLType(ParsingContextFactory.class)
                  + AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class)
                  + ")V",
              "("
                  + "L"
                  + AsmUtils.toType(Instantiator.class)
                  + "<L"
                  + AsmUtils.toType(CsvMapperCellHandler.class)
                  + "<L"
                  + targetType
                  + ";>;L"
                  + targetType
                  + ";>;"
                  + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
                  + AsmUtils.toDeclaredLType(ParsingContextFactory.class)
                  + "L"
                  + AsmUtils.toType(FieldMapperErrorHandler.class)
                  + "<L"
                  + AsmUtils.toType(CsvColumnKey.class)
                  + ";>;"
                  + ")V",
              null);

      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ALOAD, 3);
      mv.visitVarInsn(ALOAD, 4);
      mv.visitMethodInsn(
          INVOKESPECIAL,
          CELL_HANDLER_FACTORY_TYPE,
          "<init>",
          "("
              + AsmUtils.toDeclaredLType(Instantiator.class)
              + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
              + AsmUtils.toDeclaredLType(ParsingContextFactory.class)
              + AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class)
              + ")V",
          false);
      mv.visitInsn(RETURN);
      mv.visitMaxs(5, 5);
      mv.visitEnd();
    }
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "newInstance",
              "("
                  + AsmUtils.toDeclaredLType(DelayedCellSetter[].class)
                  + AsmUtils.toDeclaredLType(CellSetter[].class)
                  + ")"
                  + AsmUtils.toDeclaredLType(CsvMapperCellHandler.class),
              "("
                  + "[L"
                  + DELAYED_CELL_SETTER_TYPE
                  + "<L"
                  + targetType
                  + ";*>;"
                  + "[L"
                  + CELL_SETTER_TYPE
                  + "<L"
                  + targetType
                  + ";>;"
                  + ")"
                  + "L"
                  + AsmUtils.toType(CsvMapperCellHandler.class)
                  + "<L"
                  + targetType
                  + ";>;",
              null);
      mv.visitCode();
      mv.visitTypeInsn(NEW, classType);
      mv.visitInsn(DUP);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD, factoryType, "instantiator", AsmUtils.toDeclaredLType(Instantiator.class));
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD, factoryType, "keys", AsmUtils.toDeclaredLType(CsvColumnKey[].class));
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          factoryType,
          "parsingContextFactory",
          AsmUtils.toDeclaredLType(ParsingContextFactory.class));
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          AsmUtils.toType(ParsingContextFactory.class),
          "newContext",
          "()" + AsmUtils.toDeclaredLType(ParsingContext.class),
          false);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          factoryType,
          "fieldErrorHandler",
          AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class));
      mv.visitMethodInsn(
          INVOKESPECIAL,
          classType,
          "<init>",
          "("
              + AsmUtils.toDeclaredLType(Instantiator.class)
              + AsmUtils.toDeclaredLType(DelayedCellSetter[].class)
              + AsmUtils.toDeclaredLType(CellSetter[].class)
              + AsmUtils.toDeclaredLType(CsvColumnKey[].class)
              + AsmUtils.toDeclaredLType(ParsingContext.class)
              + AsmUtils.toDeclaredLType(FieldMapperErrorHandler.class)
              + ")V",
          false);
      mv.visitInsn(ARETURN);
      mv.visitMaxs(8, 3);
      mv.visitEnd();
    }
    cw.visitEnd();

    return cw.toByteArray();
  }
  private void writeConfigureMethod(
      ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (!property.isWritable() && property.getSchema() instanceof CompositeSchema) {
      // Adds a void $propName(Closure<?> cl) method that delegates to model state

      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
              null);
      putStateFieldValueOnStack(methodVisitor, generatedType);
      putConstantOnStack(methodVisitor, property.getName());
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEINTERFACE,
          MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
          "apply",
          STATE_APPLY_METHOD_DESCRIPTOR,
          true);
      finishVisitingMethod(methodVisitor);
      return;
    }
    if (!property.isWritable() && property.getSchema() instanceof UnmanagedImplStructSchema) {
      UnmanagedImplStructSchema<?> structSchema =
          (UnmanagedImplStructSchema<?>) property.getSchema();
      if (!structSchema.isAnnotated()) {
        return;
      }

      // Adds a void $propName(Closure<?> cl) method that executes the closure
      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
              null);
      putThisOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEVIRTUAL,
          generatedType.getInternalName(),
          property.getGetters().get(0).getName(),
          Type.getMethodDescriptor(Type.getType(property.getType().getConcreteClass())),
          false);
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKESTATIC,
          Type.getInternalName(ClosureBackedAction.class),
          "execute",
          Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE, CLOSURE_TYPE),
          false);
      finishVisitingMethod(methodVisitor);
      return;
    }

    // Adds a void $propName(Closure<?> cl) method that throws MME, to avoid attempts to convert
    // closure to something else
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            property.getName(),
            Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
            null);
    putThisOnStack(methodVisitor);
    putConstantOnStack(methodVisitor, property.getName());
    methodVisitor.visitInsn(Opcodes.ICONST_1);
    methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, OBJECT_TYPE.getInternalName());
    methodVisitor.visitInsn(Opcodes.DUP);
    methodVisitor.visitInsn(Opcodes.ICONST_0);
    putFirstMethodArgumentOnStack(methodVisitor);
    methodVisitor.visitInsn(Opcodes.AASTORE);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        "methodMissing",
        METHOD_MISSING_METHOD_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor);
  }
  protected void injectConstructor(ClassWriter classWriter) {
    String resultName = getAccessorNameInternal(this.getTarget(), this.getAccessorType());

    MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    methodVisitor.visitCode();
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
    ;
    methodVisitor.visitTypeInsn(NEW, "java/util/ArrayList");
    methodVisitor.visitInsn(DUP);
    methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V", false);
    methodVisitor.visitVarInsn(ASTORE, 1);
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL, resultName, "getTargetClass", "()Ljava/lang/Class;", false);
    methodVisitor.visitVarInsn(ASTORE, 2);
    Label whileLoop = new Label(); // enter the "while (currentClass != Object.class)" loop
    methodVisitor.visitLabel(whileLoop);
    methodVisitor.visitFrame(
        Opcodes.F_FULL,
        3,
        new Object[] {resultName, "java/util/List", "java/lang/Class"},
        0,
        new Object[] {});
    methodVisitor.visitVarInsn(ALOAD, 2);
    methodVisitor.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
    Label classNotObjectComparer =
        new Label(); // compares the current class to Object.class aka currentClass != Object.class
    methodVisitor.visitJumpInsn(IF_ACMPEQ, classNotObjectComparer);
    methodVisitor.visitVarInsn(ALOAD, 2);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        "java/lang/Class",
        "getDeclaredFields",
        "()[Ljava/lang/reflect/Field;",
        false);
    methodVisitor.visitVarInsn(ASTORE, 3);
    methodVisitor.visitVarInsn(ALOAD, 3);
    methodVisitor.visitInsn(ARRAYLENGTH);
    methodVisitor.visitVarInsn(ISTORE, 4);
    methodVisitor.visitInsn(ICONST_0);
    methodVisitor.visitVarInsn(ISTORE, 5);
    Label cachingForLoop = new Label(); // this loop handles the storing of the fields (to the list)
    methodVisitor.visitLabel(cachingForLoop);
    methodVisitor.visitFrame(
        Opcodes.F_APPEND,
        3,
        new Object[] {"[Ljava/lang/reflect/Field;", Opcodes.INTEGER, Opcodes.INTEGER},
        0,
        null);
    methodVisitor.visitVarInsn(ILOAD, 5);
    methodVisitor.visitVarInsn(ILOAD, 4);
    Label cachingForLoopIncrementLabel = new Label(); // handles the looping of the fields
    methodVisitor.visitJumpInsn(IF_ICMPGE, cachingForLoopIncrementLabel);
    methodVisitor.visitVarInsn(ALOAD, 3);
    methodVisitor.visitVarInsn(ILOAD, 5);
    methodVisitor.visitInsn(AALOAD);
    methodVisitor.visitVarInsn(ASTORE, 6);
    methodVisitor.visitVarInsn(ALOAD, 1);
    methodVisitor.visitVarInsn(ALOAD, 6);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true);
    methodVisitor.visitInsn(POP);
    methodVisitor.visitIincInsn(5, 1);
    methodVisitor.visitJumpInsn(GOTO, cachingForLoop);
    methodVisitor.visitLabel(cachingForLoopIncrementLabel);
    methodVisitor.visitFrame(Opcodes.F_CHOP, 3, null, 0, null);
    methodVisitor.visitVarInsn(ALOAD, 2);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL, "java/lang/Class", "getSuperclass", "()Ljava/lang/Class;", false);
    methodVisitor.visitVarInsn(ASTORE, 2);
    methodVisitor.visitJumpInsn(GOTO, whileLoop);
    methodVisitor.visitLabel(classNotObjectComparer);
    methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitVarInsn(ALOAD, 1);
    methodVisitor.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "size", "()I", true);
    methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/reflect/Field");
    methodVisitor.visitFieldInsn(PUTFIELD, resultName, "fieldTable", "[Ljava/lang/reflect/Field;");
    methodVisitor.visitInsn(ICONST_0);
    methodVisitor.visitVarInsn(ISTORE, 3);
    Label storingForLoop =
        new Label(); // this for loop goes about storing the fields in the array defined in the
                     // class
    methodVisitor.visitLabel(storingForLoop);
    methodVisitor.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null);
    methodVisitor.visitVarInsn(ILOAD, 3);
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitFieldInsn(GETFIELD, resultName, "fieldTable", "[Ljava/lang/reflect/Field;");
    methodVisitor.visitInsn(ARRAYLENGTH);
    Label storage =
        new Label(); // gets the field at position x and stores it in the cache (fieldTable)
    methodVisitor.visitJumpInsn(IF_ICMPGE, storage);
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitFieldInsn(GETFIELD, resultName, "fieldTable", "[Ljava/lang/reflect/Field;");
    methodVisitor.visitVarInsn(ILOAD, 3);
    methodVisitor.visitVarInsn(ALOAD, 1);
    methodVisitor.visitVarInsn(ILOAD, 3);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;", true);
    methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/reflect/Field");
    methodVisitor.visitInsn(AASTORE);
    methodVisitor.visitIincInsn(3, 1);
    methodVisitor.visitJumpInsn(GOTO, storingForLoop);
    methodVisitor.visitLabel(storage);
    methodVisitor.visitFrame(Opcodes.F_CHOP, 1, null, 0, null);
    methodVisitor.visitInsn(RETURN);
    methodVisitor.visitMaxs(4, 7);
    methodVisitor.visitEnd();
  }