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 2023/01/19 22:18:06 UTC

[groovy] branch master updated: simpler ternary bytecode (no tmp var for elvis)

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 89de534b77 simpler ternary bytecode (no tmp var for elvis)
89de534b77 is described below

commit 89de534b77e2321d46e6a9821628331693c7aae2
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jan 19 16:13:30 2023 -0600

    simpler ternary bytecode (no tmp var for elvis)
---
 .../classgen/asm/BinaryExpressionHelper.java       | 94 ++++++++--------------
 1 file changed, 34 insertions(+), 60 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
index 5dca1655e6..7eb6c09c47 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
@@ -896,98 +896,72 @@ public class BinaryExpressionHelper {
     }
 
     private void evaluateElvisExpression(final TernaryExpression expression) {
-        MethodVisitor mv = controller.getMethodVisitor();
-        CompileStack compileStack = controller.getCompileStack();
-        OperandStack operandStack = controller.getOperandStack();
-        TypeChooser typeChooser = controller.getTypeChooser();
-
-        Expression boolPart = expression.getBooleanExpression().getExpression();
+        Expression truePart = expression.getTrueExpression();
         Expression falsePart = expression.getFalseExpression();
 
-        ClassNode truePartType = typeChooser.resolveType(boolPart, controller.getClassNode());
+        TypeChooser typeChooser = controller.getTypeChooser();
+        ClassNode truePartType = typeChooser.resolveType(truePart, controller.getClassNode());
         ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode());
-        ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType);
-
-        // x?:y is equal to x?x:y, which evals to
-        //      var t=x; boolean(t)?t:y
-        // first we load x, dup it, convert the dupped to boolean, then
-        // jump depending on the value. For true we are done, for false we
-        // have to load y, thus we first remove x and then load y.
-        // But since x and y may have different stack lengths, this cannot work
-        // Thus we have to do the following:
-        // Be X the type of x, Y the type of y and S the common supertype of
-        // X and Y, then we have to see x?:y as
-        //      var t=x;boolean(t)?S(t):S(y)
-        // so we load x, dup it, store the value in a local variable (t), then
-        // do boolean conversion. In the true part load t and cast it to S,
-        // in the false part load y and cast y to S
-
-        // load x, dup it, store one in $t and cast the remaining one to boolean
-        int mark = operandStack.getStackLength();
-        boolPart.visit(controller.getAcg());
-        operandStack.dup();
-        if (ClassHelper.isPrimitiveType(truePartType) && !ClassHelper.isPrimitiveType(operandStack.getTopOperand())) {
-            truePartType = ClassHelper.getWrapper(truePartType);
-        }
-        int retValueId = compileStack.defineTemporaryVariable("$t", truePartType, true);
-        operandStack.castToBool(mark, true);
+        ClassNode commonType = WideningCategories.lowestUpperBound(truePartType, falsePartType);
+
+        // write "x?:y" as "boolean(x)?T(x):T(y)" where T is common type of x and y
+        OperandStack operandStack = controller.getOperandStack();
+        MethodVisitor mv = controller.getMethodVisitor();
 
+        // load x, dup it and cast to boolean
+        truePart.visit(controller.getAcg());
+        int top = operandStack.getStackLength();
+        operandStack.dup();
+        operandStack.castToBool(top, true);
         Label l0 = operandStack.jump(IFEQ);
-        // true part: load $t and cast to S
-        operandStack.load(truePartType, retValueId);
-        operandStack.doGroovyCast(common);
+
+        // true path: cast to T
+        operandStack.doGroovyCast(commonType);
         Label l1 = new Label();
         mv.visitJumpInsn(GOTO, l1);
 
-        // false part: load false expression and cast to S
+        // false path: drop x, load y and cast to T
         mv.visitLabel(l0);
+        operandStack.pop();
         falsePart.visit(controller.getAcg());
-        operandStack.doGroovyCast(common);
+        operandStack.doGroovyCast(commonType);
 
-        // finish and cleanup
+        // finish up
         mv.visitLabel(l1);
-        compileStack.removeVar(retValueId);
-        operandStack.replace(common, 2);
+        operandStack.replace(commonType);
     }
 
     private void evaluateTernaryExpression(final TernaryExpression expression) {
-        MethodVisitor mv = controller.getMethodVisitor();
-        TypeChooser typeChooser = controller.getTypeChooser();
-        OperandStack operandStack = controller.getOperandStack();
-
         Expression boolPart = expression.getBooleanExpression();
         Expression truePart = expression.getTrueExpression();
         Expression falsePart = expression.getFalseExpression();
 
+        TypeChooser typeChooser = controller.getTypeChooser();
         ClassNode truePartType = typeChooser.resolveType(truePart, controller.getClassNode());
         ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode());
-        ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType);
+        ClassNode commonType = WideningCategories.lowestUpperBound(truePartType, falsePartType);
 
-        // we compile b?x:y as
-        //      boolean(b)?S(x):S(y), S = common super type of x,y
-        // so we load b, do boolean conversion.
-        // In the true part load x and cast it to S,
-        // in the false part load y and cast y to S
+        // write "x?y:z" as "x?T(y):T(z)" where T is common type of y and z
+        OperandStack operandStack = controller.getOperandStack();
+        MethodVisitor mv = controller.getMethodVisitor();
 
-        // load b and convert to boolean
-        int mark = operandStack.getStackLength();
+        // load x
         boolPart.visit(controller.getAcg());
-        operandStack.castToBool(mark, true);
-
         Label l0 = operandStack.jump(IFEQ);
-        // true part: load x and cast to S
+
+        // true path: load y and cast to T
         truePart.visit(controller.getAcg());
-        operandStack.doGroovyCast(common);
+        operandStack.doGroovyCast(commonType);
         Label l1 = new Label();
         mv.visitJumpInsn(GOTO, l1);
 
-        // false part: load y and cast to S
+        // false path: load z and cast to T
         mv.visitLabel(l0);
         falsePart.visit(controller.getAcg());
-        operandStack.doGroovyCast(common);
+        operandStack.doGroovyCast(commonType);
 
-        // finish and cleanup
+        // finish up
         mv.visitLabel(l1);
-        operandStack.replace(common, 2);
+        operandStack.replace(commonType, 2);
     }
 }