Repository: groovy Updated Branches: refs/heads/native-lambda 97649f9d1 -> b0aaa1ef9
Refine bytecode generation of native lambda Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/b0aaa1ef Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/b0aaa1ef Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/b0aaa1ef Branch: refs/heads/native-lambda Commit: b0aaa1ef96c7f56efb4e7b7099fb4d61381f6d53 Parents: 97649f9 Author: sunlan <[email protected]> Authored: Fri Jan 12 17:42:44 2018 +0800 Committer: sunlan <[email protected]> Committed: Fri Jan 12 17:42:44 2018 +0800 ---------------------------------------------------------------------- .../java/org/codehaus/groovy/ast/Parameter.java | 4 ++ .../groovy/classgen/asm/ClosureWriter.java | 4 +- .../asm/sc/StaticTypesLambdaWriter.java | 65 +++++++++++++++----- src/test/groovy/transform/stc/LambdaTest.groovy | 45 +++++++++++--- 4 files changed, 93 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/b0aaa1ef/src/main/java/org/codehaus/groovy/ast/Parameter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/Parameter.java b/src/main/java/org/codehaus/groovy/ast/Parameter.java index 1b22128..b2ddb09 100644 --- a/src/main/java/org/codehaus/groovy/ast/Parameter.java +++ b/src/main/java/org/codehaus/groovy/ast/Parameter.java @@ -123,4 +123,8 @@ public class Parameter extends AnnotatedNode implements Variable { public void setModifiers(int modifiers) { this.modifiers = modifiers; } + + public Expression getDefaultValue() { + return defaultValue; + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/b0aaa1ef/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java index 33ce035..d6e215d 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java @@ -185,7 +185,7 @@ public class ClosureWriter { ClassNode classNode = controller.getClassNode(); ClassNode outerClass = controller.getOutermostClass(); // MethodNode methodNode = controller.getMethodNode(); - String name = genInnerClassName(); + String name = genClosureClassName(); boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass(); Parameter[] parameters = expression.getParameters(); @@ -305,7 +305,7 @@ public class ClosureWriter { return answer; } - protected String genInnerClassName() { + private String genClosureClassName() { ClassNode classNode = controller.getClassNode(); ClassNode outerClass = controller.getOutermostClass(); MethodNode methodNode = controller.getMethodNode(); http://git-wip-us.apache.org/repos/asf/groovy/blob/b0aaa1ef/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java index 46cbe15..29c0e40 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java @@ -38,6 +38,7 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -98,9 +99,16 @@ public class StaticTypesLambdaWriter extends LambdaWriter { ACC_PUBLIC + ACC_FINAL + ACC_STATIC); MethodVisitor mv = controller.getMethodVisitor(); - ClassNode lambdaEnclosingClassNode = getOrAddLambdaClass(expression, ACC_PUBLIC); + ClassNode lambdaEnclosingClassNode = getOrAddLambdaClass(expression, ACC_PUBLIC, abstractMethodNode); MethodNode syntheticLambdaMethodNode = lambdaEnclosingClassNode.getMethods(DO_CALL).get(0); - String syntheticLambdaMethodDesc = BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode); + String syntheticLambdaMethodWithExactTypeDesc = BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode); + String syntheticLambdaMethodDesc = + BytecodeHelper.getMethodDescriptor( + abstractMethodNode.getReturnType().getTypeClass(), + Arrays.stream(abstractMethodNode.getParameters()) + .map(e -> e.getType().getTypeClass()) + .toArray(Class[]::new) + ); controller.getOperandStack().push(ClassHelper.OBJECT_TYPE); @@ -112,23 +120,26 @@ public class StaticTypesLambdaWriter extends LambdaWriter { "java/lang/invoke/LambdaMetafactory", "metafactory", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", - false), - new Object[] { + false + ), + new Object[]{ Type.getType(syntheticLambdaMethodDesc), new Handle( Opcodes.H_INVOKESTATIC, lambdaEnclosingClassNode.getName(), syntheticLambdaMethodNode.getName(), - syntheticLambdaMethodDesc, - false), - Type.getType(syntheticLambdaMethodDesc) - }); + syntheticLambdaMethodWithExactTypeDesc, + false + ), + Type.getType(syntheticLambdaMethodWithExactTypeDesc) + } + ); } - public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods) { + public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) { ClassNode lambdaClass = lambdaClassMap.get(expression); if (lambdaClass == null) { - lambdaClass = createLambdaClass(expression, mods); + lambdaClass = createLambdaClass(expression, mods, abstractMethodNode); lambdaClassMap.put(expression, lambdaClass); controller.getAcg().addInnerClass(lambdaClass); lambdaClass.addInterface(ClassHelper.GENERATED_LAMBDA_TYPE); @@ -137,10 +148,10 @@ public class StaticTypesLambdaWriter extends LambdaWriter { return lambdaClass; } - protected ClassNode createLambdaClass(LambdaExpression expression, int mods) { + protected ClassNode createLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) { ClassNode outerClass = controller.getOutermostClass(); ClassNode classNode = controller.getClassNode(); - String name = genInnerClassName(); + String name = genLambdaClassName(); boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass(); InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.LAMBDA_TYPE.getPlainNodeReference()); @@ -156,20 +167,42 @@ public class StaticTypesLambdaWriter extends LambdaWriter { answer.setScriptBody(true); } + Parameter[] parametersWithExactType = createParametersWithExactType(expression); // expression.getParameters(); + + MethodNode methodNode = + answer.addMethod(DO_CALL, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, abstractMethodNode.getReturnType(), parametersWithExactType, ClassNode.EMPTY_ARRAY, expression.getCode()); + methodNode.setSourcePosition(expression); + + return answer; + } + + private Parameter[] createParametersWithExactType(LambdaExpression expression) { Parameter[] parameters = expression.getParameters(); if (parameters == null) { parameters = Parameter.EMPTY_ARRAY; } - MethodNode methodNode = - answer.addMethod(DO_CALL, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode()); - methodNode.setSourcePosition(expression); + ClassNode[] blockParameterTypes = expression.getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.CLOSURE_ARGUMENTS); +// Parameter[] parametersWithExactType = new Parameter[parameters.length]; - return answer; + for (int i = 0; i < parameters.length; i++) { + parameters[i].setType(blockParameterTypes[i]); + parameters[i].setOriginType(blockParameterTypes[i]); + } + return parameters; } @Override protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) { return staticTypesClosureWriter.createClosureClass(expression, mods); } + + private String genLambdaClassName() { + ClassNode classNode = controller.getClassNode(); + ClassNode outerClass = controller.getOutermostClass(); + MethodNode methodNode = controller.getMethodNode(); + + return classNode.getName() + "$" + + controller.getContext().getNextLambdaInnerName(outerClass, classNode, methodNode); + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/b0aaa1ef/src/test/groovy/transform/stc/LambdaTest.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy index 0b9e189..e7ae05f 100644 --- a/src/test/groovy/transform/stc/LambdaTest.groovy +++ b/src/test/groovy/transform/stc/LambdaTest.groovy @@ -30,25 +30,56 @@ class LambdaTest extends GroovyTestCase { public class Test1 { public static void main(String[] args) { p1(); -// p2(); - // p3(); } public static void p1() { - assert [2, 3, 4] == Stream.of(1, 2, 3).map(e -> e + 1).collect(Collectors.toList()); + assert [2, 3, 4] == Stream.of(1, 2, 3).map(e -> e.plus 1).collect(Collectors.toList()); } + } + ''' + + } + + void testMethodCall2() { + if (true) return; + + // the test can pass only in dynamic mode now, it can not pass static type checking... + + assertScript ''' + import groovy.transform.CompileStatic + import java.util.stream.Collectors + import java.util.stream.Stream - /* + @CompileStatic + public class Test1 { + public static void main(String[] args) { + p2(); + } + public static void p2() { assert 13 == Stream.of(1, 2, 3).reduce(7, (r, e) -> r + e); } - */ + } + ''' + + } + + void testMethodCall3() { + assertScript ''' + import groovy.transform.CompileStatic + import java.util.stream.Collectors + import java.util.stream.Stream + + @CompileStatic + public class Test1 { + public static void main(String[] args) { + p3(); + } - /* public static void p3() { Stream.of(1, 2, 3).forEach(e -> { System.out.println(e + 1); }); } - */ + } '''
