Repository: groovy Updated Branches: refs/heads/native-lambda b6ea72dbf -> fb8e3d10b
Add missing `ALOAD` to fix generating bytecode Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/fb8e3d10 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/fb8e3d10 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/fb8e3d10 Branch: refs/heads/native-lambda Commit: fb8e3d10b9bcce46ebb474657d67036b14c2bffc Parents: b6ea72d Author: sunlan <[email protected]> Authored: Mon Jan 15 15:35:13 2018 +0800 Committer: sunlan <[email protected]> Committed: Mon Jan 15 15:35:13 2018 +0800 ---------------------------------------------------------------------- .../groovy/classgen/asm/ClosureWriter.java | 2 +- .../asm/sc/StaticTypesLambdaWriter.java | 94 ++++++++++++++++++-- src/test/groovy/transform/stc/LambdaTest.groovy | 88 ++++++------------ 3 files changed, 113 insertions(+), 71 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/fb8e3d10/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 d6e215d..429fe3b 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java @@ -338,7 +338,7 @@ public class ClosureWriter { * same method, in this case the constructor. A closure should not * have more than one constructor! */ - private static void removeInitialValues(Parameter[] params) { + protected static void removeInitialValues(Parameter[] params) { for (int i = 0; i < params.length; i++) { if (params[i].hasInitialExpression()) { Parameter p = new Parameter(params[i].getType(), params[i].getName()); http://git-wip-us.apache.org/repos/asf/groovy/blob/fb8e3d10/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 e91e777..99c0215 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 @@ -19,6 +19,8 @@ package org.codehaus.groovy.classgen.asm.sc; +import org.codehaus.groovy.GroovyBugError; +import org.codehaus.groovy.ast.ClassCodeVisitorSupport; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.InnerClassNode; @@ -27,12 +29,16 @@ import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.expr.ClosureExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.expr.LambdaExpression; +import org.codehaus.groovy.ast.expr.VariableExpression; import org.codehaus.groovy.classgen.asm.BytecodeHelper; import org.codehaus.groovy.classgen.asm.LambdaWriter; +import org.codehaus.groovy.classgen.asm.OperandStack; 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.objectweb.asm.Handle; +import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -45,6 +51,7 @@ import java.util.stream.Stream; import static org.codehaus.groovy.classgen.asm.sc.StaticInvocationWriter.PARAMETER_TYPE; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ALOAD; /** * Writer responsible for generating lambda classes in statically compiled mode. @@ -53,7 +60,7 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC; public class StaticTypesLambdaWriter extends LambdaWriter { public static final String DO_CALL = "doCall"; public static final String ORIGINAL_PARAMETERS_WITH_EXACT_TYPE = "__ORIGINAL_PARAMETERS_WITH_EXACT_TYPE"; - public static final String LAMBDA_SHARED_VARIABLES = "_LAMBDA_SHARED_VARIABLES"; + public static final String LAMBDA_SHARED_VARIABLES = "__LAMBDA_SHARED_VARIABLES"; private StaticTypesClosureWriter staticTypesClosureWriter; private WriterController controller; private WriterControllerFactory factory; @@ -91,9 +98,18 @@ public class StaticTypesLambdaWriter extends LambdaWriter { ClassNode lambdaClassNode = getOrAddLambdaClass(expression, ACC_PUBLIC); MethodNode syntheticLambdaMethodNode = lambdaClassNode.getMethods(DO_CALL).get(0); + MethodVisitor mv = controller.getMethodVisitor(); + OperandStack operandStack = controller.getOperandStack(); - controller.getOperandStack().push(parameterType.redirect()); - controller.getMethodVisitor().visitInvokeDynamicInsn( + Parameter[] lambdaSharedVariableParameters = syntheticLambdaMethodNode.getNodeMetaData(LAMBDA_SHARED_VARIABLES); + for (int i = 0; i < lambdaSharedVariableParameters.length; i++) { + mv.visitVarInsn(ALOAD, i); + operandStack.doGroovyCast(lambdaSharedVariableParameters[i].getType().redirect()); +// operandStack.push(lambdaSharedVariableParameters[i].getType().redirect()); + } + + operandStack.push(parameterType.redirect()); + mv.visitInvokeDynamicInsn( abstractMethodNode.getName(), createAbstractMethodDesc(syntheticLambdaMethodNode, parameterType), createBootstrapMethod(), @@ -193,15 +209,40 @@ public class StaticTypesLambdaWriter extends LambdaWriter { private void addSyntheticLambdaMethodNode(LambdaExpression expression, InnerClassNode answer) { Parameter[] parametersWithExactType = createParametersWithExactType(expression); // expression.getParameters(); ClassNode returnType = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); //abstractMethodNode.getReturnType(); - Parameter[] lambdaSharedVariables = getLambdaSharedVariables(expression); - Parameter[] methodParameter = Stream.concat(Arrays.stream(lambdaSharedVariables), Arrays.stream(parametersWithExactType)).toArray(Parameter[]::new); + Parameter[] localVariableParameters = getLambdaSharedVariables(expression); + removeInitialValues(localVariableParameters); + Parameter[] methodParameter = Stream.concat(Arrays.stream(localVariableParameters), Arrays.stream(parametersWithExactType)).toArray(Parameter[]::new); MethodNode methodNode = - answer.addMethod(DO_CALL, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, returnType, methodParameter, ClassNode.EMPTY_ARRAY, expression.getCode()); + answer.addMethod( + DO_CALL, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, + returnType, + methodParameter, + ClassNode.EMPTY_ARRAY, + expression.getCode() + ); methodNode.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType); - methodNode.putNodeMetaData(LAMBDA_SHARED_VARIABLES, lambdaSharedVariables); + methodNode.putNodeMetaData(LAMBDA_SHARED_VARIABLES, localVariableParameters); methodNode.setSourcePosition(expression); + + + LocalVariableReplacementVisitor localVariableReplacementVisitor = new LocalVariableReplacementVisitor(methodNode); + + localVariableReplacementVisitor.visitMethod(methodNode); + +// System.out.println(methodNode); + + /* + VariableScope varScope = expression.getVariableScope(); + if (varScope == null) { + throw new RuntimeException( + "Must have a VariableScope by now! for expression: " + expression + " class: " + answer.getName()); + } else { + methodNode.setVariableScope(varScope.copy()); + } + */ } private Parameter[] createParametersWithExactType(LambdaExpression expression) { @@ -223,4 +264,43 @@ public class StaticTypesLambdaWriter extends LambdaWriter { protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) { return staticTypesClosureWriter.createClosureClass(expression, mods); } + + private static final class LocalVariableReplacementVisitor extends ClassCodeVisitorSupport { + private MethodNode methodNode; + + public LocalVariableReplacementVisitor(MethodNode methodNode) { + this.methodNode = methodNode; + } + + @Override + protected SourceUnit getSourceUnit() { + return null; + } + + @Override + public void visitVariableExpression(VariableExpression expression) { + if (expression.isClosureSharedVariable()) { + final String variableName = expression.getName(); +// System.out.println(">>>>>>>>>>>>>>>>>>>>>>\n"); +// System.out.println("1, " + variableName + ":" + expression.isClosureSharedVariable() + "::" + expression.getAccessedVariable()); + Parameter[] parametersWithSameVariableName = + Arrays.stream(methodNode.getParameters()) + .filter(e -> variableName.equals(e.getName())) + .toArray(Parameter[]::new); + + if (parametersWithSameVariableName.length != 1) { + throw new GroovyBugError(parametersWithSameVariableName.length + " parameters with same name " + variableName + " found(Expect only one matched)."); + } +// System.out.println("2, " + variableName + ":" + parametersWithSameVariableName[0]); + + expression.setAccessedVariable(parametersWithSameVariableName[0]); + expression.setClosureSharedVariable(false); + +// System.out.println("<<<<<<<<<<<<<<<<<<<<<<\n"); + + } + + super.visitVariableExpression(expression); + } + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/fb8e3d10/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 73ba540..dbd789a 100644 --- a/src/test/groovy/transform/stc/LambdaTest.groovy +++ b/src/test/groovy/transform/stc/LambdaTest.groovy @@ -199,69 +199,8 @@ TestScript0.groovy: 14: [Static type checking] - Cannot find matching method jav if (true) return // FIXME - /* -General error during class generation: ASM reporting processing error for Test1#p with signature void p() in TestScript0.groovy:12. TestScript0.groovy - -groovy.lang.GroovyRuntimeException: ASM reporting processing error for Test1#p with signature void p() in TestScript0.groovy:12. TestScript0.groovy - at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:447) - at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:132) - at org.codehaus.groovy.classgen.AsmClassGenerator.visitMethod(AsmClassGenerator.java:568) - at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1095) - at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:54) - at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:261) - at org.codehaus.groovy.control.CompilationUnit$18.call(CompilationUnit.java:853) - at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1092) - at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:634) - at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:612) - at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:589) - at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:359) - at groovy.lang.GroovyClassLoader.access$300(GroovyClassLoader.java:92) - at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:328) - at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:325) - at org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache.getAndPut(ConcurrentCommonCache.java:138) - at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:323) - at groovy.lang.GroovyShell.parseClass(GroovyShell.java:548) - at groovy.lang.GroovyShell.parse(GroovyShell.java:560) - at groovy.lang.GroovyShell.evaluate(GroovyShell.java:444) - at groovy.lang.GroovyShell.evaluate(GroovyShell.java:483) - at groovy.lang.GroovyShell.evaluate(GroovyShell.java:464) - at groovy.test.GroovyAssert.assertScript(GroovyAssert.java:83) - at groovy.util.GroovyTestCase.assertScript(GroovyTestCase.java:203) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210) - at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59) - at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) - at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157) - at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:169) - at groovy.transform.stc.LambdaTest.testFunctionWithLocalVariables(LambdaTest.groovy:203) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at junit.framework.TestCase.runTest(TestCase.java:176) - at junit.framework.TestCase.runBare(TestCase.java:141) - at junit.framework.TestResult$1.protect(TestResult.java:122) - at junit.framework.TestResult.runProtected(TestResult.java:142) - at junit.framework.TestResult.run(TestResult.java:125) - at junit.framework.TestCase.run(TestCase.java:129) - at junit.framework.TestSuite.runTest(TestSuite.java:252) - at junit.framework.TestSuite.run(TestSuite.java:247) - at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86) - at org.junit.runner.JUnitCore.run(JUnitCore.java:137) - at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) - at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) - at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) - at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) -Caused by: java.lang.ArrayIndexOutOfBoundsException: -1 - at org.objectweb.asm.Frame.merge(Frame.java:1501) - at org.objectweb.asm.Frame.merge(Frame.java:1478) - at org.objectweb.asm.MethodWriter.visitMaxs(MethodWriter.java:1497) - at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:428) - ... 51 more - + /* What we expect is '#1', '#2', '#3' +[groovy.lang.Reference@46d63dbb1, groovy.lang.Reference@46d63dbb2, groovy.lang.Reference@46d63dbb3] */ assertScript ''' @@ -282,4 +221,27 @@ Caused by: java.lang.ArrayIndexOutOfBoundsException: -1 } ''' } + + /* + void testLabs() { + + 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) { + p(); + } + + public static void p() { + String x = "#" + System.out.println(Stream.of(1, 2, 3).map(e -> x + e).collect(Collectors.toList())); + } + } + ''' + } + */ }
