This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push: new f682375 minor refactor f682375 is described below commit f682375eab8f75d41781a6e5e9ce8815ab7836dd Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Wed Dec 18 17:13:29 2019 -0600 minor refactor --- .../groovy/classgen/asm/ClosureWriter.java | 76 ++--- .../codehaus/groovy/classgen/asm/LambdaWriter.java | 9 +- .../classgen/asm/sc/StaticTypesLambdaWriter.java | 371 +++++++++------------ .../codehaus/groovy/control/CompilationUnit.java | 2 +- 4 files changed, 197 insertions(+), 261 deletions(-) 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 4b6cfc9..7156dd9 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java @@ -70,17 +70,14 @@ public class ClosureWriter { protected interface UseExistingReference {} - private final Map<Expression,ClassNode> closureClassMap; - private final WriterController controller; - private final WriterControllerFactory factory; - - public ClosureWriter(WriterController wc) { - this.controller = wc; - closureClassMap = new HashMap<Expression,ClassNode>(); - factory = normalController -> controller; + protected final WriterController controller; + private final Map<Expression,ClassNode> closureClasses = new HashMap<>(); + + public ClosureWriter(final WriterController controller) { + this.controller = controller; } - public void writeClosure(ClosureExpression expression) { + public void writeClosure(final ClosureExpression expression) { CompileStack compileStack = controller.getCompileStack(); MethodVisitor mv = controller.getMethodVisitor(); ClassNode classNode = controller.getClassNode(); @@ -94,8 +91,8 @@ public class ClosureWriter { } ClassNode closureClass = getOrAddClosureClass(expression, mods); String closureClassinternalName = BytecodeHelper.getClassInternalName(closureClass); - List constructors = closureClass.getDeclaredConstructors(); - ConstructorNode node = (ConstructorNode) constructors.get(0); + List<ConstructorNode> constructors = closureClass.getDeclaredConstructors(); + ConstructorNode node = constructors.get(0); Parameter[] localVariableParams = node.getParameters(); @@ -128,13 +125,13 @@ public class ClosureWriter { mv.visitMethodInsn(INVOKESPECIAL, closureClassinternalName, "<init>", BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, localVariableParams), false); controller.getOperandStack().replace(ClassHelper.CLOSURE_TYPE, localVariableParams.length); } - - public static void loadReference(String name, WriterController controller) { + + public static void loadReference(final String name, final WriterController controller) { CompileStack compileStack = controller.getCompileStack(); MethodVisitor mv = controller.getMethodVisitor(); ClassNode classNode = controller.getClassNode(); AsmClassGenerator acg = controller.getAcg(); - + // compileStack.containsVariable(name) means to ask if the variable is already declared // compileStack.getScope().isReferencedClassVariable(name) means to ask if the variable is a field // If it is no field and is not yet declared, then it is either a closure shared variable or @@ -158,19 +155,19 @@ public class ClosureWriter { } } - public ClassNode getOrAddClosureClass(ClosureExpression expression, int mods) { - ClassNode closureClass = closureClassMap.get(expression); + public ClassNode getOrAddClosureClass(final ClosureExpression expression, final int modifiers) { + ClassNode closureClass = closureClasses.get(expression); if (closureClass == null) { - closureClass = createClosureClass(expression, mods); - closureClassMap.put(expression, closureClass); + closureClass = createClosureClass(expression, modifiers); + closureClasses.put(expression, closureClass); controller.getAcg().addInnerClass(closureClass); closureClass.addInterface(ClassHelper.GENERATED_CLOSURE_Type); - closureClass.putNodeMetaData(WriterControllerFactory.class, factory); + closureClass.putNodeMetaData(WriterControllerFactory.class, (WriterControllerFactory) x -> controller); } return closureClass; } - private static boolean classNodeUsesReferences(ClassNode classNode) { + private static boolean classNodeUsesReferences(final ClassNode classNode) { boolean ret = classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE; if (ret) return ret; if (classNode instanceof InnerClassNode) { @@ -179,11 +176,10 @@ public class ClosureWriter { } return false; } - - protected ClassNode createClosureClass(ClosureExpression expression, int mods) { + + protected ClassNode createClosureClass(final ClosureExpression expression, final int modifiers) { ClassNode classNode = controller.getClassNode(); ClassNode outerClass = controller.getOutermostClass(); -// MethodNode methodNode = controller.getMethodNode(); String name = genClosureClassName(); boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass(); @@ -201,7 +197,7 @@ public class ClosureWriter { Parameter[] localVariableParams = getClosureSharedVariables(expression); removeInitialValues(localVariableParams); - InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference()); + InnerClassNode answer = new InnerClassNode(classNode, name, modifiers, ClassHelper.CLOSURE_TYPE.getPlainNodeReference()); answer.setEnclosingMethod(controller.getMethodNode()); answer.setSynthetic(true); answer.setUsingGenerics(outerClass.isUsingGenerics()); @@ -253,13 +249,13 @@ public class ClosureWriter { addFieldsAndGettersForLocalVariables(answer, localVariableParams); addConstructor(expression, localVariableParams, answer, block); - + correctAccessedVariable(answer,expression); - + return answer; } - protected ConstructorNode addConstructor(ClosureExpression expression, Parameter[] localVariableParams, InnerClassNode answer, BlockStatement block) { + protected ConstructorNode addConstructor(final ClosureExpression expression, final Parameter[] localVariableParams, final InnerClassNode answer, final BlockStatement block) { Parameter[] params = new Parameter[2 + localVariableParams.length]; params[0] = new Parameter(ClassHelper.OBJECT_TYPE, OUTER_INSTANCE); params[1] = new Parameter(ClassHelper.OBJECT_TYPE, THIS_OBJECT); @@ -271,7 +267,7 @@ public class ClosureWriter { return constructorNode; } - protected void addFieldsAndGettersForLocalVariables(InnerClassNode answer, Parameter[] localVariableParams) { + protected void addFieldsAndGettersForLocalVariables(final InnerClassNode answer, final Parameter[] localVariableParams) { for (Parameter param : localVariableParams) { String paramName = param.getName(); ClassNode type = param.getType(); @@ -298,7 +294,7 @@ public class ClosureWriter { } } - protected BlockStatement createBlockStatementForConstructor(ClosureExpression expression, ClassNode outerClass, ClassNode thisClassNode) { + protected BlockStatement createBlockStatementForConstructor(final ClosureExpression expression, final ClassNode outerClass, final ClassNode thisClassNode) { BlockStatement block = new BlockStatement(); // this block does not get a source position, because we don't // want this synthetic constructor to show up in corbertura reports @@ -329,12 +325,12 @@ public class ClosureWriter { protected static class CorrectAccessedVariableVisitor extends CodeVisitorSupport { private InnerClassNode icn; - public CorrectAccessedVariableVisitor(InnerClassNode icn) { + public CorrectAccessedVariableVisitor(final InnerClassNode icn) { this.icn = icn; } @Override - public void visitVariableExpression(VariableExpression expression) { + public void visitVariableExpression(final VariableExpression expression) { Variable v = expression.getAccessedVariable(); if (v == null) return; if (!(v instanceof FieldNode)) return; @@ -346,7 +342,7 @@ public class ClosureWriter { } } - private static void correctAccessedVariable(final InnerClassNode closureClass, ClosureExpression ce) { + private static void correctAccessedVariable(final InnerClassNode closureClass, final ClosureExpression ce) { new CorrectAccessedVariableVisitor(closureClass).visitClosureExpression(ce); } @@ -357,7 +353,7 @@ public class ClosureWriter { * same method, in this case the constructor. A closure should not * have more than one constructor! */ - protected static void removeInitialValues(Parameter[] params) { + protected static void removeInitialValues(final Parameter[] params) { for (int i = 0; i < params.length; i++) { if (params[i].hasInitialExpression()) { Parameter p = new Parameter(params[i].getType(), params[i].getName()); @@ -367,13 +363,13 @@ public class ClosureWriter { } } - public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call) { + public boolean addGeneratedClosureConstructorCall(final ConstructorCallExpression call) { ClassNode classNode = controller.getClassNode(); if (!classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) return false; AsmClassGenerator acg = controller.getAcg(); OperandStack operandStack = controller.getOperandStack(); - + MethodVisitor mv = controller.getMethodVisitor(); mv.visitVarInsn(ALOAD, 0); ClassNode callNode = classNode.getSuperClass(); @@ -391,12 +387,12 @@ public class ClosureWriter { return true; } - protected Parameter[] getClosureSharedVariables(ClosureExpression ce) { + protected Parameter[] getClosureSharedVariables(final ClosureExpression ce) { VariableScope scope = ce.getVariableScope(); Parameter[] ret = new Parameter[scope.getReferencedLocalVariablesCount()]; int index = 0; - for (Iterator iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext();) { - Variable element = (org.codehaus.groovy.ast.Variable) iter.next(); + for (Iterator<Variable> iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext();) { + Variable element = iter.next(); Parameter p = new Parameter(element.getType(), element.getName()); p.setOriginType(element.getOriginType()); p.setClosureSharedVariable(element.isClosureSharedVariable()); @@ -405,8 +401,8 @@ public class ClosureWriter { } return ret; } - - private void loadThis() { + + protected void loadThis() { MethodVisitor mv = controller.getMethodVisitor(); mv.visitVarInsn(ALOAD, 0); if (controller.isInClosure()) { diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java index 6c0b53d..d1536bb 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java @@ -22,15 +22,16 @@ import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.expr.LambdaExpression; public class LambdaWriter extends ClosureWriter { - public LambdaWriter(WriterController wc) { - super(wc); + + public LambdaWriter(final WriterController controller) { + super(controller); } - public void writeLambda(LambdaExpression expression) { + public void writeLambda(final LambdaExpression expression) { super.writeClosure(expression); } - protected Parameter[] getLambdaSharedVariables(LambdaExpression expression) { + protected Parameter[] getLambdaSharedVariables(final LambdaExpression expression) { return super.getClosureSharedVariables(expression); } } 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 05dae39..cfce5c5 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 @@ -16,20 +16,17 @@ * specific language governing permissions and limitations * under the License. */ - package org.codehaus.groovy.classgen.asm.sc; -import org.apache.groovy.util.ObjectHolder; 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.CodeVisitorSupport; import org.codehaus.groovy.ast.ConstructorNode; +import org.codehaus.groovy.ast.GroovyCodeVisitor; import org.codehaus.groovy.ast.InnerClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.builder.AstStringCompiler; -import org.codehaus.groovy.ast.expr.ClassExpression; import org.codehaus.groovy.ast.expr.ClosureExpression; import org.codehaus.groovy.ast.expr.ConstantExpression; import org.codehaus.groovy.ast.expr.Expression; @@ -45,7 +42,6 @@ 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.sc.StaticCompilationMetadataKeys; import org.codehaus.groovy.transform.stc.StaticTypesMarker; import org.objectweb.asm.MethodVisitor; @@ -55,10 +51,19 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Optional; +import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.GENERATED_LAMBDA_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE; import static org.codehaus.groovy.ast.ClassHelper.SERIALIZABLE_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.SERIALIZEDLAMBDA_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.findSAM; +import static org.codehaus.groovy.ast.ClassHelper.long_TYPE; import static org.codehaus.groovy.ast.tools.GeneralUtils.block; +import static org.codehaus.groovy.ast.tools.GeneralUtils.classX; +import static org.codehaus.groovy.ast.tools.GeneralUtils.constX; import static org.codehaus.groovy.ast.tools.GeneralUtils.declS; import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX; import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS; @@ -80,266 +85,229 @@ import static org.objectweb.asm.Opcodes.NEW; * Writer responsible for generating lambda classes in statically compiled mode. */ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFunctionalInterfaceWriter { - private static final String DO_CALL = "doCall"; - private static final String LAMBDA_SHARED_VARIABLES = "__LAMBDA_SHARED_VARIABLES"; - private static final String LAMBDA_THIS = "__lambda_this"; - private static final String INIT = "<init>"; + private static final String IS_GENERATED_CONSTRUCTOR = "__IS_GENERATED_CONSTRUCTOR"; + private static final String LAMBDA_SHARED_VARIABLES = "__LAMBDA_SHARED_VARIABLES"; + private final StaticTypesClosureWriter staticTypesClosureWriter; - private final WriterController controller; - private final WriterControllerFactory factory; - private final Map<Expression,ClassNode> lambdaClassMap = new HashMap<>(); - - public StaticTypesLambdaWriter(WriterController wc) { - super(wc); - this.staticTypesClosureWriter = new StaticTypesClosureWriter(wc); - this.controller = wc; - this.factory = normalController -> controller; + private final Map<Expression, ClassNode> lambdaClassNodes = new HashMap<>(); + + public StaticTypesLambdaWriter(final WriterController controller) { + super(controller); + this.staticTypesClosureWriter = new StaticTypesClosureWriter(controller); } @Override - public void writeLambda(LambdaExpression expression) { - ClassNode functionalInterfaceType = getFunctionalInterfaceType(expression); - if (null == functionalInterfaceType) { - // if the parameter type failed to be inferred, generate the default bytecode, which is actually a closure + public void writeLambda(final LambdaExpression expression) { + ClassNode functionalInterface = getFunctionalInterfaceType(expression); + if (functionalInterface == null || !functionalInterface.isInterface()) { super.writeLambda(expression); return; } - ClassNode redirect = functionalInterfaceType.redirect(); - if (!ClassHelper.isFunctionalInterface(redirect)) { - // if the parameter type is not real FunctionalInterface, generate the default bytecode, which is actually a closure + MethodNode abstractMethod = findSAM(functionalInterface.redirect()); + if (abstractMethod == null) { super.writeLambda(expression); return; } - boolean implementsSerializable = functionalInterfaceType.implementsInterface(SERIALIZABLE_TYPE); - expression.setSerializable(expression.isSerializable() || implementsSerializable); - - MethodNode abstractMethodNode = ClassHelper.findSAM(redirect); - String abstractMethodDesc = createMethodDescriptor(abstractMethodNode); - - ClassNode classNode = controller.getClassNode(); - - boolean isInterface = classNode.isInterface(); - ClassNode lambdaWrapperClassNode = getOrAddLambdaClass(expression, ACC_PUBLIC | ACC_FINAL | (isInterface ? ACC_STATIC : 0) | ACC_SYNTHETIC, abstractMethodNode); - MethodNode syntheticLambdaMethodNode = lambdaWrapperClassNode.getMethods(DO_CALL).get(0); + if (!expression.isSerializable() && functionalInterface.implementsInterface(SERIALIZABLE_TYPE)) { + expression.setSerializable(true); + } - boolean canDeserialize = classNode.hasMethod(createDeserializeLambdaMethodName(lambdaWrapperClassNode), createDeserializeLambdaMethodParams()); + ClassNode enclosingClass = controller.getClassNode(); + int modifiers = ACC_FINAL | ACC_PUBLIC | ACC_SYNTHETIC; + if (enclosingClass.isInterface()) modifiers |= ACC_STATIC; + ClassNode lambdaClass = getOrAddLambdaClass(expression, modifiers, abstractMethod); + MethodNode lambdaMethod = lambdaClass.getMethods("doCall").get(0); + boolean canDeserialize = enclosingClass.hasMethod(createDeserializeLambdaMethodName(lambdaClass), createDeserializeLambdaMethodParams()); if (!canDeserialize) { if (expression.isSerializable()) { - addDeserializeLambdaMethodForEachLambdaExpression(expression, lambdaWrapperClassNode); + addDeserializeLambdaMethodForEachLambdaExpression(expression, lambdaClass); addDeserializeLambdaMethod(); } - - boolean accessingInstanceMembers = isAccessingInstanceMembersOfEnclosingClass(syntheticLambdaMethodNode); - newGroovyLambdaWrapperAndLoad(lambdaWrapperClassNode, expression, accessingInstanceMembers); + newGroovyLambdaWrapperAndLoad(lambdaClass, expression, isAccessingInstanceMembersOfEnclosingClass(lambdaMethod)); } MethodVisitor mv = controller.getMethodVisitor(); - OperandStack operandStack = controller.getOperandStack(); - mv.visitInvokeDynamicInsn( - abstractMethodNode.getName(), - createAbstractMethodDesc(functionalInterfaceType, lambdaWrapperClassNode), - createBootstrapMethod(isInterface, expression.isSerializable()), - createBootstrapMethodArguments(abstractMethodDesc, H_INVOKEVIRTUAL, lambdaWrapperClassNode, syntheticLambdaMethodNode, expression.isSerializable()) + abstractMethod.getName(), + createAbstractMethodDesc(functionalInterface.redirect(), lambdaClass), + createBootstrapMethod(enclosingClass.isInterface(), expression.isSerializable()), + createBootstrapMethodArguments(createMethodDescriptor(abstractMethod), H_INVOKEVIRTUAL, lambdaClass, lambdaMethod, expression.isSerializable()) ); - if (expression.isSerializable()) { mv.visitTypeInsn(CHECKCAST, "java/io/Serializable"); } - operandStack.replace(redirect, 1); + OperandStack operandStack = controller.getOperandStack(); + operandStack.replace(functionalInterface.redirect(), 1); } - private Parameter[] createDeserializeLambdaMethodParams() { - return new Parameter[]{new Parameter(ClassHelper.SERIALIZEDLAMBDA_TYPE, SERIALIZED_LAMBDA_PARAM_NAME)}; + private static Parameter[] createDeserializeLambdaMethodParams() { + return new Parameter[]{new Parameter(SERIALIZEDLAMBDA_TYPE, "serializedLambda")}; } - private void loadEnclosingClassInstance(boolean accessingInstanceMembers) { - MethodVisitor mv = controller.getMethodVisitor(); - OperandStack operandStack = controller.getOperandStack(); - CompileStack compileStack = controller.getCompileStack(); + private static boolean isAccessingInstanceMembersOfEnclosingClass(final MethodNode syntheticLambdaMethodNode) { + boolean[] result = new boolean[1]; - if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall() || !accessingInstanceMembers) { - operandStack.pushConstant(ConstantExpression.NULL); - } else { - mv.visitVarInsn(ALOAD, 0); - operandStack.push(controller.getClassNode()); - } - } - - private boolean isAccessingInstanceMembersOfEnclosingClass(MethodNode syntheticLambdaMethodNode) { - ObjectHolder<Boolean> objectHolder = new ObjectHolder<>(false); - ClassCodeVisitorSupport classCodeVisitorSupport = new ClassCodeVisitorSupport() { + GroovyCodeVisitor visitor = new CodeVisitorSupport() { @Override - public void visitVariableExpression(VariableExpression expression) { + public void visitVariableExpression(final VariableExpression expression) { if (expression.isThisExpression()) { - objectHolder.setObject(true); + result[0] = true; } } - - @Override - protected SourceUnit getSourceUnit() { - return null; - } }; + syntheticLambdaMethodNode.getCode().visit(visitor); - classCodeVisitorSupport.visitMethod(syntheticLambdaMethodNode); - - return objectHolder.getObject(); + return result[0]; } - private void newGroovyLambdaWrapperAndLoad(ClassNode lambdaWrapperClassNode, LambdaExpression expression, boolean accessingInstanceMembers) { + private void newGroovyLambdaWrapperAndLoad(final ClassNode lambdaClass, final LambdaExpression expression, final boolean accessingInstanceMembers) { + CompileStack compileStack = controller.getCompileStack(); + OperandStack operandStack = controller.getOperandStack(); MethodVisitor mv = controller.getMethodVisitor(); - String lambdaWrapperClassInternalName = BytecodeHelper.getClassInternalName(lambdaWrapperClassNode); - mv.visitTypeInsn(NEW, lambdaWrapperClassInternalName); + + String lambdaClassInternalName = BytecodeHelper.getClassInternalName(lambdaClass); + mv.visitTypeInsn(NEW, lambdaClassInternalName); mv.visitInsn(DUP); - loadEnclosingClassInstance(accessingInstanceMembers); - controller.getOperandStack().dup(); + if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall() || !accessingInstanceMembers) { + operandStack.pushConstant(ConstantExpression.NULL); + } else { + mv.visitVarInsn(ALOAD, 0); + operandStack.push(controller.getClassNode()); + } + + operandStack.dup(); loadSharedVariables(expression); - List<ConstructorNode> constructorNodeList = - lambdaWrapperClassNode.getDeclaredConstructors().stream() - .filter(e -> Boolean.TRUE.equals(e.getNodeMetaData(IS_GENERATED_CONSTRUCTOR))) - .collect(Collectors.toList()); - - if (constructorNodeList.size() == 0) { + Optional<ConstructorNode> generatedConstructor = lambdaClass.getDeclaredConstructors().stream() + .filter(ctor -> Boolean.TRUE.equals(ctor.getNodeMetaData(IS_GENERATED_CONSTRUCTOR))).findFirst(); + if (!generatedConstructor.isPresent()) { throw new GroovyBugError("Failed to find the generated constructor"); } - ConstructorNode constructorNode = constructorNodeList.get(0); - Parameter[] lambdaWrapperClassConstructorParameters = constructorNode.getParameters(); - mv.visitMethodInsn(INVOKESPECIAL, lambdaWrapperClassInternalName, INIT, BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, lambdaWrapperClassConstructorParameters), lambdaWrapperClassNode.isInterface()); - OperandStack operandStack = controller.getOperandStack(); - operandStack.replace(ClassHelper.CLOSURE_TYPE, lambdaWrapperClassConstructorParameters.length); + Parameter[] lambdaClassConstructorParameters = generatedConstructor.get().getParameters(); + mv.visitMethodInsn(INVOKESPECIAL, lambdaClassInternalName, "<init>", BytecodeHelper.getMethodDescriptor(VOID_TYPE, lambdaClassConstructorParameters), lambdaClass.isInterface()); + + operandStack.replace(CLOSURE_TYPE, lambdaClassConstructorParameters.length); } - private Parameter[] loadSharedVariables(LambdaExpression expression) { + private Parameter[] loadSharedVariables(final LambdaExpression expression) { Parameter[] lambdaSharedVariableParameters = expression.getNodeMetaData(LAMBDA_SHARED_VARIABLES); + for (Parameter parameter : lambdaSharedVariableParameters) { - String parameterName = parameter.getName(); - loadReference(parameterName, controller); - if (parameter.getNodeMetaData(LambdaWriter.UseExistingReference.class) == null) { - parameter.setNodeMetaData(LambdaWriter.UseExistingReference.class, Boolean.TRUE); + loadReference(parameter.getName(), controller); + if (parameter.getNodeMetaData(UseExistingReference.class) == null) { + parameter.setNodeMetaData(UseExistingReference.class, Boolean.TRUE); } } return lambdaSharedVariableParameters; } - private String createAbstractMethodDesc(ClassNode functionalInterfaceType, ClassNode lambdaClassNode) { - List<Parameter> lambdaSharedVariableList = new LinkedList<>(); - - prependParameter(lambdaSharedVariableList, LAMBDA_THIS, lambdaClassNode); - - return BytecodeHelper.getMethodDescriptor(functionalInterfaceType.redirect(), lambdaSharedVariableList.toArray(Parameter.EMPTY_ARRAY)); + private String createAbstractMethodDesc(final ClassNode functionalInterface, final ClassNode lambdaClassNode) { + List<Parameter> lambdaSharedVariables = new LinkedList<>(); + prependParameter(lambdaSharedVariables, "__lambda_this", lambdaClassNode); + return BytecodeHelper.getMethodDescriptor(functionalInterface, lambdaSharedVariables.toArray(Parameter.EMPTY_ARRAY)); } - public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) { - ClassNode lambdaClass = lambdaClassMap.get(expression); - if (lambdaClass == null) { - lambdaClass = createLambdaClass(expression, mods, abstractMethodNode); - lambdaClassMap.put(expression, lambdaClass); + private ClassNode getOrAddLambdaClass(final LambdaExpression expression, final int modifiers, final MethodNode abstractMethod) { + return lambdaClassNodes.computeIfAbsent(expression, key -> { + ClassNode lambdaClass = createLambdaClass(expression, modifiers, abstractMethod); controller.getAcg().addInnerClass(lambdaClass); - lambdaClass.addInterface(ClassHelper.GENERATED_LAMBDA_TYPE); - lambdaClass.putNodeMetaData(WriterControllerFactory.class, factory); - } - lambdaClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE); - return lambdaClass; + lambdaClass.addInterface(GENERATED_LAMBDA_TYPE); + lambdaClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE); + lambdaClass.putNodeMetaData(WriterControllerFactory.class, (WriterControllerFactory) x -> controller); + return lambdaClass; + }); + } + + @Override + protected ClassNode createClosureClass(final ClosureExpression expression, final int modifiers) { + return staticTypesClosureWriter.createClosureClass(expression, modifiers); } - protected ClassNode createLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) { - ClassNode outerClass = controller.getOutermostClass(); - ClassNode classNode = controller.getClassNode(); - String name = genLambdaClassName(); - boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass(); + protected ClassNode createLambdaClass(final LambdaExpression expression, final int modifiers, final MethodNode abstractMethod) { + ClassNode enclosingClass = controller.getClassNode(); + ClassNode outermostClass = controller.getOutermostClass(); + boolean staticMethodOrInStaticClass = (controller.isStaticMethod() || enclosingClass.isStaticClass()); - InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference()); - answer.setEnclosingMethod(controller.getMethodNode()); - answer.setSynthetic(true); - answer.setUsingGenerics(outerClass.isUsingGenerics()); - answer.setSourcePosition(expression); + InnerClassNode lambdaClass = new InnerClassNode(enclosingClass, nextLambdaClassName(), modifiers, CLOSURE_TYPE.getPlainNodeReference()); + //lambdaClass.setUsingGenerics(outermostClass.isUsingGenerics()); + lambdaClass.setEnclosingMethod(controller.getMethodNode()); + lambdaClass.setSourcePosition(expression); + lambdaClass.setSynthetic(true); - if (expression.isSerializable()) { - addSerialVersionUIDField(answer); + if (controller.isInScriptBody()) { + lambdaClass.setScriptBody(true); } - if (staticMethodOrInStaticClass) { - answer.setStaticClass(true); + lambdaClass.setStaticClass(true); } - if (controller.isInScriptBody()) { - answer.setScriptBody(true); + if (expression.isSerializable()) { + addSerialVersionUIDField(lambdaClass); } - MethodNode syntheticLambdaMethodNode = addSyntheticLambdaMethodNode(expression, answer, abstractMethodNode); + MethodNode syntheticLambdaMethodNode = addSyntheticLambdaMethodNode(expression, lambdaClass, abstractMethod); Parameter[] localVariableParameters = expression.getNodeMetaData(LAMBDA_SHARED_VARIABLES); - addFieldsAndGettersForLocalVariables(answer, localVariableParameters); - ConstructorNode constructorNode = addConstructor(expression, localVariableParameters, answer, createBlockStatementForConstructor(expression, outerClass, classNode)); + addFieldsAndGettersForLocalVariables(lambdaClass, localVariableParameters); + ConstructorNode constructorNode = addConstructor(expression, localVariableParameters, lambdaClass, createBlockStatementForConstructor(expression, outermostClass, enclosingClass)); constructorNode.putNodeMetaData(IS_GENERATED_CONSTRUCTOR, Boolean.TRUE); - new LambdaBodyTransformationVisitor(answer).visitMethod(syntheticLambdaMethodNode); + syntheticLambdaMethodNode.getCode().visit(new CorrectAccessedVariableVisitor(lambdaClass)); - return answer; + return lambdaClass; } - private void addSerialVersionUIDField(InnerClassNode answer) { - answer.addFieldFirst("serialVersionUID", ACC_PRIVATE | ACC_STATIC | ACC_FINAL, ClassHelper.long_TYPE, new ConstantExpression(-1L, true)); + private String nextLambdaClassName() { + ClassNode enclosingClass = controller.getClassNode(); + ClassNode outermostClass = controller.getOutermostClass(); + return enclosingClass.getName() + "$" + controller.getContext().getNextLambdaInnerName(outermostClass, enclosingClass, controller.getMethodNode()); } - 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 static void addSerialVersionUIDField(final ClassNode lambdaClass) { + lambdaClass.addFieldFirst("serialVersionUID", ACC_PRIVATE | ACC_STATIC | ACC_FINAL, long_TYPE, constX(-1L, true)); } - private MethodNode addSyntheticLambdaMethodNode(LambdaExpression expression, InnerClassNode answer, MethodNode abstractMethodNode) { - Parameter[] parametersWithExactType = createParametersWithExactType(expression); // expression.getParameters(); -// ClassNode returnType = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); //abstractMethodNode.getReturnType(); + private MethodNode addSyntheticLambdaMethodNode(final LambdaExpression expression, final ClassNode lambdaClass, final MethodNode abstractMethod) { + Parameter[] parametersWithExactType = createParametersWithExactType(expression); Parameter[] localVariableParameters = getLambdaSharedVariables(expression); removeInitialValues(localVariableParameters); - List<Parameter> methodParameterList = new LinkedList<>(Arrays.asList(parametersWithExactType)); - - MethodNode methodNode = - answer.addMethod( - DO_CALL, - ACC_PUBLIC, - abstractMethodNode.getReturnType() /*ClassHelper.OBJECT_TYPE*/ /*returnType*/, - methodParameterList.toArray(Parameter.EMPTY_ARRAY), - ClassNode.EMPTY_ARRAY, - expression.getCode() - ); - methodNode.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType); + MethodNode doCallMethod = lambdaClass.addMethod( + "doCall", + ACC_PUBLIC, + abstractMethod.getReturnType(), + Arrays.copyOf(parametersWithExactType, parametersWithExactType.length), + ClassNode.EMPTY_ARRAY, + expression.getCode() + ); + doCallMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType); expression.putNodeMetaData(LAMBDA_SHARED_VARIABLES, localVariableParameters); - methodNode.setSourcePosition(expression); + doCallMethod.setSourcePosition(expression); - return methodNode; + return doCallMethod; } - private Parameter[] createParametersWithExactType(LambdaExpression expression) { + private Parameter[] createParametersWithExactType(final LambdaExpression expression) { Parameter[] parameters = expression.getParameters(); if (parameters == null) { parameters = Parameter.EMPTY_ARRAY; } for (Parameter parameter : parameters) { - ClassNode parameterType = parameter.getType(); ClassNode inferredType = parameter.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); - - if (null == inferredType) { + if (inferredType == null) { continue; } - ClassNode type = convertParameterType(parameterType, inferredType); + ClassNode type = convertParameterType(parameter.getType(), inferredType); parameter.setType(type); parameter.setOriginType(type); @@ -348,16 +316,15 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun return parameters; } - private static final String SERIALIZED_LAMBDA_PARAM_NAME = "serializedLambda"; - private static final String DESERIALIZE_LAMBDA_METHOD_NAME = "$deserializeLambda$"; private void addDeserializeLambdaMethod() { - ClassNode classNode = controller.getClassNode(); + ClassNode enclosingClass = controller.getClassNode(); Parameter[] parameters = createDeserializeLambdaMethodParams(); - if (classNode.hasMethod(DESERIALIZE_LAMBDA_METHOD_NAME, parameters)) { + if (enclosingClass.hasMethod("$deserializeLambda$", parameters)) { return; } + Statement code = block( - declS(localVarX("enclosingClass", ClassHelper.DYNAMIC_TYPE), new ClassExpression(classNode)), + declS(localVarX("enclosingClass", OBJECT_TYPE), classX(enclosingClass)), ((BlockStatement) new AstStringCompiler().compile( "return enclosingClass" + ".getDeclaredMethod(\"\\$deserializeLambda_${serializedLambda.getImplClass().replace('/', '$')}\\$\", serializedLambda.getClass())" + @@ -365,75 +332,47 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun ).get(0)).getStatements().get(0) ); - classNode.addSyntheticMethod( - DESERIALIZE_LAMBDA_METHOD_NAME, + enclosingClass.addSyntheticMethod( + "$deserializeLambda$", ACC_PRIVATE | ACC_STATIC, - ClassHelper.OBJECT_TYPE, + OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, code); } - private void addDeserializeLambdaMethodForEachLambdaExpression(LambdaExpression lambdaExpression, ClassNode lambdaWrapperClassNode) { - ClassNode classNode = controller.getClassNode(); + private void addDeserializeLambdaMethodForEachLambdaExpression(final LambdaExpression expression, final ClassNode lambdaClass) { + ClassNode enclosingClass = controller.getClassNode(); Statement code = block( new BytecodeSequence(new BytecodeInstruction() { @Override - public void visit(MethodVisitor mv) { - callGetCapturedArg(mv, ICONST_0, lambdaWrapperClassNode); - } - - private void callGetCapturedArg(MethodVisitor mv, int capturedArgIndex, ClassNode resultType) { - OperandStack operandStack = controller.getOperandStack(); - + public void visit(final MethodVisitor mv) { mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(capturedArgIndex); + mv.visitInsn(ICONST_0); mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/invoke/SerializedLambda", "getCapturedArg", "(I)Ljava/lang/Object;", false); - mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(resultType)); - operandStack.push(resultType); + mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(lambdaClass)); + OperandStack operandStack = controller.getOperandStack(); + operandStack.push(lambdaClass); } }), - returnS(lambdaExpression) + returnS(expression) ); - classNode.addSyntheticMethod( - createDeserializeLambdaMethodName(lambdaWrapperClassNode), + enclosingClass.addSyntheticMethod( + createDeserializeLambdaMethodName(lambdaClass), ACC_PUBLIC | ACC_STATIC, - ClassHelper.OBJECT_TYPE, + OBJECT_TYPE, createDeserializeLambdaMethodParams(), ClassNode.EMPTY_ARRAY, code); } - private String createDeserializeLambdaMethodName(ClassNode lambdaWrapperClassNode) { - return "$deserializeLambda_" + lambdaWrapperClassNode.getName().replace('.', '$') + "$"; - } - - @Override - protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) { - return staticTypesClosureWriter.createClosureClass(expression, mods); - } - - private static final class LambdaBodyTransformationVisitor extends ClassCodeVisitorSupport { - private final CorrectAccessedVariableVisitor correctAccessedVariableVisitor; - - public LambdaBodyTransformationVisitor(InnerClassNode icn) { - this.correctAccessedVariableVisitor = new CorrectAccessedVariableVisitor(icn); - } - - @Override - public void visitVariableExpression(VariableExpression expression) { - correctAccessedVariableVisitor.visitVariableExpression(expression); - } - - @Override - protected SourceUnit getSourceUnit() { - return null; - } + private static String createDeserializeLambdaMethodName(final ClassNode lambdaClass) { + return "$deserializeLambda_" + lambdaClass.getName().replace('.', '$') + "$"; } } diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java index 62f5cee..c33846d 100644 --- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java +++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java @@ -677,7 +677,7 @@ public class CompilationUnit extends ProcessingUnit { } } - private void sortClasses() throws CompilationFailedException { + private void sortClasses() { for (ModuleNode module : getAST().getModules()) { module.sortClasses(); }