private static <T> void appendCellValue(
     CellSetter<T>[] setters, boolean ignoreException, ClassWriter cw, String classType) {
   MethodVisitor mv;
   mv = cw.visitMethod(ACC_PUBLIC, "cellValue", "([CIII)V", null, null);
   mv.visitCode();
   if (setters.length != 0) {
     if (ignoreException) {
       callCellValue(mv, classType);
     } else {
       Label l0 = new Label();
       Label l1 = new Label();
       Label l2 = new Label();
       mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
       mv.visitLabel(l0);
       callCellValue(mv, classType);
       mv.visitLabel(l1);
       Label l3 = new Label();
       mv.visitJumpInsn(GOTO, l3);
       mv.visitLabel(l2);
       mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Exception"});
       mv.visitVarInsn(ASTORE, 5);
       mv.visitVarInsn(ALOAD, 0);
       mv.visitVarInsn(ILOAD, 4);
       mv.visitVarInsn(ALOAD, 5);
       mv.visitMethodInsn(
           INVOKEVIRTUAL, classType, "fieldError", "(ILjava/lang/Exception;)V", false);
       mv.visitLabel(l3);
       mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
     }
   }
   mv.visitInsn(RETURN);
   mv.visitMaxs(5, 6);
   mv.visitEnd();
 }
 protected void injectGetIndex(ClassWriter classWriter) {
   MethodVisitor mv =
       classWriter.visitMethod(ACC_PRIVATE, "getIndex", "(Ljava/lang/String;)I", null, null);
   mv.visitCode();
   mv.visitInsn(ICONST_0);
   mv.visitVarInsn(ISTORE, 2);
   Label forLoopLabel = new Label();
   mv.visitLabel(forLoopLabel);
   mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null);
   mv.visitVarInsn(ILOAD, 2);
   mv.visitVarInsn(ALOAD, 0);
   mv.visitFieldInsn(
       GETFIELD,
       getAccessorNameInternal(this.getTarget(), this.getAccessorType()),
       "fieldTable",
       "[Ljava/lang/reflect/Field;");
   mv.visitInsn(ARRAYLENGTH);
   Label forLoopIncrementLabel = new Label();
   mv.visitJumpInsn(IF_ICMPGE, forLoopIncrementLabel);
   mv.visitVarInsn(ALOAD, 0);
   mv.visitFieldInsn(
       GETFIELD,
       getAccessorNameInternal(this.getTarget(), this.getAccessorType()),
       "fieldTable",
       "[Ljava/lang/reflect/Field;");
   mv.visitVarInsn(ILOAD, 2);
   mv.visitInsn(AALOAD);
   mv.visitMethodInsn(
       INVOKEVIRTUAL, "java/lang/reflect/Field", "getName", "()Ljava/lang/String;", false);
   mv.visitVarInsn(ALOAD, 1);
   mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
   Label equalsLabel = new Label();
   mv.visitJumpInsn(IFEQ, equalsLabel);
   mv.visitVarInsn(ILOAD, 2);
   mv.visitInsn(IRETURN);
   mv.visitLabel(equalsLabel);
   mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
   mv.visitIincInsn(2, 1);
   mv.visitJumpInsn(GOTO, forLoopLabel);
   mv.visitLabel(forLoopIncrementLabel);
   mv.visitFrame(Opcodes.F_CHOP, 1, null, 0, null);
   mv.visitInsn(ICONST_M1);
   mv.visitInsn(IRETURN);
   mv.visitMaxs(2, 3);
   mv.visitEnd();
 }
 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);
 }
 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);
 }
    @Override
    public void nodeDispatch(String suffix, int divide, int start, int end) {
      MethodVisitor mv;
      mv = cw.visitMethod(ACC_PRIVATE, name() + suffix, signature(), null, null);
      mv.visitCode();
      Label startLabel = new Label();
      mv.visitLabel(startLabel);
      final int powerOfTwo = Integer.numberOfTrailingZeros(divide);

      int sStart = start >> powerOfTwo;
      int sEnd = end >> powerOfTwo;

      int left = end - (sEnd << powerOfTwo);
      if (left > 0) {
        sEnd++;
      }

      Label[] labels = newLabels(sEnd - sStart);
      Label defaultLabel = new Label();

      mv.visitVarInsn(ILOAD, argIndex());

      int sub = leafStart();
      if (sub != 0) {
        AsmUtils.addIndex(mv, sub);
        mv.visitInsn(ISUB);
      }

      AsmUtils.addIndex(mv, powerOfTwo);
      mv.visitInsn(ISHR);

      mv.visitVarInsn(ISTORE, maxArgIndex() + 1);
      mv.visitVarInsn(ILOAD, maxArgIndex() + 1);
      mv.visitTableSwitchInsn(sStart, sEnd - 1, defaultLabel, labels);

      for (int i = sStart; i < sEnd; i++) {

        int estart = i << powerOfTwo;
        int eend = Math.min(end, (i + 1) << powerOfTwo);

        mv.visitLabel(labels[i - sStart]);
        if (i == start) {
          mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null);
        } else {
          mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        }

        loadArguments(mv);
        mv.visitMethodInsn(
            INVOKESPECIAL,
            classType,
            name() + (divide / maxMethodSize) + "n" + estart + "t" + eend,
            signature(),
            false);

        if (isVoid()) {
          if (i < (sEnd - 1)) {
            mv.visitJumpInsn(GOTO, defaultLabel);
          }
        } else {
          mv.visitInsn(ARETURN);
        }
      }

      mv.visitLabel(defaultLabel);
      mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);

      if (isVoid()) {
        mv.visitInsn(RETURN);
      } else {
        mv.visitInsn(ACONST_NULL);
        mv.visitInsn(ARETURN);
      }

      Label endLabel = new Label();
      mv.visitLabel(endLabel);
      appendDebugInfo(mv, startLabel, endLabel);
      mv.visitMaxs(6, 5);
      mv.visitEnd();
    }
 private void jumpToLabelIfStackEvaluatesToTrue(MethodVisitor methodVisitor, Label label) {
   methodVisitor.visitJumpInsn(IFNE, label);
 }
  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();
  }