/** 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; }
@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(); }