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 2020/02/14 20:09:25 UTC

[groovy] 02/04: add builders for BytecodeExpression supporting closure/lambda

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

commit 158ebffaf8e682ce4a7e6c8e2bc4f393b5824a4c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Feb 14 12:19:08 2020 -0600

    add builders for BytecodeExpression supporting closure/lambda
---
 .../codehaus/groovy/ast/tools/GeneralUtils.java    | 22 +++++
 .../org/codehaus/groovy/classgen/Verifier.java     | 13 ++-
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java | 21 ++---
 .../asm/sc/StaticTypesUnaryExpressionHelper.java   | 99 ++++++++++------------
 .../transformers/ConstructorCallTransformer.java   | 36 ++++----
 5 files changed, 98 insertions(+), 93 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
index 49b7163..47b45cc 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -60,12 +60,14 @@ import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.stmt.ThrowStatement;
 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.classgen.BytecodeExpression;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.control.io.ReaderSource;
 import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.transform.AbstractASTTransformation;
+import org.objectweb.asm.MethodVisitor;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -74,6 +76,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import static org.apache.groovy.util.BeanUtils.capitalize;
 import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_IDENTICAL;
@@ -156,6 +159,21 @@ public class GeneralUtils {
         return block;
     }
 
+    public static BytecodeExpression bytecodeX(Consumer<MethodVisitor> writer) {
+        return new BytecodeExpression() {
+            @Override
+            public void visit(final MethodVisitor visitor) {
+                writer.accept(visitor);
+            }
+        };
+    }
+
+    public static BytecodeExpression bytecodeX(ClassNode type, Consumer<MethodVisitor> writer) {
+        BytecodeExpression expression = bytecodeX(writer);
+        expression.setType(type);
+        return expression;
+    }
+
     public static MethodCallExpression callSuperX(String methodName, Expression args) {
         return callX(varX("super"), methodName, args);
     }
@@ -757,6 +775,10 @@ public class GeneralUtils {
         return new PropertyExpression(owner, property);
     }
 
+    public static PropertyExpression propX(Expression owner, Expression property, boolean safe) {
+        return new PropertyExpression(owner, property, safe);
+    }
+
     public static PropertyExpression thisPropX(boolean implicit, String property) {
         PropertyExpression pexp = propX(varX("this"), property);
         pexp.setImplicitThis(implicit);
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 6b24a15..4310bfb 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -93,6 +93,7 @@ import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
 import static org.apache.groovy.ast.tools.ExpressionUtils.transformInlineConstants;
 import static org.apache.groovy.ast.tools.MethodNodeUtils.getPropertyName;
 import static org.apache.groovy.ast.tools.MethodNodeUtils.methodDescriptorWithoutReturnType;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.bytecodeX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
@@ -162,13 +163,11 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         final String classInternalName = BytecodeHelper.getClassInternalName(node);
         metaClassField =
                 node.addField("metaClass", ACC_PRIVATE | ACC_TRANSIENT | ACC_SYNTHETIC, ClassHelper.METACLASS_TYPE,
-                        new BytecodeExpression(ClassHelper.METACLASS_TYPE) {
-                            @Override
-                            public void visit(MethodVisitor mv) {
-                                mv.visitVarInsn(ALOAD, 0);
-                                mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
-                            }
-                        });
+                        bytecodeX(ClassHelper.METACLASS_TYPE, mv -> {
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                        })
+                );
         metaClassField.setSynthetic(true);
         return metaClassField;
     }
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index 5c19e6c..313ee38 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -77,6 +77,7 @@ import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
 import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.bytecodeX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
@@ -350,13 +351,10 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
         Label l4 = new Label();
         mv.visitLabel(l4);
         mv.visitVarInsn(ALOAD, var);
