[es6] Implement for-of iterator finalization
Implements iterator finalisation by desugaring for-of loops with an additional try-finally wrapper. See comment in parser.cc for details.
Also improved some AST printing facilities while there.
@Ross, I had to disable the bytecode generation test for for-of, because it got completely out of hand after this change (the new bytecode has 150+ lines). See the TODO that I assigned to you.
Patch set 1 is WIP patch by Georg (http://crrev.com/1695583003), patch set 2 relative changes.
@Georg, FYI, I changed the following:
- Moved try-finally out of the loop body, for performance, and in order to be able to handle `continue` correctly.
- Fixed scope management in ParseForStatement, which was the cause for the variable allocation failure.
- Fixed pre-existing zone initialisation bug in rewriter, which caused the crashes.
- Enabled all tests, adjusted a few others, added a couple more.
BUG=v8:2214
LOG=Y
Review URL: https://codereview.chromium.org/1695393003
Cr-Commit-Position: refs/heads/master@{#34111}
2016-02-18 10:49:07 +00:00
|
|
|
// Copyright 2016 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
// Flags: --harmony-iterator-close
|
|
|
|
|
|
|
|
function* g() { yield 42; return 88 };
|
|
|
|
|
|
|
|
|
|
|
|
// Return method is "undefined".
|
|
|
|
{
|
|
|
|
g.prototype.return = null;
|
|
|
|
|
|
|
|
assertEquals(undefined, (() => {
|
|
|
|
for (let x of g()) { break; }
|
|
|
|
})());
|
|
|
|
|
|
|
|
assertEquals(undefined, (() => {
|
|
|
|
for (x of g()) { break; }
|
|
|
|
})());
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g()) { throw 42; }
|
|
|
|
}, 42);
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x of g()) { throw 42; }
|
|
|
|
}, 42);
|
|
|
|
|
|
|
|
assertEquals(42, (() => {
|
|
|
|
for (let x of g()) { return 42; }
|
|
|
|
})());
|
|
|
|
|
|
|
|
assertEquals(42, (() => {
|
|
|
|
for (x of g()) { return 42; }
|
|
|
|
})());
|
|
|
|
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return method is not callable.
|
|
|
|
{
|
|
|
|
g.prototype.return = 666;
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (let x of g()) { break; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (x of g()) { break; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (let x of g()) { throw 666; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (x of g()) { throw 666; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (let x of g()) { return 666; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (x of g()) { return 666; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return method does not return an object.
|
|
|
|
{
|
|
|
|
g.prototype.return = () => 666;
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (let x of g()) { break; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (x of g()) { break; }
|
|
|
|
}, TypeError);
|
|
|
|
|
2016-02-24 18:21:32 +00:00
|
|
|
// Throw from the body of a for loop 'wins' vs throw
|
|
|
|
// originating from a bad 'return' value.
|
|
|
|
assertThrowsEquals(() => {
|
[es6] Implement for-of iterator finalization
Implements iterator finalisation by desugaring for-of loops with an additional try-finally wrapper. See comment in parser.cc for details.
Also improved some AST printing facilities while there.
@Ross, I had to disable the bytecode generation test for for-of, because it got completely out of hand after this change (the new bytecode has 150+ lines). See the TODO that I assigned to you.
Patch set 1 is WIP patch by Georg (http://crrev.com/1695583003), patch set 2 relative changes.
@Georg, FYI, I changed the following:
- Moved try-finally out of the loop body, for performance, and in order to be able to handle `continue` correctly.
- Fixed scope management in ParseForStatement, which was the cause for the variable allocation failure.
- Fixed pre-existing zone initialisation bug in rewriter, which caused the crashes.
- Enabled all tests, adjusted a few others, added a couple more.
BUG=v8:2214
LOG=Y
Review URL: https://codereview.chromium.org/1695393003
Cr-Commit-Position: refs/heads/master@{#34111}
2016-02-18 10:49:07 +00:00
|
|
|
for (let x of g()) { throw 666; }
|
2016-02-24 18:21:32 +00:00
|
|
|
}, 666);
|
[es6] Implement for-of iterator finalization
Implements iterator finalisation by desugaring for-of loops with an additional try-finally wrapper. See comment in parser.cc for details.
Also improved some AST printing facilities while there.
@Ross, I had to disable the bytecode generation test for for-of, because it got completely out of hand after this change (the new bytecode has 150+ lines). See the TODO that I assigned to you.
Patch set 1 is WIP patch by Georg (http://crrev.com/1695583003), patch set 2 relative changes.
@Georg, FYI, I changed the following:
- Moved try-finally out of the loop body, for performance, and in order to be able to handle `continue` correctly.
- Fixed scope management in ParseForStatement, which was the cause for the variable allocation failure.
- Fixed pre-existing zone initialisation bug in rewriter, which caused the crashes.
- Enabled all tests, adjusted a few others, added a couple more.
BUG=v8:2214
LOG=Y
Review URL: https://codereview.chromium.org/1695393003
Cr-Commit-Position: refs/heads/master@{#34111}
2016-02-18 10:49:07 +00:00
|
|
|
|
2016-02-24 18:21:32 +00:00
|
|
|
assertThrowsEquals(() => {
|
[es6] Implement for-of iterator finalization
Implements iterator finalisation by desugaring for-of loops with an additional try-finally wrapper. See comment in parser.cc for details.
Also improved some AST printing facilities while there.
@Ross, I had to disable the bytecode generation test for for-of, because it got completely out of hand after this change (the new bytecode has 150+ lines). See the TODO that I assigned to you.
Patch set 1 is WIP patch by Georg (http://crrev.com/1695583003), patch set 2 relative changes.
@Georg, FYI, I changed the following:
- Moved try-finally out of the loop body, for performance, and in order to be able to handle `continue` correctly.
- Fixed scope management in ParseForStatement, which was the cause for the variable allocation failure.
- Fixed pre-existing zone initialisation bug in rewriter, which caused the crashes.
- Enabled all tests, adjusted a few others, added a couple more.
BUG=v8:2214
LOG=Y
Review URL: https://codereview.chromium.org/1695393003
Cr-Commit-Position: refs/heads/master@{#34111}
2016-02-18 10:49:07 +00:00
|
|
|
for (x of g()) { throw 666; }
|
2016-02-24 18:21:32 +00:00
|
|
|
}, 666);
|
[es6] Implement for-of iterator finalization
Implements iterator finalisation by desugaring for-of loops with an additional try-finally wrapper. See comment in parser.cc for details.
Also improved some AST printing facilities while there.
@Ross, I had to disable the bytecode generation test for for-of, because it got completely out of hand after this change (the new bytecode has 150+ lines). See the TODO that I assigned to you.
Patch set 1 is WIP patch by Georg (http://crrev.com/1695583003), patch set 2 relative changes.
@Georg, FYI, I changed the following:
- Moved try-finally out of the loop body, for performance, and in order to be able to handle `continue` correctly.
- Fixed scope management in ParseForStatement, which was the cause for the variable allocation failure.
- Fixed pre-existing zone initialisation bug in rewriter, which caused the crashes.
- Enabled all tests, adjusted a few others, added a couple more.
BUG=v8:2214
LOG=Y
Review URL: https://codereview.chromium.org/1695393003
Cr-Commit-Position: refs/heads/master@{#34111}
2016-02-18 10:49:07 +00:00
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (let x of g()) { return 666; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertThrows(() => {
|
|
|
|
for (x of g()) { return 666; }
|
|
|
|
}, TypeError);
|
|
|
|
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
|
|
|
|
assertEquals(42, eval('for (x of g()) { x; }'));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return method returns an object.
|
|
|
|
{
|
|
|
|
let log = [];
|
|
|
|
g.prototype.return = (...args) => { log.push(args); return {} };
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
for (let x of g()) { break; }
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
for (x of g()) { break; }
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g()) { throw 42; }
|
|
|
|
}, 42);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x of g()) { throw 42; }
|
|
|
|
}, 42);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertEquals(42, (() => {
|
|
|
|
for (let x of g()) { return 42; }
|
|
|
|
})());
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertEquals(42, (() => {
|
|
|
|
for (x of g()) { return 42; }
|
|
|
|
})());
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
assertEquals([], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertEquals(42, eval('for (x of g()) { x; }'));
|
|
|
|
assertEquals([], log);
|
2016-02-24 18:52:17 +00:00
|
|
|
|
|
|
|
// Even if doing the assignment throws, still call return
|
|
|
|
x = { set attr(_) { throw 1234; } };
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x.attr of g()) { throw 456; }
|
|
|
|
}, 1234);
|
|
|
|
assertEquals([[]], log);
|
[es6] Implement for-of iterator finalization
Implements iterator finalisation by desugaring for-of loops with an additional try-finally wrapper. See comment in parser.cc for details.
Also improved some AST printing facilities while there.
@Ross, I had to disable the bytecode generation test for for-of, because it got completely out of hand after this change (the new bytecode has 150+ lines). See the TODO that I assigned to you.
Patch set 1 is WIP patch by Georg (http://crrev.com/1695583003), patch set 2 relative changes.
@Georg, FYI, I changed the following:
- Moved try-finally out of the loop body, for performance, and in order to be able to handle `continue` correctly.
- Fixed scope management in ParseForStatement, which was the cause for the variable allocation failure.
- Fixed pre-existing zone initialisation bug in rewriter, which caused the crashes.
- Enabled all tests, adjusted a few others, added a couple more.
BUG=v8:2214
LOG=Y
Review URL: https://codereview.chromium.org/1695393003
Cr-Commit-Position: refs/heads/master@{#34111}
2016-02-18 10:49:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return method throws.
|
|
|
|
{
|
|
|
|
let log = [];
|
|
|
|
g.prototype.return = (...args) => { log.push(args); throw 23 };
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g()) { break; }
|
|
|
|
}, 23);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x of g()) { break; }
|
|
|
|
}, 23);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g()) { throw 42; }
|
|
|
|
}, 42);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x of g()) { throw 42; }
|
|
|
|
}, 42);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g()) { return 42; }
|
|
|
|
}, 23);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x of g()) { return 42; }
|
|
|
|
}, 23);
|
|
|
|
assertEquals([[]], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertEquals(42, eval('for (let x of g()) { x; }'));
|
|
|
|
assertEquals([], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertEquals(42, eval('for (x of g()) { x; }'));
|
|
|
|
assertEquals([], log);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Next method throws.
|
|
|
|
{
|
|
|
|
g.prototype.next = () => { throw 666; };
|
|
|
|
g.prototype.return = () => { assertUnreachable() };
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g()) {}
|
|
|
|
}, 666);
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (x of g()) {}
|
|
|
|
}, 666);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Nested loops.
|
|
|
|
{
|
|
|
|
function* g1() { yield 1; yield 2; throw 3; }
|
|
|
|
function* g2() { yield -1; yield -2; throw -3; }
|
|
|
|
|
|
|
|
assertDoesNotThrow(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) break;
|
|
|
|
}
|
|
|
|
if (x == 2) break;
|
|
|
|
}
|
|
|
|
}, -3);
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, -3);
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 3);
|
|
|
|
|
|
|
|
assertDoesNotThrow(() => {
|
|
|
|
l: for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) break l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
throw 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 4);
|
|
|
|
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) throw 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 4);
|
|
|
|
|
|
|
|
let log = [];
|
|
|
|
g1.prototype.return = () => { log.push(1); throw 5 };
|
|
|
|
g2.prototype.return = () => { log.push(2); throw -5 };
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) break;
|
|
|
|
}
|
|
|
|
if (x == 2) break;
|
|
|
|
}
|
|
|
|
}, -5);
|
|
|
|
assertEquals([2, 1], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, -3);
|
|
|
|
assertEquals([1], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, -5);
|
|
|
|
assertEquals([2, 1], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
l: for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) break l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, -5);
|
|
|
|
assertEquals([2, 1], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
throw 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 4);
|
|
|
|
assertEquals([2, 1], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
for (let y of g2()) {
|
|
|
|
if (y == -2) throw 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, 4);
|
|
|
|
assertEquals([2, 1], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
try {
|
|
|
|
for (let y of g2()) {
|
|
|
|
}
|
|
|
|
} catch (_) {}
|
|
|
|
}
|
|
|
|
}, 3);
|
|
|
|
assertEquals([], log);
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
assertThrowsEquals(() => {
|
|
|
|
for (let x of g1()) {
|
|
|
|
try {
|
|
|
|
for (let y of g2()) {
|
|
|
|
}
|
|
|
|
} catch (_) {}
|
|
|
|
if (x == 2) break;
|
|
|
|
}
|
|
|
|
}, 5);
|
|
|
|
assertEquals([1], log);
|
|
|
|
}
|