diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 19ecfd9cc52..90a0df7fd23 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -86,20 +86,18 @@ public class ExpressionCodegen extends JetVisitor { } if (thenExpression == null) { - generateSingleBranchIf(elseExpression, true); + generateSingleBranchIf(elseExpression, false); return; } if (elseExpression == null) { - generateSingleBranchIf(thenExpression, false); + generateSingleBranchIf(thenExpression, true); return; } - Label thenLabel = new Label(); Label elseLabel = new Label(); - myStack.pop().condJump(thenLabel, elseLabel, v); - v.mark(thenLabel); + myStack.pop().condJump(elseLabel, true, v); // == 0, i.e. false gen(thenExpression, asmType); @@ -125,9 +123,7 @@ public class ExpressionCodegen extends JetVisitor { myLoopEnds.push(end); gen(expression.getCondition()); - Label thenLabel = new Label(); - myStack.pop().condJump(thenLabel, end, v); - v.mark(thenLabel); + myStack.pop().condJump(end, true, v); gen(expression.getBody(), Type.VOID_TYPE); v.goTo(condition); @@ -149,7 +145,7 @@ public class ExpressionCodegen extends JetVisitor { gen(expression.getBody(), Type.VOID_TYPE); gen(expression.getCondition()); - myStack.pop().condJump(condition, end, v); + myStack.pop().condJump(condition, false, v); v.mark(end); @@ -180,15 +176,13 @@ public class ExpressionCodegen extends JetVisitor { } private void generateSingleBranchIf(JetExpression expression, boolean inverse) { - Label ifTrue = new Label(); - Label ifFalse = new Label(); + Label endLabel = new Label(); - myStack.pop().condJump(inverse ? ifFalse : ifTrue, inverse ? ifTrue : ifFalse, v); - v.mark(ifTrue); + myStack.pop().condJump(endLabel, inverse, v); gen(expression, Type.VOID_TYPE); - v.mark(ifFalse); + v.mark(endLabel); } @Override @@ -503,49 +497,42 @@ public class ExpressionCodegen extends JetVisitor { final IElementType opToken = expression.getOperationReference().getReferencedNameElementType(); if (opToken == JetTokens.EQ) { generateAssignmentExpression(expression); + return; } - else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { + if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { generateAugmentedAssignment(expression); + return; } - else if (opToken == JetTokens.ANDAND) { - generateBooleanExpression(expression); - } - else { - DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); - if (op instanceof FunctionDescriptor) { - JetType returnType = bindingContext.getExpressionType(expression); - final Type asmType = typeMapper.mapType(returnType); - DeclarationDescriptor cls = op.getContainingDeclaration(); - if (isNumberPrimitive(cls)) { - if (op.getName().equals("compareTo")) { - generateCompareOp(expression, opToken, asmType); + DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); + if (op instanceof FunctionDescriptor) { + JetType returnType = bindingContext.getExpressionType(expression); + final Type asmType = typeMapper.mapType(returnType); + DeclarationDescriptor cls = op.getContainingDeclaration(); + if (isNumberPrimitive(cls)) { + if (op.getName().equals("compareTo")) { + generateCompareOp(expression, opToken, asmType); + } + else { + int opcode = opcodeForMethod(op.getName()); + generateBinaryOp(expression, (FunctionDescriptor) op, opcode); + } + return; + } + else if (isClass(cls, "Hashable")) { + if (op.getName().equals("equals")) { + final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft())); + final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight())); + if (isNumberPrimitive(leftType) && leftType == rightType) { + generateCompareOp(expression, opToken, leftType); + return; } else { - int opcode = opcodeForMethod(op.getName()); - generateBinaryOp(expression, (FunctionDescriptor) op, opcode); - } - return; - } - else if (isClass(cls, "Hashable")) { - if (op.getName().equals("equals")) { - final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft())); - final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight())); - if (isNumberPrimitive(leftType) && leftType == rightType) { - generateCompareOp(expression, opToken, leftType); - return; - } - else { - throw new UnsupportedOperationException("Don't know how to generate equality for these types"); - } + throw new UnsupportedOperationException("Don't know how to generate equality for these types"); } } } - throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); } - } - - private void generateBooleanExpression(JetBinaryExpression expression) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); } private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) { @@ -607,7 +594,7 @@ public class ExpressionCodegen extends JetVisitor { private void generateCompareOp(JetBinaryExpression expression, IElementType opToken, Type type) { gen(expression.getLeft(), type); gen(expression.getRight(), type); - myStack.push(StackValue.cmp(opToken, type)); + myStack.push(StackValue.cmp(opToken)); } private void generateAssignmentExpression(JetBinaryExpression expression) { diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index fa8f0b5da7c..fb3ae926cbb 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -32,15 +32,15 @@ public abstract class StackValue { return new Constant(value, type); } - public static StackValue cmp(IElementType opToken, Type operandType) { - return new NumberCompare(opToken, operandType); + public static StackValue cmp(IElementType opToken) { + return new NumberCompare(opToken); } public static StackValue not(StackValue stackValue) { return new Invert(stackValue); } - public abstract void condJump(Label jumpIfTrue, Label jumpIfFalse, InstructionAdapter v); + public abstract void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v); private static void box(final Type type, InstructionAdapter v) { if (type == Type.INT_TYPE) { @@ -80,10 +80,8 @@ public abstract class StackValue { protected void putAsBoolean(InstructionAdapter v) { Label ifTrue = new Label(); - Label ifFalse = new Label(); Label end = new Label(); - condJump(ifTrue, ifFalse, v); - v.mark(ifFalse); + condJump(ifTrue, false, v); v.iconst(0); v.goTo(end); v.mark(ifTrue); @@ -107,11 +105,14 @@ public abstract class StackValue { } @Override - public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { put(Type.INT_TYPE, v); - // TODO optimize extra jump away - v.ifne(ifTrue); - v.goTo(ifFalse); + if (jumpIfFalse) { + v.ifeq(label); + } + else { + v.ifne(label); + } } } @@ -126,11 +127,14 @@ public abstract class StackValue { } @Override - public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { if (this.type == Type.BOOLEAN_TYPE) { - // TODO optimize extra jump away - v.ifne(ifTrue); - v.goTo(ifFalse); + if (jumpIfFalse) { + v.ifeq(label); + } + else { + v.ifne(label); + } } else { throw new UnsupportedOperationException("can't generate a cond jump for a non-boolean value on stack"); @@ -153,10 +157,12 @@ public abstract class StackValue { } @Override - public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { if (value instanceof Boolean) { boolean boolValue = ((Boolean) value).booleanValue(); - v.goTo(boolValue ? ifTrue : ifFalse); + if (boolValue ^ jumpIfFalse) { + v.goTo(label); + } } else { throw new UnsupportedOperationException("don't know how to generate this condjump"); @@ -166,12 +172,10 @@ public abstract class StackValue { private static class NumberCompare extends StackValue { private final IElementType opToken; - private final Type operandType; - public NumberCompare(IElementType opToken, Type operandType) { + public NumberCompare(IElementType opToken) { super(Type.BOOLEAN_TYPE); this.opToken = opToken; - this.operandType = operandType; } @Override @@ -183,33 +187,44 @@ public abstract class StackValue { } @Override - public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { int opcode; - if (opToken == JetTokens.EQEQ) opcode = Opcodes.IFEQ; - else if (opToken == JetTokens.EXCLEQ) opcode = Opcodes.IFNE; - else if (opToken == JetTokens.GT) opcode = Opcodes.IFGT; - else if (opToken == JetTokens.GTEQ) opcode = Opcodes.IFGE; - else if (opToken == JetTokens.LT) opcode = Opcodes.IFLT; - else if (opToken == JetTokens.LTEQ) opcode = Opcodes.IFLE; + if (opToken == JetTokens.EQEQ) { + opcode = jumpIfFalse ? Opcodes.IFNE : Opcodes.IFEQ; + } + else if (opToken == JetTokens.EXCLEQ) { + opcode = jumpIfFalse ? Opcodes.IFEQ : Opcodes.IFNE; + } + else if (opToken == JetTokens.GT) { + opcode = jumpIfFalse ? Opcodes.IFLE : Opcodes.IFGT; + } + else if (opToken == JetTokens.GTEQ) { + opcode = jumpIfFalse ? Opcodes.IFLT : Opcodes.IFGE; + } + else if (opToken == JetTokens.LT) { + opcode = jumpIfFalse ? Opcodes.IFGE : Opcodes.IFLT; + } + else if (opToken == JetTokens.LTEQ) { + opcode = jumpIfFalse ? Opcodes.IFGT : Opcodes.IFLE; + } else { throw new UnsupportedOperationException("don't know how to generate this condjump"); } - if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) { + if (type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE) { if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { - v.cmpg(operandType); + v.cmpg(type); } else { - v.cmpl(operandType); + v.cmpl(type); } } - else if (operandType == Type.LONG_TYPE) { + else if (type == Type.LONG_TYPE) { v.lcmp(); } else { opcode += (Opcodes.IF_ICMPEQ - Opcodes.IFEQ); } - v.visitJumpInsn(opcode, ifTrue); - v.goTo(ifFalse); + v.visitJumpInsn(opcode, label); } } @@ -230,8 +245,8 @@ public abstract class StackValue { } @Override - public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { - myOperand.condJump(ifFalse, ifTrue, v); + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + myOperand.condJump(label, !jumpIfFalse, v); } } } diff --git a/idea/testData/codegen/if.jet b/idea/testData/codegen/if.jet new file mode 100644 index 00000000000..282a87e267b --- /dev/null +++ b/idea/testData/codegen/if.jet @@ -0,0 +1 @@ +fun foo(b: Boolean): Int { return if (b) 15 else 20 } \ No newline at end of file diff --git a/idea/testData/codegen/singleBranchIf.jet b/idea/testData/codegen/singleBranchIf.jet new file mode 100644 index 00000000000..29001194b38 --- /dev/null +++ b/idea/testData/codegen/singleBranchIf.jet @@ -0,0 +1,4 @@ +fun foo(b: Boolean) : Int { + if (b) return 15; + return 20; +} diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 2fee7689398..51b8c0e2002 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -109,7 +109,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { } public void testIf() throws Exception { - loadText("fun foo(b: Boolean): Int { return if (b) 15 else 20 }"); + loadFile("if.jet"); System.out.println(generateToText()); final Method main = generateFunction(); @@ -118,7 +118,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { } public void testSingleBranchIf() throws Exception { - loadText("fun foo(b: Boolean) : Int { if (b) return 15;\n return 20; }"); + loadFile("singleBranchIf.jet"); System.out.println(generateToText()); final Method main = generateFunction(); @@ -451,21 +451,6 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals(0, main.invoke(null, 4)); } - public void _testAnd() throws Exception { - loadText("fun foo(a : Int): Boolean = a > 0 && a/0 > 0"); - final Method main = generateFunction(); - assertEquals(false, main.invoke(null, 0)); - boolean hadException = false; - try { - main.invoke(null, 5); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof ArithmeticException) { - hadException = true; - } - } - assertTrue(hadException); - } - private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception { loadText(text); System.out.println(generateToText());