private void writeNonAbstractMethodWrapper(
      ClassVisitor visitor, Type generatedType, Class<?> managedTypeClass, Method method) {
    Label start = new Label();
    Label end = new Label();
    Label handler = new Label();

    MethodVisitor methodVisitor = declareMethod(visitor, method);

    methodVisitor.visitTryCatchBlock(start, end, handler, null);

    setCanCallSettersField(methodVisitor, generatedType, false);

    methodVisitor.visitLabel(start);
    invokeSuperMethod(methodVisitor, managedTypeClass, method);
    methodVisitor.visitLabel(end);

    setCanCallSettersField(methodVisitor, generatedType, true);
    methodVisitor.visitInsn(ARETURN);

    methodVisitor.visitLabel(handler);
    setCanCallSettersField(methodVisitor, generatedType, true);
    methodVisitor.visitInsn(ATHROW);

    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
  }
  private void writeSetter(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    WeaklyTypeReferencingMethod<?, Void> weakSetter = property.getSetter();
    // There is no setter for this property
    if (weakSetter == null) {
      return;
    }

    String propertyName = property.getName();
    Class<?> propertyClass = property.getType().getConcreteClass();
    Type propertyType = Type.getType(propertyClass);
    Label calledOutsideOfConstructor = new Label();

    Method setter = weakSetter.getMethod();

    // the regular typed setter
    String methodDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, propertyType);
    MethodVisitor methodVisitor =
        declareMethod(
            visitor, setter.getName(), methodDescriptor, AsmClassGeneratorUtils.signature(setter));

    putCanCallSettersFieldValueOnStack(methodVisitor, generatedType);
    jumpToLabelIfStackEvaluatesToTrue(methodVisitor, calledOutsideOfConstructor);
    throwExceptionBecauseCalledOnItself(methodVisitor);

    methodVisitor.visitLabel(calledOutsideOfConstructor);
    putStateFieldValueOnStack(methodVisitor, generatedType);
    putConstantOnStack(methodVisitor, propertyName);
    putFirstMethodArgumentOnStack(methodVisitor, propertyType);
    if (propertyClass.isPrimitive()) {
      boxType(methodVisitor, propertyClass);
    }
    invokeStateSetMethod(methodVisitor);

    finishVisitingMethod(methodVisitor);
  }
 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);
 }
 protected MethodVisitor makeDelegateToClosureCall(
     final String name,
     final String desc,
     final String signature,
     final String[] exceptions,
     final int accessFlags) {
   MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions);
   //        TraceMethodVisitor tmv = new TraceMethodVisitor(mv);
   //        mv = tmv;
   mv.visitCode();
   int stackSize = 0;
   // method body should be:
   //  this.$delegate$closure$methodName.call(new Object[] { method arguments })
   Type[] args = Type.getArgumentTypes(desc);
   int arrayStore = args.length + 1;
   BytecodeHelper.pushConstant(mv, args.length);
   mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); // stack size = 1
   stackSize = 1;
   int idx = 1;
   for (int i = 0; i < args.length; i++) {
     Type arg = args[i];
     mv.visitInsn(DUP); // stack size = 2
     BytecodeHelper.pushConstant(mv, i); // array index, stack size = 3
     stackSize = 3;
     // primitive types must be boxed
     if (isPrimitive(arg)) {
       mv.visitIntInsn(getLoadInsn(arg), idx);
       String wrappedType = getWrappedClassDescriptor(arg);
       mv.visitMethodInsn(
           INVOKESTATIC,
           wrappedType,
           "valueOf",
           "(" + arg.getDescriptor() + ")L" + wrappedType + ";");
     } else {
       mv.visitVarInsn(ALOAD, idx); // load argument i
     }
     idx += registerLen(arg);
     stackSize = Math.max(4, 3 + registerLen(arg));
     mv.visitInsn(AASTORE); // store value into array
   }
   mv.visitVarInsn(ASTORE, arrayStore); // store array
   int arrayIndex = arrayStore;
   mv.visitVarInsn(ALOAD, 0); // load this
   mv.visitFieldInsn(
       GETFIELD, proxyName, CLOSURES_MAP_FIELD, "Ljava/util/Map;"); // load closure map
   mv.visitLdcInsn(name); // load method name
   mv.visitMethodInsn(
       INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
   arrayStore++;
   mv.visitVarInsn(ASTORE, arrayStore);
   // if null, test if wildcard exists
   Label notNull = new Label();
   mv.visitIntInsn(ALOAD, arrayStore);
   mv.visitJumpInsn(IFNONNULL, notNull);
   mv.visitVarInsn(ALOAD, 0); // load this
   mv.visitFieldInsn(
       GETFIELD, proxyName, CLOSURES_MAP_FIELD, "Ljava/util/Map;"); // load closure map
   mv.visitLdcInsn("*"); // load wildcard
   mv.visitMethodInsn(
       INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
   mv.visitVarInsn(ASTORE, arrayStore);
   mv.visitLabel(notNull);
   mv.visitVarInsn(ALOAD, arrayStore);
   mv.visitMethodInsn(
       INVOKESTATIC,
       BytecodeHelper.getClassInternalName(this.getClass()),
       "ensureClosure",
       "(Ljava/lang/Object;)Lgroovy/lang/Closure;");
   mv.visitVarInsn(ALOAD, arrayIndex); // load argument array
   stackSize++;
   mv.visitMethodInsn(
       INVOKEVIRTUAL,
       "groovy/lang/Closure",
       "call",
       "([Ljava/lang/Object;)Ljava/lang/Object;"); // call closure
   unwrapResult(mv, desc);
   mv.visitMaxs(stackSize, arrayStore + 1);
   mv.visitEnd();
   //        System.out.println("tmv.getText() = " + tmv.getText());
   return EMPTY_VISITOR;
 }
  /**
   * When an object doesn't implement the GroovyObject interface, we generate bytecode for the
   * {@link GroovyObject} interface methods. Otherwise, the superclass is expected to implement
   * them.
   */
  private void createGroovyObjectSupport() {
    visitField(ACC_PRIVATE + ACC_TRANSIENT, "metaClass", "Lgroovy/lang/MetaClass;", null, null);

    // getMetaClass
    MethodVisitor mv;
    {
      mv = super.visitMethod(ACC_PUBLIC, "getMetaClass", "()Lgroovy/lang/MetaClass;", null, null);
      mv.visitCode();
      Label l0 = new Label();
      mv.visitLabel(l0);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, proxyName, "metaClass", "Lgroovy/lang/MetaClass;");
      Label l1 = new Label();
      mv.visitJumpInsn(IFNONNULL, l1);
      Label l2 = new Label();
      mv.visitLabel(l2);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
      mv.visitMethodInsn(
          INVOKESTATIC,
          "org/codehaus/groovy/runtime/InvokerHelper",
          "getMetaClass",
          "(Ljava/lang/Class;)Lgroovy/lang/MetaClass;");
      mv.visitFieldInsn(PUTFIELD, proxyName, "metaClass", "Lgroovy/lang/MetaClass;");
      mv.visitLabel(l1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, proxyName, "metaClass", "Lgroovy/lang/MetaClass;");
      mv.visitInsn(ARETURN);
      mv.visitMaxs(2, 1);
      mv.visitEnd();
    }

    // getProperty
    {
      mv =
          super.visitMethod(
              ACC_PUBLIC, "getProperty", "(Ljava/lang/String;)Ljava/lang/Object;", null, null);
      mv.visitCode();
      mv.visitIntInsn(ALOAD, 0);
      mv.visitMethodInsn(
          INVOKEINTERFACE, "groovy/lang/GroovyObject", "getMetaClass", "()Lgroovy/lang/MetaClass;");
      mv.visitIntInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          "groovy/lang/MetaClass",
          "getProperty",
          "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");
      mv.visitInsn(ARETURN);
      mv.visitMaxs(3, 2);
      mv.visitEnd();
    }

    // setProperty
    {
      mv =
          super.visitMethod(
              ACC_PUBLIC, "setProperty", "(Ljava/lang/String;Ljava/lang/Object;)V", null, null);
      mv.visitCode();
      Label l0 = new Label();
      mv.visitLabel(l0);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(INVOKEVIRTUAL, proxyName, "getMetaClass", "()Lgroovy/lang/MetaClass;");
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          "groovy/lang/MetaClass",
          "setProperty",
          "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");
      Label l1 = new Label();
      mv.visitLabel(l1);
      mv.visitInsn(RETURN);
      Label l2 = new Label();
      mv.visitLabel(l2);
      mv.visitMaxs(4, 3);
      mv.visitEnd();
    }

    // invokeMethod
    {
      mv =
          super.visitMethod(
              ACC_PUBLIC,
              "invokeMethod",
              "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;",
              null,
              null);
      Label l0 = new Label();
      mv.visitLabel(l0);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(INVOKEVIRTUAL, proxyName, "getMetaClass", "()Lgroovy/lang/MetaClass;");
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          "groovy/lang/MetaClass",
          "invokeMethod",
          "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
      mv.visitInsn(ARETURN);
      Label l1 = new Label();
      mv.visitLabel(l1);
      mv.visitMaxs(4, 3);
      mv.visitEnd();
    }

    // setMetaClass
    {
      mv = super.visitMethod(ACC_PUBLIC, "setMetaClass", "(Lgroovy/lang/MetaClass;)V", null, null);
      mv.visitCode();
      Label l0 = new Label();
      mv.visitLabel(l0);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitFieldInsn(PUTFIELD, proxyName, "metaClass", "Lgroovy/lang/MetaClass;");
      Label l1 = new Label();
      mv.visitLabel(l1);
      mv.visitInsn(RETURN);
      Label l2 = new Label();
      mv.visitLabel(l2);
      mv.visitMaxs(2, 2);
      mv.visitEnd();
    }
  }