-        final ClassNode finalComponentType = componentType;
-        PropertyExpression pexp = propX(new BytecodeExpression(finalComponentType) {
-            @Override
-            public void visit(final MethodVisitor mv) {
-                mv.visitVarInsn(ALOAD, next);
-            }
-        }, propertyName);
+        PropertyExpression pexp = propX(
+                bytecodeX(componentType, v -> v.visitVarInsn(ALOAD, next)),
+                propertyName
+        );
         pexp.visit(controller.getAcg());
         controller.getOperandStack().box();
         controller.getOperandStack().remove(1);
@@ -430,13 +428,8 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
                 if (currentCall != null && currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) != null) {
                     property = currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
                     String[] props = property.split("\\.");
-                    BytecodeExpression thisLoader = new BytecodeExpression(CLOSURE_TYPE) {
-                        @Override
-                        public void visit(final MethodVisitor mv) {
-                            mv.visitVarInsn(ALOAD, 0); // load this
-                        }
-                    };
-                    PropertyExpression pexp = new PropertyExpression(thisLoader, constX(props[0]), safe);
+                    BytecodeExpression thisLoader = bytecodeX(CLOSURE_TYPE, mv -> mv.visitVarInsn(ALOAD, 0));
+                    PropertyExpression pexp = propX(thisLoader, constX(props[0]), safe);
                     for (int i = 1, n = props.length; i < n; i += 1) {
                         pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
                         pexp = propX(pexp, props[i]);
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java
index c02e0e2..51a8ed4 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java
@@ -30,7 +30,6 @@ import org.codehaus.groovy.classgen.asm.TypeChooser;
 import org.codehaus.groovy.classgen.asm.UnaryExpressionHelper;
 import org.codehaus.groovy.classgen.asm.WriterController;
 import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
 import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
@@ -42,6 +41,7 @@ import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
 import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.bytecodeX;
 
 /**
  * An unary expression helper which generates optimized bytecode depending on
@@ -63,27 +63,24 @@ public class StaticTypesUnaryExpressionHelper extends UnaryExpressionHelper impl
     public void writeBitwiseNegate(final BitwiseNegationExpression expression) {
         expression.getExpression().visit(controller.getAcg());
         if (isPrimitiveOnTop()) {
-            final ClassNode top = getTopOperand();
-            if (top==int_TYPE || top==short_TYPE || top==byte_TYPE || top==char_TYPE || top==long_TYPE) {
-                BytecodeExpression bytecodeExpression = new BytecodeExpression() {
-                    @Override
-                    public void visit(final MethodVisitor mv) {
-                        if (long_TYPE==top) {
-                            mv.visitLdcInsn(-1);
-                            mv.visitInsn(LXOR);
-                        } else {
-                            mv.visitInsn(ICONST_M1);
-                            mv.visitInsn(IXOR);
-                            if (byte_TYPE==top) {
-                                mv.visitInsn(I2B);
-                            } else if (char_TYPE==top) {
-                                mv.visitInsn(I2C);
-                            } else if (short_TYPE==top) {
-                                mv.visitInsn(I2S);
-                            }
+            ClassNode top = getTopOperand();
+            if (top == int_TYPE || top == short_TYPE || top == byte_TYPE || top == char_TYPE || top == long_TYPE) {
+                BytecodeExpression bytecodeExpression = bytecodeX(mv -> {
+                    if (long_TYPE == top) {
+                        mv.visitLdcInsn(-1);
+                        mv.visitInsn(LXOR);
+                    } else {
+                        mv.visitInsn(ICONST_M1);
+                        mv.visitInsn(IXOR);
+                        if (byte_TYPE == top) {
+                            mv.visitInsn(I2B);
+                        } else if (char_TYPE == top) {
+                            mv.visitInsn(I2C);
+                        } else if (short_TYPE == top) {
+                            mv.visitInsn(I2S);
                         }
                     }
-                };
+                });
                 bytecodeExpression.visit(controller.getAcg());
                 controller.getOperandStack().remove(1);
                 return;
@@ -100,19 +97,16 @@ public class StaticTypesUnaryExpressionHelper extends UnaryExpressionHelper impl
         if (typeChooser.resolveType(subExpression, classNode) == boolean_TYPE) {
             subExpression.visit(controller.getAcg());
             controller.getOperandStack().doGroovyCast(boolean_TYPE);
-            BytecodeExpression bytecodeExpression = new BytecodeExpression() {
-                @Override
-                public void visit(final MethodVisitor mv) {
-                    Label ne = new Label();
-                    mv.visitJumpInsn(IFNE, ne);
-                    mv.visitInsn(ICONST_1);
-                    Label out = new Label();
-                    mv.visitJumpInsn(GOTO, out);
-                    mv.visitLabel(ne);
-                    mv.visitInsn(ICONST_0);
-                    mv.visitLabel(out);
-                }
-            };
+            BytecodeExpression bytecodeExpression = bytecodeX(mv -> {
+                Label ne = new Label();
+                mv.visitJumpInsn(IFNE, ne);
+                mv.visitInsn(ICONST_1);
+                Label out = new Label();
+                mv.visitJumpInsn(GOTO, out);
+                mv.visitLabel(ne);
+                mv.visitInsn(ICONST_0);
+                mv.visitLabel(out);
+            });
             bytecodeExpression.visit(controller.getAcg());
             controller.getOperandStack().remove(1);
             return;
@@ -124,29 +118,26 @@ public class StaticTypesUnaryExpressionHelper extends UnaryExpressionHelper impl
     public void writeUnaryMinus(final UnaryMinusExpression expression) {
         expression.getExpression().visit(controller.getAcg());
         if (isPrimitiveOnTop()) {
-            final ClassNode top = getTopOperand();
-            if (top!=boolean_TYPE) {
-                BytecodeExpression bytecodeExpression = new BytecodeExpression() {
-                    @Override
-                    public void visit(final MethodVisitor mv) {
-                        if (int_TYPE == top || short_TYPE == top || byte_TYPE==top || char_TYPE==top) {
-                            mv.visitInsn(INEG);
-                            if (byte_TYPE==top) {
-                                mv.visitInsn(I2B);
-                            } else if (char_TYPE==top) {
-                                mv.visitInsn(I2C);
-                            } else if (short_TYPE==top) {
-                                mv.visitInsn(I2S);
-                            }
-                        } else if (long_TYPE == top) {
-                            mv.visitInsn(LNEG);
-                        } else if (float_TYPE == top) {
-                            mv.visitInsn(FNEG);
-                        } else if (double_TYPE == top) {
-                            mv.visitInsn(DNEG);
+            ClassNode top = getTopOperand();
+            if (top != boolean_TYPE) {
+                BytecodeExpression bytecodeExpression = bytecodeX(mv -> {
+                    if (int_TYPE == top || short_TYPE == top || byte_TYPE == top || char_TYPE == top) {
+                        mv.visitInsn(INEG);
+                        if (byte_TYPE == top) {
+                            mv.visitInsn(I2B);
+                        } else if (char_TYPE == top) {
+                            mv.visitInsn(I2C);
+                        } else if (short_TYPE == top) {
+                            mv.visitInsn(I2S);
                         }
+                    } else if (long_TYPE == top) {
+                        mv.visitInsn(LNEG);
+                    } else if (float_TYPE == top) {
+                        mv.visitInsn(FNEG);
+                    } else if (double_TYPE == top) {
+                        mv.visitInsn(DNEG);
                     }
-                };
+                });
                 bytecodeExpression.visit(controller.getAcg());
                 controller.getOperandStack().remove(1);
                 return;
diff --git a/src/main/java/org/codehaus/groovy/transform/sc/transformers/ConstructorCallTransformer.java b/src/main/java/org/codehaus/groovy/transform/sc/transformers/ConstructorCallTransformer.java
index 9c269ea..d4f31e4 100644
--- a/src/main/java/org/codehaus/groovy/transform/sc/transformers/ConstructorCallTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/sc/transformers/ConstructorCallTransformer.java
@@ -29,7 +29,6 @@ import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.classgen.BytecodeExpression;
@@ -45,12 +44,15 @@ import org.objectweb.asm.Opcodes;
 
 import java.util.List;
 
+import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.bytecodeX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.DIRECT_METHOD_CALL_TARGET;
 
 public class ConstructorCallTransformer {
     private final StaticCompilationTransformer staticCompilationTransformer;
 
-    public ConstructorCallTransformer(StaticCompilationTransformer staticCompilationTransformer) {
+    public ConstructorCallTransformer(final StaticCompilationTransformer staticCompilationTransformer) {
         this.staticCompilationTransformer = staticCompilationTransformer;
     }
 
@@ -116,8 +118,9 @@ public class ConstructorCallTransformer {
             this.originalCall = originalCall;
             this.setSourcePosition(originalCall);
             this.copyNodeMetaData(originalCall);
-            List<Expression> originalExpressions = originalCall.getArguments() instanceof TupleExpression ?
-                    ((TupleExpression)originalCall.getArguments()).getExpressions() : null;
+            List<Expression> originalExpressions = originalCall.getArguments() instanceof TupleExpression
+                    ? ((TupleExpression) originalCall.getArguments()).getExpressions()
+                    : null;
             this.innerClassCall = originalExpressions != null && originalExpressions.size() == 2;
         }
 
@@ -133,12 +136,12 @@ public class ConstructorCallTransformer {
 
         @Override
         public void visit(final MethodVisitor mv) {
-            final WriterController controller = acg.getController();
-            final OperandStack operandStack = controller.getOperandStack();
-            final CompileStack compileStack = controller.getCompileStack();
+            WriterController controller = acg.getController();
+            CompileStack compileStack = controller.getCompileStack();
+            OperandStack operandStack = controller.getOperandStack();
 
             // create a temporary variable to store the constructed object
-            final int tmpObj = compileStack.defineTemporaryVariable("tmpObj", declaringClass, false);
+            int tmpObj = compileStack.defineTemporaryVariable("tmpObj", declaringClass, false);
             String classInternalName = BytecodeHelper.getClassInternalName(declaringClass);
             mv.visitTypeInsn(NEW, classInternalName);
             mv.visitInsn(DUP);
@@ -147,7 +150,7 @@ public class ConstructorCallTransformer {
                 // load "this"
                 mv.visitVarInsn(ALOAD, 0);
                 InnerClassNode icn = (InnerClassNode) declaringClass.redirect();
-                Parameter[] params = { new Parameter(icn.getOuterClass(), "$p$") };
+                Parameter[] params = {new Parameter(icn.getOuterClass(), "$p$")};
                 desc = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, params);
             }
             mv.visitMethodInsn(INVOKESPECIAL, classInternalName, "<init>", desc, false);
@@ -155,17 +158,14 @@ public class ConstructorCallTransformer {
 
             // load every field
             for (MapEntryExpression entryExpression : map.getMapEntryExpressions()) {
-                int line = entryExpression.getLineNumber();
-                int col = entryExpression.getColumnNumber();
                 Expression keyExpression = staticCompilationTransformer.transform(entryExpression.getKeyExpression());
                 Expression valueExpression = staticCompilationTransformer.transform(entryExpression.getValueExpression());
-                BinaryExpression bexp = new BinaryExpression(new PropertyExpression(new BytecodeExpression(declaringClass) {
-                            @Override
-                            public void visit(final MethodVisitor mv) {
-                                mv.visitVarInsn(ALOAD, tmpObj);
-                            }
-                        }, keyExpression),
-                        Token.newSymbol("=", line, col),
+                BinaryExpression bexp = binX(
+                        propX(
+                                bytecodeX(declaringClass, v -> v.visitVarInsn(ALOAD, tmpObj)),
+                                keyExpression
+                        ),
+                        Token.newSymbol("=", entryExpression.getLineNumber(), entryExpression.getColumnNumber()),
                         valueExpression
                 );
                 bexp.setSourcePosition(entryExpression);