You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2019/12/19 00:18:48 UTC
[groovy] branch master updated: minor refactor
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 <er...@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();
}