/** Generate a call to the delegate object. */
  protected MethodVisitor makeDelegateCall(
      final String name,
      final String desc,
      final String signature,
      final String[] exceptions,
      final int accessFlags) {
    MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions);
    mv.visitVarInsn(ALOAD, 0); // load this
    mv.visitFieldInsn(
        GETFIELD,
        proxyName,
        DELEGATE_OBJECT_FIELD,
        BytecodeHelper.getTypeDescription(delegateClass)); // load delegate
    // using InvokerHelper to allow potential intercepted calls
    int size;
    mv.visitLdcInsn(name); // method name
    Type[] args = Type.getArgumentTypes(desc);
    BytecodeHelper.pushConstant(mv, args.length);
    mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
    size = 3;
    int idx = 1;
    for (int i = 0; i < args.length; i++) {
      Type arg = args[i];
      mv.visitInsn(DUP);
      BytecodeHelper.pushConstant(mv, i);
      // 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
      }
      size = Math.max(6, 5 + registerLen(arg));
      idx += registerLen(arg);
      mv.visitInsn(AASTORE); // store value into array
    }
    mv.visitMethodInsn(
        INVOKESTATIC,
        "org/codehaus/groovy/runtime/InvokerHelper",
        "invokeMethod",
        "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
    unwrapResult(mv, desc);
    mv.visitMaxs(size, registerLen(args) + 1);

    return EMPTY_VISITOR;
  }
 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;
 }