From 707408b241ed71742a58b57f3c657b64af9305f8 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 23 Aug 2012 20:44:12 +0400 Subject: [PATCH] For loops over arrays generated with multi-decl support --- .../jet/codegen/ExpressionCodegen.java | 84 +++++++++++-------- .../multiDecl/forArray/MultiDeclFor.kt | 18 ++++ .../MultiDeclForComponentExtensions.kt | 19 +++++ .../MultiDeclForComponentMemberExtensions.kt | 21 +++++ ...nentMemberExtensionsInExtensionFunction.kt | 21 +++++ .../forArray/MultiDeclForValCaptured.kt | 18 ++++ .../jet/codegen/MultiDeclTestGenerated.java | 34 ++++++++ 7 files changed, 180 insertions(+), 35 deletions(-) create mode 100644 compiler/testData/codegen/multiDecl/forArray/MultiDeclFor.kt create mode 100644 compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentExtensions.kt create mode 100644 compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensions.kt create mode 100644 compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt create mode 100644 compiler/testData/codegen/multiDecl/forArray/MultiDeclForValCaptured.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 44ccd6d3fa6..8a7a101e692 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -384,7 +384,7 @@ public class ExpressionCodegen extends JetVisitor { assert expressionType != null; Type loopRangeType = asmType(expressionType); if (loopRangeType.getSort() == Type.ARRAY) { - new ForInArrayLoopGenerator(expression, loopRangeType).invoke(); + generateForLoop(expression.getBody(), new ForInArrayLoopGenerator(expression)); return StackValue.none(); } else { @@ -410,7 +410,7 @@ public class ExpressionCodegen extends JetVisitor { private interface ForLoopGenerator { void beforeLoop(); - void condition(); + void conditionAndJump(@NotNull Label loopExit); void beforeBody(); void afterBody(); void afterLoop(); @@ -423,8 +423,7 @@ public class ExpressionCodegen extends JetVisitor { generator.beforeLoop(); v.mark(loopEntry); - generator.condition(); - v.ifeq(loopExit); + generator.conditionAndJump(loopExit); generator.beforeBody(); blockStackElements.push(new LoopBlockStackElement(loopExit, loopEntry, null)); @@ -446,7 +445,7 @@ public class ExpressionCodegen extends JetVisitor { private final Label bodyEnd = new Label(); private final List leaveVariableTasks = Lists.newArrayList(); - private final JetType elementType; + protected final JetType elementType; private AbstractForLoopGenerator( @NotNull JetForExpression forExpression @@ -580,7 +579,7 @@ public class ExpressionCodegen extends JetVisitor { } @Override - public void condition() { + public void conditionAndJump(@NotNull Label loopExit) { // tmp.hasNext() JetExpression loopRange = forExpression.getLoopRange(); @@ -595,6 +594,7 @@ public class ExpressionCodegen extends JetVisitor { Type asmType = asmType(type); StackValue.coerce(asmType, Type.BOOLEAN_TYPE, v); + v.ifeq(loopExit); } @Override @@ -669,72 +669,86 @@ public class ExpressionCodegen extends JetVisitor { } } - private class ForInArrayLoopGenerator extends IntrinsicForLoopGenerator { + private class ForInArrayLoopGenerator extends AbstractForLoopGenerator { private int myIndexVar; private int myArrayVar; - private boolean localArrayVar; + private Runnable afterLoopAction; + private final JetType loopRangeType; - public ForInArrayLoopGenerator(JetForExpression expression, Type loopRangeType) { - super(expression, loopRangeType); + private ForInArrayLoopGenerator(@NotNull JetForExpression forExpression) { + super(forExpression); + loopRangeType = bindingContext.get(BindingContext.EXPRESSION_TYPE, forExpression.getLoopRange()); } @Override - protected void generatePrologue() { + public void beforeLoop() { myIndexVar = myFrameMap.enterTemp(Type.INT_TYPE); - StackValue value = gen(expression.getLoopRange()); + JetExpression loopRange = forExpression.getLoopRange(); + StackValue value = gen(loopRange); if (value instanceof StackValue.Local) { myArrayVar = ((StackValue.Local) value).index; - localArrayVar = true; } else { myArrayVar = myFrameMap.enterTemp(TYPE_OBJECT); - value.put(loopRangeType, v); + afterLoopAction = new Runnable() { + @Override + public void run() { + myFrameMap.leaveTemp(TYPE_OBJECT); + } + }; + Type asmLoopRangeType = asmType(loopRangeType); + value.put(asmLoopRangeType, v); v.store(myArrayVar, TYPE_OBJECT); } - if (expressionType.isNullable()) { - v.load(myArrayVar, TYPE_OBJECT); - v.ifnull(end); - } + //if (loopRangeType.isNullable()) { + // v.load(myArrayVar, TYPE_OBJECT); + // v.ifnull(end); + //} v.iconst(0); v.store(myIndexVar, Type.INT_TYPE); } @Override - protected void generateCondition(Type asmParamType, Label end) { - Type arrayElParamType; - if (JetStandardLibraryNames.ARRAY.is(expressionType)) { - arrayElParamType = boxType(asmParamType); - } - else { - arrayElParamType = asmParamType; - } - + public void conditionAndJump(@NotNull Label loopExit) { v.load(myIndexVar, Type.INT_TYPE); v.load(myArrayVar, TYPE_OBJECT); v.arraylength(); - v.ificmpge(end); + v.ificmpge(loopExit); + } + + @Override + protected void assignToLoopParameter(int parameterIndex) { + Type arrayElParamType; + Type asmElementType = asmType(elementType); + if (JetStandardLibraryNames.ARRAY.is(loopRangeType)) { + arrayElParamType = boxType(asmElementType); + } + else { + arrayElParamType = asmElementType; + } v.load(myArrayVar, TYPE_OBJECT); v.load(myIndexVar, Type.INT_TYPE); v.aload(arrayElParamType); - StackValue.onStack(arrayElParamType).put(asmParamType, v); - v.store(lookupLocal(parameterDescriptor), asmParamType); + StackValue.onStack(arrayElParamType).put(asmElementType, v); + v.store(parameterIndex, asmElementType); } @Override - protected void generateIncrement() { + public void afterBody() { v.iinc(myIndexVar, 1); + super.afterBody(); } @Override - protected void cleanupTemp() { - myFrameMap.leaveTemp(Type.INT_TYPE); - if (!localArrayVar) { - myFrameMap.leaveTemp(TYPE_OBJECT); + public void afterLoop() { + if (afterLoopAction != null) { + afterLoopAction.run(); } + myFrameMap.leaveTemp(Type.INT_TYPE); } } diff --git a/compiler/testData/codegen/multiDecl/forArray/MultiDeclFor.kt b/compiler/testData/codegen/multiDecl/forArray/MultiDeclFor.kt new file mode 100644 index 00000000000..9ae7bc19e81 --- /dev/null +++ b/compiler/testData/codegen/multiDecl/forArray/MultiDeclFor.kt @@ -0,0 +1,18 @@ +class C(val i: Int) { + fun component1() = i + 1 + fun component2() = i + 2 +} + +fun doTest(l : Array): String { + var s = "" + for ((a, b) in l) { + s += "$a:$b;" + } + return s +} + +fun box(): String { + val l = Array(3, {x -> C(x)}) + val s = doTest(l) + return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s" +} \ No newline at end of file diff --git a/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentExtensions.kt b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentExtensions.kt new file mode 100644 index 00000000000..dea403c786c --- /dev/null +++ b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentExtensions.kt @@ -0,0 +1,19 @@ +class C(val i: Int) { +} + +fun C.component1() = i + 1 +fun C.component2() = i + 2 + +fun doTest(l : Array): String { + var s = "" + for ((a, b) in l) { + s += "$a:$b;" + } + return s +} + +fun box(): String { + val l = Array(3, {x -> C(x)}) + val s = doTest(l) + return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s" +} \ No newline at end of file diff --git a/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensions.kt b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensions.kt new file mode 100644 index 00000000000..8579b88efc4 --- /dev/null +++ b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensions.kt @@ -0,0 +1,21 @@ +class C(val i: Int) { +} + +class M { + fun C.component1() = i + 1 + fun C.component2() = i + 2 + + fun doTest(l : Array): String { + var s = "" + for ((a, b) in l) { + s += "$a:$b;" + } + return s + } +} + +fun box(): String { + val l = Array(3, {x -> C(x)}) + val s = M().doTest(l) + return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s" +} \ No newline at end of file diff --git a/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt new file mode 100644 index 00000000000..298a71a5146 --- /dev/null +++ b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt @@ -0,0 +1,21 @@ +class C(val i: Int) { +} + +class M { + fun C.component1() = i + 1 + fun C.component2() = i + 2 +} + +fun M.doTest(l : Array): String { + var s = "" + for ((a, b) in l) { + s += "$a:$b;" + } + return s +} + +fun box(): String { + val l = Array(3, {x -> C(x)}) + val s = M().doTest(l) + return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s" +} \ No newline at end of file diff --git a/compiler/testData/codegen/multiDecl/forArray/MultiDeclForValCaptured.kt b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForValCaptured.kt new file mode 100644 index 00000000000..88d24eddce8 --- /dev/null +++ b/compiler/testData/codegen/multiDecl/forArray/MultiDeclForValCaptured.kt @@ -0,0 +1,18 @@ +class C(val i: Int) { + fun component1() = i + 1 + fun component2() = i + 2 +} + +fun doTest(l : Array): String { + var s = "" + for ((a, b) in l) { + s += {"$a:$b;"}() + } + return s +} + +fun box(): String { + val l = Array(3, {x -> C(x)}) + val s = doTest(l) + return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/MultiDeclTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/MultiDeclTestGenerated.java index 8028f7cec6b..599001e4679 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/MultiDeclTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/MultiDeclTestGenerated.java @@ -82,6 +82,39 @@ public class MultiDeclTestGenerated extends AbstractMultiDeclTestCase { blackBoxFileByFullPath("compiler/testData/codegen/multiDecl/VarCapturedInObjectLiteral.kt"); } + @TestMetadata("compiler/testData/codegen/multiDecl/forArray") + public static class ForArray extends AbstractMultiDeclTestCase { + public void testAllFilesPresentInForArray() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.codegen.AbstractMultiDeclTestCase", new File("compiler/testData/codegen/multiDecl/forArray"), "kt", false); + } + + @TestMetadata("MultiDeclFor.kt") + public void testMultiDeclFor() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/multiDecl/forArray/MultiDeclFor.kt"); + } + + @TestMetadata("MultiDeclForComponentExtensions.kt") + public void testMultiDeclForComponentExtensions() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentExtensions.kt"); + } + + @TestMetadata("MultiDeclForComponentMemberExtensions.kt") + public void testMultiDeclForComponentMemberExtensions() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensions.kt"); + } + + @TestMetadata("MultiDeclForComponentMemberExtensionsInExtensionFunction.kt") + public void testMultiDeclForComponentMemberExtensionsInExtensionFunction() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/multiDecl/forArray/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt"); + } + + @TestMetadata("MultiDeclForValCaptured.kt") + public void testMultiDeclForValCaptured() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/multiDecl/forArray/MultiDeclForValCaptured.kt"); + } + + } + @TestMetadata("compiler/testData/codegen/multiDecl/forIterator") public static class ForIterator extends AbstractMultiDeclTestCase { public void testAllFilesPresentInForIterator() throws Exception { @@ -118,6 +151,7 @@ public class MultiDeclTestGenerated extends AbstractMultiDeclTestCase { public static Test suite() { TestSuite suite = new TestSuite("MultiDeclTestGenerated"); suite.addTestSuite(MultiDeclTestGenerated.class); + suite.addTestSuite(ForArray.class); suite.addTestSuite(ForIterator.class); return suite; }