diff options
Diffstat (limited to 'js/src/jit-test/tests/generators')
-rw-r--r-- | js/src/jit-test/tests/generators/bug1098947.js | 11 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/bug1151326.js | 16 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/bug908920.js | 9 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/bug931414.js | 11 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/closing-osr.js | 24 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/es6-syntax.js | 34 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/next-on-finished.js | 6 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/return-break-continue.js | 66 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/return.js | 181 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/throw-closes.js | 63 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/throw-on-finished.js | 7 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/wrappers.js | 37 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/yield-in-finally.js | 178 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/yield-regexp.js | 41 | ||||
-rw-r--r-- | js/src/jit-test/tests/generators/yield-yield.js | 12 |
15 files changed, 696 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/generators/bug1098947.js b/js/src/jit-test/tests/generators/bug1098947.js new file mode 100644 index 000000000..c84ccd8d7 --- /dev/null +++ b/js/src/jit-test/tests/generators/bug1098947.js @@ -0,0 +1,11 @@ +function f() { + try { + let foo = 3; + for (var i=0; i<50; i++) + yield i + foo; + } catch(e) {} +} +var it = f(); +for (var i=0; i<40; i++) + it.next(); +it.close(); diff --git a/js/src/jit-test/tests/generators/bug1151326.js b/js/src/jit-test/tests/generators/bug1151326.js new file mode 100644 index 000000000..17120fbf9 --- /dev/null +++ b/js/src/jit-test/tests/generators/bug1151326.js @@ -0,0 +1,16 @@ +// |jit-test| error: closing generator +var finally3; +function gen() { + try { + try { + yield 1; + } finally { + finally3(); + } + } catch (e) { + yield finally3 === parseInt; + } +} +iter = gen(); +iter.next(); +iter.close(); diff --git a/js/src/jit-test/tests/generators/bug908920.js b/js/src/jit-test/tests/generators/bug908920.js new file mode 100644 index 000000000..4cb781b57 --- /dev/null +++ b/js/src/jit-test/tests/generators/bug908920.js @@ -0,0 +1,9 @@ +if (typeof schedulegc != 'undefined') { + Function("\ + x = (function() { yield })();\ + new Set(x);\ + schedulegc(1);\ + print( /x/ );\ + for (p in x) {}\ + ")(); +} diff --git a/js/src/jit-test/tests/generators/bug931414.js b/js/src/jit-test/tests/generators/bug931414.js new file mode 100644 index 000000000..df1f24d09 --- /dev/null +++ b/js/src/jit-test/tests/generators/bug931414.js @@ -0,0 +1,11 @@ +// |jit-test| error: TypeError + +load(libdir + "iteration.js"); + +function iterable() { + var iterable = {}; + iterable[Symbol.iterator] = () => ({next: () => void 0}); + return iterable; +} + +(function*(){yield*iterable()}()).next(); diff --git a/js/src/jit-test/tests/generators/closing-osr.js b/js/src/jit-test/tests/generators/closing-osr.js new file mode 100644 index 000000000..2bb609993 --- /dev/null +++ b/js/src/jit-test/tests/generators/closing-osr.js @@ -0,0 +1,24 @@ +// OSR into a |finally| block while closing a legacy generator should work. +var log = ""; +function f() { + try { + try { + log += "a"; + yield 2; + log += "b"; + yield 3; + } finally { + log += "c"; + for (var i=0; i<20; i++) {}; + log += "d"; + } + } catch(e) { + log += "e"; + } + log += "f"; +} + +var it = f(); +assertEq(it.next(), 2); +it.close(); +assertEq(log, "acd"); diff --git a/js/src/jit-test/tests/generators/es6-syntax.js b/js/src/jit-test/tests/generators/es6-syntax.js new file mode 100644 index 000000000..e805a0b62 --- /dev/null +++ b/js/src/jit-test/tests/generators/es6-syntax.js @@ -0,0 +1,34 @@ +// Test interactions between ES6 generators and not-yet-standard +// features. + +function assertSyntaxError(str) { + var msg; + var evil = eval; + try { + // Non-direct eval. + evil(str); + } catch (exc) { + if (exc instanceof SyntaxError) + return; + msg = "Assertion failed: expected SyntaxError, got " + exc; + } + if (msg === undefined) + msg = "Assertion failed: expected SyntaxError, but no exception thrown"; + throw new Error(msg + " - " + str); +} + +// Destructuring binding. +assertSyntaxError("function* f(x = yield) {}"); +assertSyntaxError("function* f(x = yield 17) {}"); +assertSyntaxError("function* f([yield]) {}"); +assertSyntaxError("function* f({ yield }) {}"); +assertSyntaxError("function* f(...yield) {}"); + +// For each. +assertSyntaxError("for yield"); +assertSyntaxError("for yield (;;) {}"); +assertSyntaxError("for yield (x of y) {}"); +assertSyntaxError("for yield (var i in o) {}"); + +// Expression bodies. +assertSyntaxError("function* f() yield 7"); diff --git a/js/src/jit-test/tests/generators/next-on-finished.js b/js/src/jit-test/tests/generators/next-on-finished.js new file mode 100644 index 000000000..66c25a13f --- /dev/null +++ b/js/src/jit-test/tests/generators/next-on-finished.js @@ -0,0 +1,6 @@ +function*g(){ }; +o = g(); +o.next(); +result = o.next(); +assertEq(result.done, true); +assertEq(o.value, undefined); diff --git a/js/src/jit-test/tests/generators/return-break-continue.js b/js/src/jit-test/tests/generators/return-break-continue.js new file mode 100644 index 000000000..1d3070e28 --- /dev/null +++ b/js/src/jit-test/tests/generators/return-break-continue.js @@ -0,0 +1,66 @@ +load(libdir + "iteration.js"); + +// break in finally. +function *f1() { + L: try { + yield 1; + } finally { + break L; + } + return 2; +} +it = f1(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(4), 2, true); +assertIteratorDone(it); + +// continue in finally, followed by return. +function *f2() { + do try { + yield 1; + } catch (e) { + assertEq(0, 1); + } finally { + continue; + } while (0); + return 2; +} +it = f2(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(4), 2, true); +assertIteratorDone(it); + +// continue in finally, followed by yield. +function *f3() { + do try { + yield 1; + } catch (e) { + assertEq(0, 1); + } finally { + continue; + } while (0); + yield 2; +} +it = f3(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(4), 2, false); +assertIteratorDone(it); + +// continue in finally. +function *f4() { + var i = 0; + while (true) { + try { + yield i++; + } finally { + if (i < 3) + continue; + } + } +} +it = f4(); +assertIteratorNext(it, 0); +assertIteratorResult(it.return(-1), 1, false); +assertIteratorResult(it.return(-2), 2, false); +assertIteratorResult(it.return(-3), -3, true); +assertIteratorDone(it); diff --git a/js/src/jit-test/tests/generators/return.js b/js/src/jit-test/tests/generators/return.js new file mode 100644 index 000000000..b71b38921 --- /dev/null +++ b/js/src/jit-test/tests/generators/return.js @@ -0,0 +1,181 @@ +// |jit-test| error:done + +load(libdir + "iteration.js"); + +function *f1() { + yield 1; + yield 2; +} + +// Return after initial yield. +var it = f1(); +assertIteratorResult(it.return(3), 3, true); +assertIteratorResult(it.return(Math), Math, true); +assertIteratorResult(it.return(), undefined, true); +assertIteratorDone(it); + +// Return after other yield. +it = f1(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(null), null, true); +assertIteratorDone(it); + +// Finally blocks should run and can override the return value. +function *f2() { + try { + yield 1; + yield 2; + } finally { + return 9; + } +} +it = f2(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(3), 9, true); +assertIteratorDone(it); + +// Yield in finally block can override the return, but we should still +// return the correct value after that. +function *f3() { + try { + try { + yield 1; + yield 2; + } finally { + yield 3; + } + } finally { + yield 4; + } +} +it = f3(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(9), 3, false); +assertIteratorNext(it, 4); +assertIteratorDone(it, 9); +assertIteratorDone(it, undefined); + +// Finally block can throw. +function *f4() { + try { + yield 1; + yield 2; + } finally { + throw 3; + } +} +it = f4(); +assertIteratorNext(it, 1); +assertThrowsValue(() => it.return(8), 3); +assertIteratorDone(it); + +function *f5() {} +it = f5(); +assertIteratorDone(it); +assertIteratorResult(it.return(3), 3, true); +assertIteratorDone(it); + +function *f6() { + try { + yield 1; + yield 2; + } finally { + try { + return 9; + } finally { + yield 3; + } + } +} +it = f6(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(5), 3, false); +assertIteratorDone(it, 9); +assertIteratorDone(it); + +// If we yield in a finally block, a second .return() can override +// the first one. +function *f7() { + try { + yield 1; + yield 2; + } finally { + try { + yield 3; + } finally { + yield 4; + } + } +} +it = f7(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(5), 3, false); +assertIteratorResult(it.return(6), 4, false); +assertIteratorDone(it, 6); +assertIteratorDone(it); + +// If we yield in a finally block, .throw() should work. +function *f8() { + try { + yield 1; + yield 2; + } finally { + yield 3; + } +} +it = f8(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(5), 3, false); +assertThrowsValue(() => it.throw(4), 4); +assertIteratorDone(it); + +// If the generator is already running, we should throw a TypeError. +function *f9() { + try { + yield 1; + yield 2; + } finally { + it.return(4); + yield 3; + } +} +it = f9(); +assertIteratorNext(it, 1); +assertThrowsInstanceOf(() => it.return(5), TypeError); +assertIteratorDone(it); +assertIteratorDone(it); + +// Second return overrides first one and closes the generator. +function *f10() { + try { + yield 1; + } finally { + yield 2; + } +} +it = f10(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(-1), 2, false); +assertIteratorResult(it.return(-2), -2, true); +assertIteratorDone(it); + +function *f11() { + try { + try { + yield 1; + } finally { + throw 2; + } + } catch(e) { + yield e; + } finally { + yield 3; + } +} +it = f11(); +assertIteratorNext(it, 1); +assertIteratorResult(it.return(9), 2, false); +assertIteratorNext(it, 3); +assertIteratorDone(it); + +throw "done"; diff --git a/js/src/jit-test/tests/generators/throw-closes.js b/js/src/jit-test/tests/generators/throw-closes.js new file mode 100644 index 000000000..072e40e3d --- /dev/null +++ b/js/src/jit-test/tests/generators/throw-closes.js @@ -0,0 +1,63 @@ +// When a generator function throws, the generator is closed. + +load(libdir + "asserts.js"); +load(libdir + "iteration.js"); + +// Star generator, next() throws. +function *g() { + yield 1; + yield 2; + throw 3; + yield 4; +} +var i = g(); +assertIteratorNext(i, 1); +assertIteratorNext(i, 2); +assertThrowsValue(() => i.next(), 3); +assertIteratorDone(i); +assertIteratorDone(i); + +// Star generator, throw() throws. +function *h() { + yield 1; + yield 2; +} +var i = h(); +assertIteratorNext(i, 1); +assertThrowsValue(() => i.throw(4), 4); +assertIteratorDone(i); + +// Star generator, return() throws. +function *h2() { + try { + yield 1; + yield 2; + } finally { + throw 6; + } +} +var i = h2(); +assertIteratorNext(i, 1); +assertThrowsValue(() => i.return(4), 6); +assertIteratorDone(i); + +// Legacy generator, throw() throws. +function l1() { + yield 1; + yield 2; +} +var i = l1(); +assertEq(i.next(), 1); +assertThrowsValue(() => i.throw(5), 5); +assertThrowsInstanceOf(() => i.next(), StopIteration); + +// Legacy generator, next() throws. +function l2() { + yield 1; + throw 6; + yield 2; +} +var i = l2(); +assertEq(i.next(), 1); +assertThrowsValue(() => i.next(), 6); +assertThrowsInstanceOf(() => i.next(), StopIteration); diff --git a/js/src/jit-test/tests/generators/throw-on-finished.js b/js/src/jit-test/tests/generators/throw-on-finished.js new file mode 100644 index 000000000..541e48f1f --- /dev/null +++ b/js/src/jit-test/tests/generators/throw-on-finished.js @@ -0,0 +1,7 @@ +load(libdir + "asserts.js"); + +function*g(){ }; +o = g(); +o.next(); +function TestException() {}; +assertThrowsInstanceOf(() => o.throw(new TestException()), TestException); diff --git a/js/src/jit-test/tests/generators/wrappers.js b/js/src/jit-test/tests/generators/wrappers.js new file mode 100644 index 000000000..5cada5201 --- /dev/null +++ b/js/src/jit-test/tests/generators/wrappers.js @@ -0,0 +1,37 @@ +// Generator methods work transparently on CrossCompartmentWrappers. + +load(libdir + "asserts.js"); +load(libdir + "iteration.js"); + +function gen() { yield 1; yield 2; } +var it = gen(); + +var g = newGlobal(); +g.eval("function gen2() { yield 3; yield 4; }; var it2 = gen2();"); + +// LegacyGenerator.next +assertEq(it.next.call(g.it2), 3); + +// LegacyGenerator.throw +assertThrowsValue(() => it.throw.call(g.it2, 7), 7); + +function *gen3() { yield 1; yield 2; } +it = gen3(); +g.eval("function *gen4() { yield 5; yield 6; }; var it4 = gen4();"); + +// StarGenerator.next +assertIteratorResult(it.next.call(g.it4), 5, false) + +// StarGenerator.throw +assertThrowsValue(() => it.throw.call(g.it4, 8), 8); + +// StarGenerator.return +assertIteratorResult(it.return.call(g.it4, 8), 8, true); + +// Other objects should throw. +try { + it.next.call([]); + assertEq(0, 1); +} catch (e) { + assertEq(e.toString().includes("called on incompatible Array"), true); +} diff --git a/js/src/jit-test/tests/generators/yield-in-finally.js b/js/src/jit-test/tests/generators/yield-in-finally.js new file mode 100644 index 000000000..a99e5a61a --- /dev/null +++ b/js/src/jit-test/tests/generators/yield-in-finally.js @@ -0,0 +1,178 @@ +// return value in try block should not be overridden by yield in finally block. + +load(libdir + "asserts.js"); + +// simple +function* g1() { + try { + return 42; + } finally { + yield 43; + } +} +var o = g1(); +var v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// without return value +function* g2() { + try { + return; + } finally { + yield 43; + } +} +o = g2(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// nested try-finally +function* g3() { + try { + try { + return 42; + } finally { + try { + return 43; + } finally { + yield 44; + } + } + } finally { + yield 45; + } +} +o = g3(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 44); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 45); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// yield* +function* g4() { + try { + return 42; + } finally { + try { + return 43; + } finally { + yield* g5(); + } + } +} +function* g5() { + yield 44; + return 45; +} +o = g4(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 44); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// return in block scope +function* g6() { + let a = 10; + { + let a = 20; + try { + let a = 30; + { + let a = 40; + return 42; + } + } finally { + yield 43; + } + } +} +o = g6(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// no finally +function* g7() { + try { + return 42; + } catch (e) { + yield 1; + } +} +o = g7(); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// legacy iterator have no return value +function g8() { + try { + return; + } finally { + yield 43; + } +} +o = g8(); +v = o.next(); +assertEq(v, 43); +assertThrowsInstanceOf(() => o.next(), StopIteration); + +// in "with" statement +options("strict"); +eval(` +function* g9() { + with ({ ".genrval": { value: 44, done: false } }) { + try { + return 42; + } finally { + yield 43; + } + } +} +o = g9(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); +`); diff --git a/js/src/jit-test/tests/generators/yield-regexp.js b/js/src/jit-test/tests/generators/yield-regexp.js new file mode 100644 index 000000000..bcef03af0 --- /dev/null +++ b/js/src/jit-test/tests/generators/yield-regexp.js @@ -0,0 +1,41 @@ +// Bug 1099956 + +load(libdir + "asserts.js"); + +// ES6 treating yield as an identifier except in ES6 generators introduces a +// syntax conflict with permissible JS >= 1.7 legacy generator syntax. Is +// |yield /a/g| inside a function an attempt to convert the function into a +// legacy generator, yielding a RegExp instance? Or does it instead read as +// |(yield / a) / g|? Similar ambiguities exist for different textual content +// in place of |a| -- |yield /x+17/g| or |(yield / x) + 17 / g|, and so on. +// (And, much less importantly, is |yield /a/g| a syntax error in global code +// as in JS >= 1.7, or is it |(yield / a) / g|.) +// +// For now, in JS >= 1.7, we preserve the old behavior. In all other JS we +// conform to ES6: |yield /a/g| is a YieldExpression inside an ES6 generator, +// and it's an IdentifierReference divided twice when not in an ES6 generator. +// This test will need changes if we change our JS >= 1.7 parsing to be +// ES6-compatible. + +function f1() { + yield /abc/g; +} + +var g = f1(); +var v; +v = g.next(); +assertEq(v instanceof RegExp, true); +assertEq(v.toString(), "/abc/g"); +assertThrowsValue(() => g.next(), StopIteration); + +function* f2() { + yield /abc/g; +} + +g = f2(); +v = g.next(); +assertEq(v.done, false); +assertEq(v.value instanceof RegExp, true); +assertEq(v.value.toString(), "/abc/g"); +v = g.next(); +assertEq(v.done, true); diff --git a/js/src/jit-test/tests/generators/yield-yield.js b/js/src/jit-test/tests/generators/yield-yield.js new file mode 100644 index 000000000..123abc5b7 --- /dev/null +++ b/js/src/jit-test/tests/generators/yield-yield.js @@ -0,0 +1,12 @@ +// Bug 880447 + +load(libdir + "asserts.js"); + +function f() { + yield yield 1; +} + +var g = f(); +assertEq(g.next(), 1); +assertEq(g.send("hello"), "hello"); +assertThrowsValue(() => g.next(), StopIteration); |