From b74bdb9cfdd3329ed0ccf2589d4d9ae4f531ecb6 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 8 Apr 2011 19:52:55 +0200 Subject: [PATCH] refactored conditional jump generation to enable and/or generation --- .../jet/codegen/ExpressionCodegen.java | 85 +++++++++++-------- .../org/jetbrains/jet/codegen/StackValue.java | 83 ++++++++---------- idea/testData/codegen/if.jet | 1 - idea/testData/codegen/singleBranchIf.jet | 4 - .../jet/codegen/NamespaceGenTest.java | 19 ++++- 5 files changed, 100 insertions(+), 92 deletions(-) delete mode 100644 idea/testData/codegen/if.jet delete mode 100644 idea/testData/codegen/singleBranchIf.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 90a0df7fd23..19ecfd9cc52 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -86,18 +86,20 @@ public class ExpressionCodegen extends JetVisitor { } if (thenExpression == null) { - generateSingleBranchIf(elseExpression, false); + generateSingleBranchIf(elseExpression, true); return; } if (elseExpression == null) { - generateSingleBranchIf(thenExpression, true); + generateSingleBranchIf(thenExpression, false); return; } + Label thenLabel = new Label(); Label elseLabel = new Label(); - myStack.pop().condJump(elseLabel, true, v); // == 0, i.e. false + myStack.pop().condJump(thenLabel, elseLabel, v); + v.mark(thenLabel); gen(thenExpression, asmType); @@ -123,7 +125,9 @@ public class ExpressionCodegen extends JetVisitor { myLoopEnds.push(end); gen(expression.getCondition()); - myStack.pop().condJump(end, true, v); + Label thenLabel = new Label(); + myStack.pop().condJump(thenLabel, end, v); + v.mark(thenLabel); gen(expression.getBody(), Type.VOID_TYPE); v.goTo(condition); @@ -145,7 +149,7 @@ public class ExpressionCodegen extends JetVisitor { gen(expression.getBody(), Type.VOID_TYPE); gen(expression.getCondition()); - myStack.pop().condJump(condition, false, v); + myStack.pop().condJump(condition, end, v); v.mark(end); @@ -176,13 +180,15 @@ public class ExpressionCodegen extends JetVisitor { } private void generateSingleBranchIf(JetExpression expression, boolean inverse) { - Label endLabel = new Label(); + Label ifTrue = new Label(); + Label ifFalse = new Label(); - myStack.pop().condJump(endLabel, inverse, v); + myStack.pop().condJump(inverse ? ifFalse : ifTrue, inverse ? ifTrue : ifFalse, v); + v.mark(ifTrue); gen(expression, Type.VOID_TYPE); - v.mark(endLabel); + v.mark(ifFalse); } @Override @@ -497,42 +503,49 @@ public class ExpressionCodegen extends JetVisitor { final IElementType opToken = expression.getOperationReference().getReferencedNameElementType(); if (opToken == JetTokens.EQ) { generateAssignmentExpression(expression); - return; } - if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { + else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { generateAugmentedAssignment(expression); - return; } - 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 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); } else { - throw new UnsupportedOperationException("Don't know how to generate equality for these types"); + 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 binary op " + expression); } - throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); + } + + private void generateBooleanExpression(JetBinaryExpression expression) { + throw new UnsupportedOperationException(); } private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) { @@ -594,7 +607,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)); + myStack.push(StackValue.cmp(opToken, type)); } 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 fb3ae926cbb..fa8f0b5da7c 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) { - return new NumberCompare(opToken); + public static StackValue cmp(IElementType opToken, Type operandType) { + return new NumberCompare(opToken, operandType); } public static StackValue not(StackValue stackValue) { return new Invert(stackValue); } - public abstract void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v); + public abstract void condJump(Label jumpIfTrue, Label jumpIfFalse, InstructionAdapter v); private static void box(final Type type, InstructionAdapter v) { if (type == Type.INT_TYPE) { @@ -80,8 +80,10 @@ public abstract class StackValue { protected void putAsBoolean(InstructionAdapter v) { Label ifTrue = new Label(); + Label ifFalse = new Label(); Label end = new Label(); - condJump(ifTrue, false, v); + condJump(ifTrue, ifFalse, v); + v.mark(ifFalse); v.iconst(0); v.goTo(end); v.mark(ifTrue); @@ -105,14 +107,11 @@ public abstract class StackValue { } @Override - public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { put(Type.INT_TYPE, v); - if (jumpIfFalse) { - v.ifeq(label); - } - else { - v.ifne(label); - } + // TODO optimize extra jump away + v.ifne(ifTrue); + v.goTo(ifFalse); } } @@ -127,14 +126,11 @@ public abstract class StackValue { } @Override - public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { if (this.type == Type.BOOLEAN_TYPE) { - if (jumpIfFalse) { - v.ifeq(label); - } - else { - v.ifne(label); - } + // TODO optimize extra jump away + v.ifne(ifTrue); + v.goTo(ifFalse); } else { throw new UnsupportedOperationException("can't generate a cond jump for a non-boolean value on stack"); @@ -157,12 +153,10 @@ public abstract class StackValue { } @Override - public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { if (value instanceof Boolean) { boolean boolValue = ((Boolean) value).booleanValue(); - if (boolValue ^ jumpIfFalse) { - v.goTo(label); - } + v.goTo(boolValue ? ifTrue : ifFalse); } else { throw new UnsupportedOperationException("don't know how to generate this condjump"); @@ -172,10 +166,12 @@ public abstract class StackValue { private static class NumberCompare extends StackValue { private final IElementType opToken; + private final Type operandType; - public NumberCompare(IElementType opToken) { + public NumberCompare(IElementType opToken, Type operandType) { super(Type.BOOLEAN_TYPE); this.opToken = opToken; + this.operandType = operandType; } @Override @@ -187,44 +183,33 @@ public abstract class StackValue { } @Override - public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { int opcode; - 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; - } + 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; else { throw new UnsupportedOperationException("don't know how to generate this condjump"); } - if (type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE) { + if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) { if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { - v.cmpg(type); + v.cmpg(operandType); } else { - v.cmpl(type); + v.cmpl(operandType); } } - else if (type == Type.LONG_TYPE) { + else if (operandType == Type.LONG_TYPE) { v.lcmp(); } else { opcode += (Opcodes.IF_ICMPEQ - Opcodes.IFEQ); } - v.visitJumpInsn(opcode, label); + v.visitJumpInsn(opcode, ifTrue); + v.goTo(ifFalse); } } @@ -245,8 +230,8 @@ public abstract class StackValue { } @Override - public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { - myOperand.condJump(label, !jumpIfFalse, v); + public void condJump(Label ifTrue, Label ifFalse, InstructionAdapter v) { + myOperand.condJump(ifFalse, ifTrue, v); } } } diff --git a/idea/testData/codegen/if.jet b/idea/testData/codegen/if.jet deleted file mode 100644 index 282a87e267b..00000000000 --- a/idea/testData/codegen/if.jet +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 29001194b38..00000000000 --- a/idea/testData/codegen/singleBranchIf.jet +++ /dev/null @@ -1,4 +0,0 @@ -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 51b8c0e2002..2fee7689398 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 { - loadFile("if.jet"); + loadText("fun foo(b: Boolean): Int { return if (b) 15 else 20 }"); System.out.println(generateToText()); final Method main = generateFunction(); @@ -118,7 +118,7 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { } public void testSingleBranchIf() throws Exception { - loadFile("singleBranchIf.jet"); + loadText("fun foo(b: Boolean) : Int { if (b) return 15;\n return 20; }"); System.out.println(generateToText()); final Method main = generateFunction(); @@ -451,6 +451,21 @@ 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());