For loops over arrays generated with multi-decl support

This commit is contained in:
Andrey Breslav
2012-08-23 20:44:12 +04:00
parent d5c44c3dd8
commit 707408b241
7 changed files with 180 additions and 35 deletions
@@ -384,7 +384,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
private final Label bodyEnd = new Label();
private final List<Runnable> 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<StackValue, StackValue> {
}
@Override
public void condition() {
public void conditionAndJump(@NotNull Label loopExit) {
// tmp<iterator>.hasNext()
JetExpression loopRange = forExpression.getLoopRange();
@@ -595,6 +594,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Type asmType = asmType(type);
StackValue.coerce(asmType, Type.BOOLEAN_TYPE, v);
v.ifeq(loopExit);
}
@Override
@@ -669,72 +669,86 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
}
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);
}
}
@@ -0,0 +1,18 @@
class C(val i: Int) {
fun component1() = i + 1
fun component2() = i + 2
}
fun doTest(l : Array<C>): String {
var s = ""
for ((a, b) in l) {
s += "$a:$b;"
}
return s
}
fun box(): String {
val l = Array<C>(3, {x -> C(x)})
val s = doTest(l)
return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s"
}
@@ -0,0 +1,19 @@
class C(val i: Int) {
}
fun C.component1() = i + 1
fun C.component2() = i + 2
fun doTest(l : Array<C>): String {
var s = ""
for ((a, b) in l) {
s += "$a:$b;"
}
return s
}
fun box(): String {
val l = Array<C>(3, {x -> C(x)})
val s = doTest(l)
return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s"
}
@@ -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<C>): String {
var s = ""
for ((a, b) in l) {
s += "$a:$b;"
}
return s
}
}
fun box(): String {
val l = Array<C>(3, {x -> C(x)})
val s = M().doTest(l)
return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s"
}
@@ -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<C>): String {
var s = ""
for ((a, b) in l) {
s += "$a:$b;"
}
return s
}
fun box(): String {
val l = Array<C>(3, {x -> C(x)})
val s = M().doTest(l)
return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s"
}
@@ -0,0 +1,18 @@
class C(val i: Int) {
fun component1() = i + 1
fun component2() = i + 2
}
fun doTest(l : Array<C>): String {
var s = ""
for ((a, b) in l) {
s += {"$a:$b;"}()
}
return s
}
fun box(): String {
val l = Array<C>(3, {x -> C(x)})
val s = doTest(l)
return if (s == "1:2;2:3;3:4;") "OK" else "fail: $s"
}
@@ -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;
}