Repository: groovy Updated Branches: refs/heads/native-lambda 4172bd764 -> 083089fc3
Minor refactoring Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/083089fc Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/083089fc Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/083089fc Branch: refs/heads/native-lambda Commit: 083089fc35405379c4a4f27fa1d3123eb396dc67 Parents: 4172bd7 Author: sunlan <[email protected]> Authored: Sat Jan 13 00:18:00 2018 +0800 Committer: sunlan <[email protected]> Committed: Sat Jan 13 00:18:00 2018 +0800 ---------------------------------------------------------------------- .../asm/sc/StaticTypesLambdaWriter.java | 123 +++++++++++-------- src/test/groovy/transform/stc/LambdaTest.groovy | 17 +++ 2 files changed, 86 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/083089fc/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 c847c33..bdf10d8 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 @@ -31,8 +31,8 @@ import org.codehaus.groovy.classgen.asm.BytecodeHelper; import org.codehaus.groovy.classgen.asm.LambdaWriter; import org.codehaus.groovy.classgen.asm.WriterController; import org.codehaus.groovy.classgen.asm.WriterControllerFactory; +import org.codehaus.groovy.transform.stc.StaticTypesMarker; import org.objectweb.asm.Handle; -import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -77,50 +77,61 @@ public class StaticTypesLambdaWriter extends LambdaWriter { .collect(Collectors.toList()); if (!(isFunctionInterface(parameterType) && abstractMethodNodeList.size() == 1)) { + // if the parameter type is not real FunctionInterface, generate the default bytecode, which is actually a closure super.writeLambda(expression); return; } MethodNode abstractMethodNode = abstractMethodNodeList.get(0); - String abstractMethodName = abstractMethodNode.getName(); - String abstractMethodDesc = "()L" + parameterType.redirect().getPackageName().replace('.', '/') + "/" + parameterType.redirect().getNameWithoutPackage() + ";"; + String abstractMethodDesc = createMethodDescriptor(abstractMethodNode); - - MethodVisitor mv = controller.getMethodVisitor(); - ClassNode lambdaEnclosingClassNode = getOrAddLambdaClass(expression, ACC_PUBLIC, abstractMethodNode); - MethodNode syntheticLambdaMethodNode = lambdaEnclosingClassNode.getMethods(DO_CALL).get(0); + ClassNode lambdaClassNode = getOrAddLambdaClass(expression, ACC_PUBLIC); + MethodNode syntheticLambdaMethodNode = lambdaClassNode.getMethods(DO_CALL).get(0); 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); - - mv.visitInvokeDynamicInsn( - abstractMethodName, - abstractMethodDesc, + + controller.getOperandStack().push(parameterType.redirect()); + controller.getMethodVisitor().visitInvokeDynamicInsn( + abstractMethodNode.getName(), + createAbstractMethodDesc(parameterType), + createBootstrapMethod(), + createBootstrapMethodArguments(abstractMethodDesc, lambdaClassNode, syntheticLambdaMethodNode, syntheticLambdaMethodWithExactTypeDesc) + ); + } + + private String createAbstractMethodDesc(ClassNode parameterType) { + return "()L" + parameterType.redirect().getPackageName().replace('.', '/') + "/" + parameterType.redirect().getNameWithoutPackage() + ";"; + } + + private Handle createBootstrapMethod() { + return new Handle( + Opcodes.H_INVOKESTATIC, + "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 + ); + } + + private Object[] createBootstrapMethodArguments(String abstractMethodDesc, ClassNode lambdaClassNode, MethodNode syntheticLambdaMethodNode, String syntheticLambdaMethodWithExactTypeDesc) { + return new Object[]{ + Type.getType(abstractMethodDesc), new Handle( Opcodes.H_INVOKESTATIC, - "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;", + lambdaClassNode.getName(), + syntheticLambdaMethodNode.getName(), + syntheticLambdaMethodWithExactTypeDesc, false ), - new Object[]{ - Type.getType(syntheticLambdaMethodDesc), - new Handle( - Opcodes.H_INVOKESTATIC, - lambdaEnclosingClassNode.getName(), - syntheticLambdaMethodNode.getName(), - syntheticLambdaMethodWithExactTypeDesc, - false - ), - Type.getType(syntheticLambdaMethodWithExactTypeDesc) - } + Type.getType(syntheticLambdaMethodWithExactTypeDesc) + }; + } + + private String createMethodDescriptor(MethodNode abstractMethodNode) { + return BytecodeHelper.getMethodDescriptor( + abstractMethodNode.getReturnType().getTypeClass(), + Arrays.stream(abstractMethodNode.getParameters()) + .map(e -> e.getType().getTypeClass()) + .toArray(Class[]::new) ); } @@ -128,10 +139,10 @@ public class StaticTypesLambdaWriter extends LambdaWriter { return parameterType.redirect().isInterface() && !parameterType.redirect().getAnnotations(ClassHelper.FunctionalInterface_Type).isEmpty(); } - public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) { + public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods) { ClassNode lambdaClass = lambdaClassMap.get(expression); if (lambdaClass == null) { - lambdaClass = createLambdaClass(expression, mods, abstractMethodNode); + lambdaClass = createLambdaClass(expression, mods); lambdaClassMap.put(expression, lambdaClass); controller.getAcg().addInnerClass(lambdaClass); lambdaClass.addInterface(ClassHelper.GENERATED_LAMBDA_TYPE); @@ -140,7 +151,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter { return lambdaClass; } - protected ClassNode createLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) { + protected ClassNode createLambdaClass(LambdaExpression expression, int mods) { ClassNode outerClass = controller.getOutermostClass(); ClassNode classNode = controller.getClassNode(); String name = genLambdaClassName(); @@ -159,13 +170,27 @@ public class StaticTypesLambdaWriter extends LambdaWriter { answer.setScriptBody(true); } + addSyntheticLambdaMethodNode(expression, answer); + + return answer; + } + + private String genLambdaClassName() { + ClassNode classNode = controller.getClassNode(); + ClassNode outerClass = controller.getOutermostClass(); + MethodNode methodNode = controller.getMethodNode(); + + return classNode.getName() + "$" + + controller.getContext().getNextLambdaInnerName(outerClass, classNode, methodNode); + } + + private void addSyntheticLambdaMethodNode(LambdaExpression expression, InnerClassNode answer) { Parameter[] parametersWithExactType = createParametersWithExactType(expression); // expression.getParameters(); + ClassNode returnType = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); //abstractMethodNode.getReturnType(); MethodNode methodNode = - answer.addMethod(DO_CALL, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, abstractMethodNode.getReturnType(), parametersWithExactType, ClassNode.EMPTY_ARRAY, expression.getCode()); + answer.addMethod(DO_CALL, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, returnType, parametersWithExactType, ClassNode.EMPTY_ARRAY, expression.getCode()); methodNode.setSourcePosition(expression); - - return answer; } private Parameter[] createParametersWithExactType(LambdaExpression expression) { @@ -174,13 +199,12 @@ public class StaticTypesLambdaWriter extends LambdaWriter { parameters = Parameter.EMPTY_ARRAY; } - ClassNode[] blockParameterTypes = expression.getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.CLOSURE_ARGUMENTS); -// Parameter[] parametersWithExactType = new Parameter[parameters.length]; - for (int i = 0; i < parameters.length; i++) { - parameters[i].setType(blockParameterTypes[i]); - parameters[i].setOriginType(blockParameterTypes[i]); + ClassNode inferredType = parameters[i].getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + parameters[i].setType(inferredType); + parameters[i].setOriginType(inferredType); } + return parameters; } @@ -188,13 +212,4 @@ public class StaticTypesLambdaWriter extends LambdaWriter { 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/083089fc/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 db4aa36..700f9cd 100644 --- a/src/test/groovy/transform/stc/LambdaTest.groovy +++ b/src/test/groovy/transform/stc/LambdaTest.groovy @@ -39,6 +39,23 @@ class LambdaTest extends GroovyTestCase { ''' } + /* + void testFunction2() { + assertScript ''' + import groovy.transform.CompileStatic + import java.util.stream.Collectors + import java.util.stream.Stream + + @CompileStatic + void p() { + assert [2, 3, 4] == Stream.of(1, 2, 3).map(e -> e.plus 1).collect(Collectors.toList()); + } + + p() + ''' + } + */ + void testBinaryOperator() { if (true) return;
