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);
}
}