Handle getLambdaAccessMethod(Handle implMethod) { if (!implMethod.getOwner().equals(className)) { return implMethod; } if (Flags.hasFlag(classAccess, ACC_INTERFACE)) { // the method will be relocated to a companion class return implMethod; } // TODO: do not generate an access method if the impl method is not private (probably not // implementable with a single pass) String name = "access$lambda$" + lambdaAccessToImplMethods.size(); String desc = getLambdaAccessMethodDesc(implMethod); Handle accessMethod = new Handle(H_INVOKESTATIC, className, name, desc); lambdaAccessToImplMethods.put(accessMethod, implMethod); return accessMethod; }
@Override public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { Object key = Arrays.asList(name, desc); if (visitedMethods.contains(key)) return EMPTY_VISITOR; if (Modifier.isPrivate(access) || Modifier.isNative(access) || ((access & ACC_SYNTHETIC) != 0)) { // do not generate bytecode for private methods return EMPTY_VISITOR; } int accessFlags = access; visitedMethods.add(key); if ((objectDelegateMethods.contains(name) || delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) && !Modifier.isStatic(access) && !Modifier.isFinal(access)) { if (!GROOVYOBJECT_METHOD_NAMESS.contains(name)) { if (Modifier.isAbstract(access)) { // prevents the proxy from being abstract accessFlags -= ACC_ABSTRACT; } if (delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) { delegatedClosures.put(name, Boolean.TRUE); return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags); } if (generateDelegateField && objectDelegateMethods.contains(name)) { return makeDelegateCall(name, desc, signature, exceptions, accessFlags); } delegatedClosures.put(name, Boolean.TRUE); return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags); } } else if ("<init>".equals(name) && (Modifier.isPublic(access) || Modifier.isProtected(access))) { return createConstructor(access, name, desc, signature, exceptions); } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMESS.contains(name)) { accessFlags -= ACC_ABSTRACT; MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions); mv.visitCode(); Type[] args = Type.getArgumentTypes(desc); if (emptyBody) { Type returnType = Type.getReturnType(desc); if (returnType == Type.VOID_TYPE) { mv.visitInsn(RETURN); } else { int loadIns = getLoadInsn(returnType); switch (loadIns) { case ILOAD: mv.visitInsn(ICONST_0); break; case LLOAD: mv.visitInsn(LCONST_0); break; case FLOAD: mv.visitInsn(FCONST_0); break; case DLOAD: mv.visitInsn(DCONST_0); break; default: mv.visitInsn(ACONST_NULL); } mv.visitInsn(getReturnInsn(returnType)); mv.visitMaxs(2, registerLen(args) + 1); } } else { // for compatibility with the legacy proxy generator, we should throw an // UnsupportedOperationException // instead of an AbtractMethodException mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException"); mv.visitInsn(DUP); mv.visitMethodInsn( INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "()V"); mv.visitInsn(ATHROW); mv.visitMaxs(2, registerLen(args) + 1); } mv.visitEnd(); } return EMPTY_VISITOR; }