This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new abebae2503 GROOVY-10918: direct store to local variable or parameter
(no temporary)
abebae2503 is described below
commit abebae25031cc59ad402bc45e4d86765ff67d5c8
Author: Eric Milles <[email protected]>
AuthorDate: Thu Feb 16 08:48:35 2023 -0600
GROOVY-10918: direct store to local variable or parameter (no temporary)
2_5_X backport
---
.../classgen/asm/BinaryExpressionHelper.java | 271 +++++++++++----------
.../classgen/asm/sc/StaticCompilationTest.groovy | 41 ++--
2 files changed, 156 insertions(+), 156 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 63b105c7d5..5bdf80ff86 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
@@ -22,6 +22,7 @@ import groovy.lang.GroovyRuntimeException;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.ArrayExpression;
import org.codehaus.groovy.ast.expr.BinaryExpression;
@@ -46,10 +47,10 @@ import org.codehaus.groovy.classgen.BytecodeExpression;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.syntax.SyntaxException;
import org.codehaus.groovy.syntax.Token;
-import org.codehaus.groovy.syntax.Types;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
+import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
import static org.codehaus.groovy.syntax.Types.BITWISE_AND_EQUAL;
import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
@@ -81,12 +82,14 @@ import static org.codehaus.groovy.syntax.Types.LOGICAL_OR;
import static org.codehaus.groovy.syntax.Types.MATCH_REGEX;
import static org.codehaus.groovy.syntax.Types.MINUS;
import static org.codehaus.groovy.syntax.Types.MINUS_EQUAL;
+import static org.codehaus.groovy.syntax.Types.MINUS_MINUS;
import static org.codehaus.groovy.syntax.Types.MOD;
import static org.codehaus.groovy.syntax.Types.MOD_EQUAL;
import static org.codehaus.groovy.syntax.Types.MULTIPLY;
import static org.codehaus.groovy.syntax.Types.MULTIPLY_EQUAL;
import static org.codehaus.groovy.syntax.Types.PLUS;
import static org.codehaus.groovy.syntax.Types.PLUS_EQUAL;
+import static org.codehaus.groovy.syntax.Types.PLUS_PLUS;
import static org.codehaus.groovy.syntax.Types.POWER;
import static org.codehaus.groovy.syntax.Types.POWER_EQUAL;
import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
@@ -115,15 +118,15 @@ public class BinaryExpressionHelper {
private static final MethodCaller isCaseMethod =
MethodCaller.newStatic(ScriptBytecodeAdapter.class, "isCase");
private final WriterController controller;
-
+
public BinaryExpressionHelper(WriterController wc) {
this.controller = wc;
}
-
+
public WriterController getController(){
return controller;
}
-
+
public void eval(BinaryExpression expression) {
switch (expression.getOperation().getType()) {
case EQUAL: // = assignment
@@ -306,7 +309,7 @@ public class BinaryExpressionHelper {
throw new GroovyBugError("Operation: " + expression.getOperation()
+ " not supported");
}
}
-
+
protected void assignToArray(Expression parent, Expression receiver,
Expression index, Expression rhsValueLoader) {
// let's replace this assignment to a subscript operator with a
// method call
@@ -322,47 +325,49 @@ public class BinaryExpressionHelper {
rhsValueLoader.visit(controller.getAcg());
}
- private static boolean isNull(Expression exp) {
- if (exp instanceof ConstantExpression){
- return ((ConstantExpression) exp).getValue()==null;
- } else {
- return false;
- }
- }
-
- public void evaluateEqual(BinaryExpression expression, boolean
defineVariable) {
+ public void evaluateEqual(final BinaryExpression expression, final boolean
defineVariable) {
AsmClassGenerator acg = controller.getAcg();
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
- Expression rightExpression = expression.getRightExpression();
Expression leftExpression = expression.getLeftExpression();
+ Expression rightExpression = expression.getRightExpression();
+ boolean directAssignment = defineVariable && !(leftExpression
instanceof TupleExpression);
- if ( defineVariable &&
- rightExpression instanceof EmptyExpression &&
- !(leftExpression instanceof TupleExpression) )
- {
- VariableExpression ve = (VariableExpression) leftExpression;
- BytecodeVariable var = compileStack.defineVariable(ve,
controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false);
- operandStack.loadOrStoreVariable(var, false);
- return;
- }
- // evaluate the RHS and store the result
// TODO: LHS has not been visited, it could be a variable in a closure
and type chooser is not aware.
ClassNode lhsType =
controller.getTypeChooser().resolveType(leftExpression,
controller.getClassNode());
+
+ if (directAssignment && rightExpression instanceof EmptyExpression) {
+ BytecodeVariable v = compileStack.defineVariable((Variable)
leftExpression, lhsType, false);
+ operandStack.loadOrStoreVariable(v, false);
+ return;
+ }
+
+ // evaluate RHS and store the value
+
if (rightExpression instanceof ListExpression && lhsType.isArray()) {
ListExpression list = (ListExpression) rightExpression;
ArrayExpression array = new
ArrayExpression(lhsType.getComponentType(), list.getExpressions());
array.setSourcePosition(list);
array.visit(acg);
} else if (rightExpression instanceof EmptyExpression) {
- loadInitValue(leftExpression.getType());
+ loadInitValue(lhsType); // null or zero (or false)
} else {
rightExpression.visit(acg);
}
+ // GROOVY-10918: direct store to local variable or parameter (no temp)
+ if (!defineVariable && leftExpression instanceof VariableExpression) {
+ BytecodeVariable v =
compileStack.getVariable(leftExpression.getText(), false);
+ if (v != null) {
+ operandStack.dup(); // return value of the assignment
expression
+ operandStack.storeVar(v);
+ return;
+ }
+ }
+
ClassNode rhsType = operandStack.getTopOperand();
- boolean directAssignment = defineVariable && !(leftExpression
instanceof TupleExpression);
int rhsValueId;
+
if (directAssignment) {
VariableExpression var = (VariableExpression) leftExpression;
if (var.isClosureSharedVariable() &&
ClassHelper.isPrimitiveType(rhsType)) {
@@ -371,18 +376,18 @@ public class BinaryExpressionHelper {
operandStack.box();
}
- // ensure we try to unbox null to cause a runtime NPE in case we
assign
- // null to a primitive typed variable, even if it is used only in
boxed
+ // ensure we try to unbox null to cause a runtime NPE in case we
assign
+ // null to a primitive typed variable, even if it is used only in
boxed
// form as it is closure shared
- if (var.isClosureSharedVariable() &&
ClassHelper.isPrimitiveType(var.getOriginType()) && isNull(rightExpression)) {
+ if (var.isClosureSharedVariable() &&
ClassHelper.isPrimitiveType(var.getOriginType()) &&
isNullConstant(rightExpression)) {
operandStack.doGroovyCast(var.getOriginType());
- // these two are never reached in bytecode and only there
- // to avoid verifyerrors and compiler infrastructure hazzle
- operandStack.box();
+ // these two are never reached in bytecode and only there
+ // to avoid verify errors and compiler infrastructure hazzle
+ operandStack.box();
operandStack.doGroovyCast(lhsType);
}
- // normal type transformation
- if (!ClassHelper.isPrimitiveType(lhsType) &&
isNull(rightExpression)) {
+ // normal type transformation
+ if (!ClassHelper.isPrimitiveType(lhsType) &&
isNullConstant(rightExpression)) {
operandStack.replace(lhsType);
} else {
operandStack.doGroovyCast(lhsType);
@@ -392,57 +397,53 @@ public class BinaryExpressionHelper {
} else {
rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType,
true);
}
- //TODO: if rhs is VariableSlotLoader already, then skip crating a new
one
- BytecodeExpression rhsValueLoader = new
VariableSlotLoader(rhsType,rhsValueId,operandStack);
-
+ // TODO: if rhs is VariableSlotLoader already, then skip crating a new
one
+ BytecodeExpression rhsValueLoader = new
VariableSlotLoader(rhsType,rhsValueId,operandStack);
+
// assignment for subscript
if (leftExpression instanceof BinaryExpression) {
BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
- if (leftBinExpr.getOperation().getType() ==
Types.LEFT_SQUARE_BRACKET) {
+ if (leftBinExpr.getOperation().getType() == LEFT_SQUARE_BRACKET) {
assignToArray(expression, leftBinExpr.getLeftExpression(),
leftBinExpr.getRightExpression(), rhsValueLoader);
}
compileStack.removeVar(rhsValueId);
return;
}
-
+
compileStack.pushLHS(true);
- // multiple declaration
if (leftExpression instanceof TupleExpression) {
+ // multiple declaration
TupleExpression tuple = (TupleExpression) leftExpression;
int i = 0;
for (Expression e : tuple.getExpressions()) {
- VariableExpression var = (VariableExpression) e;
- MethodCallExpression call = new MethodCallExpression(
- rhsValueLoader, "getAt",
- new ArgumentListExpression(new ConstantExpression(i)));
+ Expression call = new MethodCallExpression(rhsValueLoader,
"getAt",
+ new ArgumentListExpression(new ConstantExpression( i++
)));
call.visit(acg);
- i++;
if (defineVariable) {
- operandStack.doGroovyCast(var);
- compileStack.defineVariable(var, true);
+ Variable v = (Variable) e;
+ operandStack.doGroovyCast(v);
+ compileStack.defineVariable(v, true);
operandStack.remove(1);
} else {
- acg.visitVariableExpression(var);
+ e.visit(acg);
}
}
- }
- // single declaration
- else if (defineVariable) {
+ } else if (defineVariable) {
+ // single declaration
rhsValueLoader.visit(acg);
operandStack.remove(1);
compileStack.popLHS();
return;
- }
- // normal assignment
- else {
+ } else {
+ // normal assignment
int mark = operandStack.getStackLength();
rhsValueLoader.visit(acg);
leftExpression.visit(acg);
- operandStack.remove(operandStack.getStackLength()-mark);
+ operandStack.remove(operandStack.getStackLength() - mark);
}
compileStack.popLHS();
-
+
// return value of assignment
rhsValueLoader.visit(acg);
compileStack.removeVar(rhsValueId);
@@ -468,35 +469,35 @@ public class BinaryExpressionHelper {
boolean done = false;
if ( ClassHelper.isPrimitiveType(leftType) &&
- ClassHelper.isPrimitiveType(rightType))
+ ClassHelper.isPrimitiveType(rightType))
{
BinaryExpressionMultiTypeDispatcher helper = new
BinaryExpressionMultiTypeDispatcher(getController());
done = helper.doPrimitiveCompare(leftType, rightType, expression);
}
-
+
if (!done) {
AsmClassGenerator acg = controller.getAcg();
OperandStack operandStack = controller.getOperandStack();
-
+
leftExp.visit(acg);
operandStack.box();
rightExp.visit(acg);
operandStack.box();
-
+
compareMethod.call(controller.getMethodVisitor());
ClassNode resType = ClassHelper.boolean_TYPE;
if (compareMethod==findRegexMethod) {
resType = ClassHelper.OBJECT_TYPE;
- }
+ }
operandStack.replace(resType,2);
}
}
-
+
private void evaluateCompareTo(BinaryExpression expression) {
Expression leftExpression = expression.getLeftExpression();
AsmClassGenerator acg = controller.getAcg();
OperandStack operandStack = controller.getOperandStack();
-
+
leftExpression.visit(acg);
operandStack.box();
@@ -532,7 +533,7 @@ public class BinaryExpressionHelper {
mv.visitLabel(trueCase);
operandStack.remove(1); // have to remove 1 because of the GOTO
}
-
+
private void evaluateLogicalOrExpression(BinaryExpression expression) {
MethodVisitor mv = controller.getMethodVisitor();
AsmClassGenerator acg = controller.getAcg();
@@ -543,21 +544,21 @@ public class BinaryExpressionHelper {
expression.getLeftExpression().visit(acg);
operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
Label trueCase = operandStack.jump(IFNE);
-
+
expression.getRightExpression().visit(acg);
operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
Label falseCase = operandStack.jump(IFEQ);
-
+
mv.visitLabel(trueCase);
ConstantExpression.PRIM_TRUE.visit(acg);
operandStack.jump(GOTO, end);
mv.visitLabel(falseCase);
ConstantExpression.PRIM_FALSE.visit(acg);
-
+
mv.visitLabel(end);
}
-
+
protected void evaluateBinaryExpression(String message, BinaryExpression
binExp) {
CompileStack compileStack = controller.getCompileStack();
@@ -567,7 +568,7 @@ public class BinaryExpressionHelper {
// ensure VariableArguments are read, not stored
compileStack.pushLHS(false);
controller.getInvocationWriter().makeSingleArgumentCall(receiver,
message, arguments);
- compileStack.popLHS();
+ compileStack.popLHS();
}
protected void evaluateArrayAssignmentWithOperator(String method,
BinaryExpression expression, BinaryExpression leftBinExpr) {
@@ -603,28 +604,28 @@ public class BinaryExpressionHelper {
Expression leftExpression = expression.getLeftExpression();
AsmClassGenerator acg = controller.getAcg();
OperandStack operandStack = controller.getOperandStack();
-
+
if (leftExpression instanceof BinaryExpression) {
BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
- if (leftBinExpr.getOperation().getType() ==
Types.LEFT_SQUARE_BRACKET) {
+ if (leftBinExpr.getOperation().getType() == LEFT_SQUARE_BRACKET) {
evaluateArrayAssignmentWithOperator(method, expression,
leftBinExpr);
return;
}
- }
+ }
evaluateBinaryExpression(method, expression);
// br to leave a copy of rvalue on the stack. see also isPopRequired()
operandStack.dup();
-
+
controller.getCompileStack().pushLHS(true);
leftExpression.visit(acg);
controller.getCompileStack().popLHS();
}
-
+
private void evaluateInstanceof(BinaryExpression expression) {
OperandStack operandStack = controller.getOperandStack();
-
+
expression.getLeftExpression().visit(controller.getAcg());
operandStack.box();
Expression rightExp = expression.getRightExpression();
@@ -648,21 +649,21 @@ public class BinaryExpressionHelper {
private void evaluatePostfixMethod(int op, String method, Expression
expression, Expression orig) {
CompileStack compileStack = controller.getCompileStack();
final OperandStack operandStack = controller.getOperandStack();
-
+
// load Expressions
VariableSlotLoader usesSubscript = loadWithSubscript(expression);
// save copy for later
operandStack.dup();
- ClassNode expressionType = operandStack.getTopOperand();
+ ClassNode expressionType = operandStack.getTopOperand();
int tempIdx = compileStack.defineTemporaryVariable("postfix_" +
method, expressionType, true);
-
+
// execute Method
execMethodAndStoreForSubscriptOperator(op,method,expression,usesSubscript,orig);
-
+
// remove the result of the method call
- operandStack.pop();
-
+ operandStack.pop();
+
//reload saved value
operandStack.load(expressionType, tempIdx);
compileStack.removeVar(tempIdx);
@@ -672,10 +673,10 @@ public class BinaryExpressionHelper {
public void evaluatePostfixMethod(PostfixExpression expression) {
int op = expression.getOperation().getType();
switch (op) {
- case Types.PLUS_PLUS:
+ case PLUS_PLUS:
evaluatePostfixMethod(op, "next", expression.getExpression(),
expression);
break;
- case Types.MINUS_MINUS:
+ case MINUS_MINUS:
evaluatePostfixMethod(op, "previous",
expression.getExpression(), expression);
break;
}
@@ -684,33 +685,33 @@ public class BinaryExpressionHelper {
public void evaluatePrefixMethod(PrefixExpression expression) {
int type = expression.getOperation().getType();
switch (type) {
- case Types.PLUS_PLUS:
+ case PLUS_PLUS:
evaluatePrefixMethod(type, "next", expression.getExpression(),
expression);
break;
- case Types.MINUS_MINUS:
+ case MINUS_MINUS:
evaluatePrefixMethod(type, "previous",
expression.getExpression(), expression);
break;
}
}
-
+
private void evaluatePrefixMethod(int op, String method, Expression
expression, Expression orig) {
// load Expressions
VariableSlotLoader usesSubscript = loadWithSubscript(expression);
-
+
// execute Method
execMethodAndStoreForSubscriptOperator(op,method,expression,usesSubscript,orig);
// new value is already on stack, so nothing to do here
if (usesSubscript!=null)
controller.getCompileStack().removeVar(usesSubscript.getIndex());
}
-
+
private VariableSlotLoader loadWithSubscript(Expression expression) {
final OperandStack operandStack = controller.getOperandStack();
// if we have a BinaryExpression, let us check if it is with
// subscription
if (expression instanceof BinaryExpression) {
BinaryExpression be = (BinaryExpression) expression;
- if (be.getOperation().getType()==Types.LEFT_SQUARE_BRACKET) {
+ if (be.getOperation().getType() == LEFT_SQUARE_BRACKET) {
// right expression is the subscript expression
// we store the result of the subscription on the stack
Expression subscript = be.getRightExpression();
@@ -727,14 +728,14 @@ public class BinaryExpressionHelper {
newBe.setSourcePosition(be);
newBe.visit(controller.getAcg());
return subscriptExpression;
- }
- }
-
+ }
+ }
+
// normal loading of expression
expression.visit(controller.getAcg());
return null;
}
-
+
private void execMethodAndStoreForSubscriptOperator(int op, String method,
Expression expression, VariableSlotLoader usesSubscript, Expression orig) {
final OperandStack operandStack = controller.getOperandStack();
writePostOrPrefixMethod(op,method,expression,orig);
@@ -743,20 +744,20 @@ public class BinaryExpressionHelper {
if (usesSubscript!=null) {
CompileStack compileStack = controller.getCompileStack();
BinaryExpression be = (BinaryExpression) expression;
-
+
ClassNode methodResultType = operandStack.getTopOperand();
final int resultIdx =
compileStack.defineTemporaryVariable("postfix_" + method, methodResultType,
true);
BytecodeExpression methodResultLoader = new
VariableSlotLoader(methodResultType, resultIdx, operandStack);
-
- // execute the assignment, this will leave the right side
+
+ // execute the assignment, this will leave the right side
// (here the method call result) on the stack
assignToArray(be, be.getLeftExpression(), usesSubscript,
methodResultLoader);
compileStack.removeVar(resultIdx);
- }
+ }
// here we handle a.b++ and a++
else if (expression instanceof VariableExpression ||
- expression instanceof FieldExpression ||
+ expression instanceof FieldExpression ||
expression instanceof PropertyExpression)
{
operandStack.dup();
@@ -771,19 +772,19 @@ public class BinaryExpressionHelper {
final OperandStack operandStack = controller.getOperandStack();
// at this point the receiver will be already on the stack.
// in a[1]++ the method will be "++" aka "next" and the receiver a[1]
-
+
ClassNode BEType = controller.getTypeChooser().resolveType(expression,
controller.getClassNode());
Expression callSiteReceiverSwap = new BytecodeExpression(BEType) {
@Override
public void visit(MethodVisitor mv) {
- // CallSite is normally not showing up on the
+ // CallSite is normally not showing up on the
// operandStack, so we place a dummy here with same
// slot length.
operandStack.push(ClassHelper.OBJECT_TYPE);
// change (receiver,callsite) to (callsite,receiver)
operandStack.swap();
setType(operandStack.getTopOperand());
-
+
// no need to keep any of those on the operand stack
// after this expression is processed, the operand stack
// will contain callSiteReceiverSwap.getType()
@@ -793,7 +794,7 @@ public class BinaryExpressionHelper {
// execute method
// this will load the callsite and the receiver normally in the wrong
// order since the receiver is already present, but before the callsite
- // Therefore we use callSiteReceiverSwap to correct the order.
+ // Therefore we use callSiteReceiverSwap to correct the order.
// After this call the JVM operand stack will contain the result of
// the method call... usually simply Object in operandStack
controller.getCallSiteWriter().makeCallSite(
@@ -801,37 +802,37 @@ public class BinaryExpressionHelper {
method,
MethodCallExpression.NO_ARGUMENTS,
false, false, false, false);
- // now rhs is completely done and we need only to store. In a[1]++
this
+ // now rhs is completely done and we need only to store. In a[1]++ this
// would be a.getAt(1).next() for the rhs, "lhs" code is a.putAt(1,
rhs)
-
+
}
-
+
private void evaluateElvisOperatorExpression(ElvisOperatorExpression
expression) {
MethodVisitor mv = controller.getMethodVisitor();
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
TypeChooser typeChooser = controller.getTypeChooser();
-
+
Expression boolPart =
expression.getBooleanExpression().getExpression();
Expression falsePart = expression.getFalseExpression();
-
+
ClassNode truePartType = typeChooser.resolveType(boolPart,
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
+
+ // 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
+ // 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.
+ // 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 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
+ // 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
+ // 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();
@@ -842,66 +843,66 @@ public class BinaryExpressionHelper {
}
int retValueId = compileStack.defineTemporaryVariable("$t",
truePartType, true);
operandStack.castToBool(mark,true);
-
+
Label l0 = operandStack.jump(IFEQ);
// true part: load $t and cast to S
operandStack.load(truePartType, retValueId);
operandStack.doGroovyCast(common);
Label l1 = new Label();
mv.visitJumpInsn(GOTO, l1);
-
+
// false part: load false expression and cast to S
mv.visitLabel(l0);
- falsePart.visit(controller.getAcg());
+ falsePart.visit(controller.getAcg());
operandStack.doGroovyCast(common);
-
+
// finish and cleanup
mv.visitLabel(l1);
compileStack.removeVar(retValueId);
- controller.getOperandStack().replace(common, 2);
-
+ controller.getOperandStack().replace(common, 2);
+
}
private void evaluateNormalTernary(TernaryExpression expression) {
MethodVisitor mv = controller.getMethodVisitor();
OperandStack operandStack = controller.getOperandStack();
TypeChooser typeChooser = controller.getTypeChooser();
-
+
Expression boolPart = expression.getBooleanExpression();
Expression truePart = expression.getTrueExpression();
Expression falsePart = expression.getFalseExpression();
-
+
ClassNode truePartType = typeChooser.resolveType(truePart,
controller.getClassNode());
ClassNode falsePartType = typeChooser.resolveType(falsePart,
controller.getClassNode());
ClassNode common = WideningCategories.lowestUpperBound(truePartType,
falsePartType);
- // we compile b?x:y as
+ // 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
+ // 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
// load b and convert to boolean
int mark = operandStack.getStackLength();
boolPart.visit(controller.getAcg());
operandStack.castToBool(mark,true);
-
+
Label l0 = operandStack.jump(IFEQ);
// true part: load x and cast to S
truePart.visit(controller.getAcg());
operandStack.doGroovyCast(common);
Label l1 = new Label();
mv.visitJumpInsn(GOTO, l1);
-
+
// false part: load y and cast to S
mv.visitLabel(l0);
- falsePart.visit(controller.getAcg());
+ falsePart.visit(controller.getAcg());
operandStack.doGroovyCast(common);
-
+
// finish and cleanup
mv.visitLabel(l1);
- controller.getOperandStack().replace(common, 2);
-
+ controller.getOperandStack().replace(common, 2);
+
}
public void evaluateTernary(TernaryExpression expression) {
diff --git
a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
index 318f692b93..fa4eadce52 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
@@ -270,27 +270,26 @@ class StaticCompilationTest extends
AbstractBytecodeTestCase {
}
m 'Cedric'
''').hasStrictSequence([
- "ICONST",
- "INVOKESTATIC java/lang/Integer.valueOf
(I)Ljava/lang/Integer;",
- "ASTORE",
- "L1",
- "ALOAD 2",
- "POP",
- "L2",
- "LINENUMBER",
- "ALOAD 1",
- "ASTORE 3",
- "ALOAD 3",
- "ASTORE 2",
- "ALOAD 3",
- "POP",
- "L3",
- "LINENUMBER",
- "ALOAD 2",
- "CHECKCAST java/lang/String",
- "INVOKEVIRTUAL java/lang/String.toUpperCase
()Ljava/lang/String;",
- "ARETURN",
- "L4"
+ 'LINENUMBER 4',
+ 'ICONST_1',
+ 'INVOKESTATIC java/lang/Integer.valueOf
(I)Ljava/lang/Integer;',
+ 'ASTORE 2',
+ 'L1',
+ 'ALOAD 2',
+ 'POP',
+ 'L2',
+ 'LINENUMBER 5',
+ 'ALOAD 1',
+ 'DUP',
+ 'ASTORE 2',
+ 'POP',
+ 'L3',
+ 'LINENUMBER 6',
+ 'ALOAD 2',
+ 'CHECKCAST java/lang/String',
+ 'INVOKEVIRTUAL java/lang/String.toUpperCase
()Ljava/lang/String;',
+ 'ARETURN',
+ 'L4'
])
}