Port native lambda to Java7 Just port its implementation and make the code can run on Java7, so when running on Java7, native lambda is still closure.
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/727c89a3 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/727c89a3 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/727c89a3 Branch: refs/heads/GROOVY_2_6_X Commit: 727c89a39d6360bb905eac36a68515a78aa78d9c Parents: af33df8 Author: danielsun1106 <realblue...@hotmail.com> Authored: Sun Feb 18 13:00:36 2018 +0800 Committer: danielsun1106 <realblue...@hotmail.com> Committed: Sun Feb 18 13:02:27 2018 +0800 ---------------------------------------------------------------------- .../codehaus/groovy/ast/CodeVisitorSupport.java | 5 ++ .../codehaus/groovy/ast/GroovyCodeVisitor.java | 4 +- .../groovy/classgen/asm/InvocationWriter.java | 16 +++-- .../asm/sc/StaticTypesLambdaWriter.java | 30 +++++---- .../customizers/SecureASTCustomizer.java | 6 ++ src/test/groovy/transform/stc/LambdaTest.groovy | 65 ++++++++++++++++++++ 6 files changed, 107 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java index 523475e..e0b003d 100644 --- a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java +++ b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java @@ -35,6 +35,7 @@ import org.codehaus.groovy.ast.expr.ElvisOperatorExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.expr.FieldExpression; import org.codehaus.groovy.ast.expr.GStringExpression; +import org.codehaus.groovy.ast.expr.LambdaExpression; import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.ast.expr.MapEntryExpression; import org.codehaus.groovy.ast.expr.MapExpression; @@ -227,6 +228,10 @@ public abstract class CodeVisitorSupport implements GroovyCodeVisitor { expression.getCode().visit(this); } + public void visitLambdaExpression(LambdaExpression expression) { + visitClosureExpression(expression); + } + public void visitTupleExpression(TupleExpression expression) { visitListOfExpressions(expression.getExpressions()); } http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java index db793cc..f2f8027 100644 --- a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java +++ b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java @@ -139,9 +139,7 @@ public interface GroovyCodeVisitor { void visitClosureExpression(ClosureExpression expression); - default void visitLambdaExpression(LambdaExpression expression) { - visitClosureExpression(expression); - } + void visitLambdaExpression(LambdaExpression expression); void visitTupleExpression(TupleExpression expression); http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java index 6ab3fd9..b9c5b62 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java @@ -32,6 +32,7 @@ import org.codehaus.groovy.ast.expr.ClassExpression; import org.codehaus.groovy.ast.expr.ConstantExpression; import org.codehaus.groovy.ast.expr.ConstructorCallExpression; import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.ExpressionTransformer; import org.codehaus.groovy.ast.expr.MethodCallExpression; import org.codehaus.groovy.ast.expr.PropertyExpression; import org.codehaus.groovy.ast.expr.SpreadExpression; @@ -528,13 +529,18 @@ public class InvocationWriter { ClassNode type = call.getObjectExpression().getType(); final MethodNode methodNode = ClassHelper.findSAM(type); - call = (MethodCallExpression) call.transformExpression(expression -> { - if (!(expression instanceof ConstantExpression)) { - return expression; - } + call = (MethodCallExpression) call.transformExpression(new ExpressionTransformer() { + @Override + public Expression transform(Expression expression) { + if (!(expression instanceof ConstantExpression)) { + return expression; + } - return new ConstantExpression(methodNode.getName()); + return new ConstantExpression(methodNode.getName()); + } }); + + call.setMethodTarget(methodNode); return call; } http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/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 ab45f9c..6184181 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 @@ -42,6 +42,7 @@ import org.codehaus.groovy.classgen.asm.WriterController; import org.codehaus.groovy.classgen.asm.WriterControllerFactory; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.transform.stc.StaticTypesMarker; +import org.codehaus.groovy.vmplugin.VMPluginFactory; import org.objectweb.asm.Handle; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -52,7 +53,6 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import static org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_LAMBDA_TYPE; import static org.codehaus.groovy.transform.stc.StaticTypesMarker.PARAMETER_TYPE; @@ -78,6 +78,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter { public static final String IS_GENERATED_CONSTRUCTOR = "__IS_GENERATED_CONSTRUCTOR"; public static final String LAMBDA_WRAPPER = "__lambda_wrapper"; public static final String SAM_NAME = "__SAM_NAME"; + private static final boolean PRE_JAVA8 = VMPluginFactory.getPlugin().getVersion() < 8; private StaticTypesClosureWriter staticTypesClosureWriter; private WriterController controller; private WriterControllerFactory factory; @@ -98,8 +99,8 @@ public class StaticTypesLambdaWriter extends LambdaWriter { public void writeLambda(LambdaExpression expression) { ClassNode lambdaType = getLambdaType(expression); - if (!ClassHelper.isFunctionalInterface(lambdaType.redirect())) { - // if the parameter type is not real FunctionInterface, generate the default bytecode, which is actually a closure + if (PRE_JAVA8 || !ClassHelper.isFunctionalInterface(lambdaType.redirect())) { + // if running on pre8 JVM or the parameter type is not real FunctionInterface, generate the default bytecode, which is actually a closure super.writeLambda(expression); return; } @@ -203,10 +204,14 @@ public class StaticTypesLambdaWriter extends LambdaWriter { loadSharedVariables(syntheticLambdaMethodNode); - List<ConstructorNode> constructorNodeList = - lambdaWrapperClassNode.getDeclaredConstructors().stream() - .filter(e -> Boolean.TRUE.equals(e.getNodeMetaData(IS_GENERATED_CONSTRUCTOR))) - .collect(Collectors.toList()); + List<ConstructorNode> constructorNodeList = new LinkedList<>(); + for (ConstructorNode e : lambdaWrapperClassNode.getDeclaredConstructors()) { + if (!Boolean.TRUE.equals(e.getNodeMetaData(IS_GENERATED_CONSTRUCTOR))) { + continue; + } + + constructorNodeList.add(e); + } if (constructorNodeList.size() == 0) { throw new GroovyBugError("Failed to find the generated constructor"); @@ -268,16 +273,19 @@ public class StaticTypesLambdaWriter extends LambdaWriter { BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode), lambdaClassNode.isInterface() ), - Type.getType(BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode.getReturnType(), syntheticLambdaMethodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE))) + Type.getType(BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode.getReturnType(), (Parameter[]) syntheticLambdaMethodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE))) }; } private String createMethodDescriptor(MethodNode abstractMethodNode) { + List<Class> typeClassList = new LinkedList<>(); + for (Parameter e : abstractMethodNode.getParameters()) { + typeClassList.add(e.getType().getTypeClass()); + } + return BytecodeHelper.getMethodDescriptor( abstractMethodNode.getReturnType().getTypeClass(), - Arrays.stream(abstractMethodNode.getParameters()) - .map(e -> e.getType().getTypeClass()) - .toArray(Class[]::new) + typeClassList.toArray(new Class[0]) ); } http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java index 1bb302b..c839e7e 100644 --- a/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java +++ b/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java @@ -42,6 +42,7 @@ import org.codehaus.groovy.ast.expr.ElvisOperatorExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.expr.FieldExpression; import org.codehaus.groovy.ast.expr.GStringExpression; +import org.codehaus.groovy.ast.expr.LambdaExpression; import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.ast.expr.MapEntryExpression; import org.codehaus.groovy.ast.expr.MapExpression; @@ -989,6 +990,11 @@ public class SecureASTCustomizer extends CompilationCustomizer { expression.getCode().visit(this); } + @Override + public void visitLambdaExpression(LambdaExpression expression) { + visitClosureExpression(expression); + } + public void visitTupleExpression(final TupleExpression expression) { assertExpressionAuthorized(expression); visitListOfExpressions(expression.getExpressions()); http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/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 a24e3c1..0e2345f 100644 --- a/src/test/groovy/transform/stc/LambdaTest.groovy +++ b/src/test/groovy/transform/stc/LambdaTest.groovy @@ -19,10 +19,15 @@ package groovy.transform.stc +import org.codehaus.groovy.vmplugin.VMPluginFactory + class LambdaTest extends GroovyTestCase { private static final boolean SKIP_ERRORS = true; + private static final boolean PRE_JAVA8 = VMPluginFactory.getPlugin().getVersion() < 8; void testFunction() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -42,6 +47,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionScript() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -57,6 +64,8 @@ class LambdaTest extends GroovyTestCase { } void testBinaryOperator() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -76,6 +85,8 @@ class LambdaTest extends GroovyTestCase { } void testConsumer() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -96,6 +107,8 @@ class LambdaTest extends GroovyTestCase { } void testPredicate() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -117,6 +130,8 @@ class LambdaTest extends GroovyTestCase { } void testUnaryOperator() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -138,6 +153,8 @@ class LambdaTest extends GroovyTestCase { } void testBiConsumer() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -158,6 +175,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithLocalVariables() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -179,6 +198,8 @@ class LambdaTest extends GroovyTestCase { void testFunctionWithLocalVariables2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -200,6 +221,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithLocalVariables4() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -221,6 +244,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithStaticMethodCall() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -246,6 +271,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithStaticMethodCall2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -271,6 +298,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithInstanceMethodCall() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -294,6 +323,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionInConstructor() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -317,6 +348,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithInstanceMethodCall2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -340,6 +373,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithInstanceMethodCall3() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -363,6 +398,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionCall() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -384,6 +421,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionCall2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -405,6 +444,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionCall3() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -426,6 +467,8 @@ class LambdaTest extends GroovyTestCase { } void testConsumerCall() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -449,6 +492,8 @@ class LambdaTest extends GroovyTestCase { } void testConsumerCall2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -472,6 +517,8 @@ class LambdaTest extends GroovyTestCase { } void testConsumerCall3() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -495,6 +542,8 @@ class LambdaTest extends GroovyTestCase { } void testSamCall() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -520,6 +569,8 @@ class LambdaTest extends GroovyTestCase { } void testSamCall2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -545,6 +596,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithUpdatingLocalVariable() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -566,6 +619,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithUpdatingLocalVariable2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -587,6 +642,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithVariableDeclaration() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -609,6 +666,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithMixingVariableDeclarationAndMethodInvocation() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -637,6 +696,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithNestedLambda() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -664,6 +725,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithNestedLambda2() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors @@ -689,6 +752,8 @@ class LambdaTest extends GroovyTestCase { } void testFunctionWithNestedLambda3() { + if (PRE_JAVA8) return; + assertScript ''' import groovy.transform.CompileStatic import java.util.stream.Collectors