diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit-test/tests/parser | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/parser')
143 files changed, 3351 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/parser/arrow-rest.js b/js/src/jit-test/tests/parser/arrow-rest.js new file mode 100644 index 0000000000..c4ba373c07 --- /dev/null +++ b/js/src/jit-test/tests/parser/arrow-rest.js @@ -0,0 +1,204 @@ +// The parser should throw SyntaxError immediately if it finds "..." in a +// context where it's not allowed. + +function testThrow(code, column) { + var caught = false; + try { + eval(code); + } catch (e) { + caught = true; + assertEq(e.columnNumber, column); + } + assertEq(caught, true, + "failed to throw evaluating <" + code + ">"); +} + +// expression statement + +testThrow(` +...a)=> +`, 0); + +// default parameter + +testThrow(` +function f(x=...a) => +`, 13); + +// rest parameter + +testThrow(` +function f(... ...a) => +`, 15); + +// destructuring parameter + +testThrow(` +([... ...a)=> +`, 6); + +testThrow(` +({...a)=> +`, 6); + +testThrow(` +function f([... ...a)=> +`, 16); + +testThrow(` +function f({...a)=> +`, 16); + +// arrow + +testThrow(` +x => ...a)=> +`, 5); + +// template literal + +testThrow("`${ ...a)=>}`", 4); + +// destructing assignment + +testThrow(` +var [... ...a)=> +`, 9); + +testThrow(` +var {...a)=> +`, 9); + +// initializer + +testThrow(` +var [a] = ...a)=> +`, 10); + +testThrow(` +var {a:a} = ...a)=> +`, 12); + +testThrow(` +var a = ...a)=> +`, 8); + +// if statement + +testThrow(` +if (...a) => +`, 4); + +// for statement + +testThrow(` +for (...a)=> +`, 5); + +testThrow(` +for (let a in ...a)=> +`, 14); + +testThrow(` +for (let a of ...a)=> +`, 14); + +testThrow(` +for (; ...a)=> +`, 7); + +testThrow(` +for (;; ...a)=> +`, 8); + +// case + +testThrow(` +switch (x) { case ...a)=> +`, 18); + +// return statement + +testThrow(` +function f(x) { return ...a)=> +`, 23); + +// yield expression + +testThrow(` +function* f(x) { yield ...a)=> +`, 23); + +// throw statement + +testThrow(` +throw ...a) => +`, 6); + +// class + +testThrow(` +class A extends ...a) => +`, 16); + +// conditional expression + +testThrow(` +1 ? ...a) => +`, 4); + +testThrow(` +1 ? 2 : ...a) => +`, 8); + +// unary operators + +testThrow(` +void ...a) => +`, 5); + +testThrow(` +typeof ...a) => +`, 7); + +testThrow(` +++ ...a) => +`, 3); + +testThrow(` +delete ...a) => +`, 7); + +// new + +testThrow(` +new ...a) => +`, 4); + +// member expression + +testThrow(` +x[...a) => +`, 2); + +// array literal + +testThrow(` +[... ...a) => +`, 5); + +// object literal + +testThrow(` +({[...a) => +`, 3); + +testThrow(` +({x: ...a) => +`, 5); + +// assignment + +testThrow(` +x = ...a) => +`, 4); diff --git a/js/src/jit-test/tests/parser/arrow-with-block.js b/js/src/jit-test/tests/parser/arrow-with-block.js new file mode 100644 index 0000000000..de6f34c314 --- /dev/null +++ b/js/src/jit-test/tests/parser/arrow-with-block.js @@ -0,0 +1,92 @@ +load(libdir + "asserts.js"); + +let x = 10; +let g = 4; + +assertEq(eval(` +a => {} +/x/g; +`).toString(), "/x/g"); +assertEq(eval(` +a => {} +/x/; +`).toString(), "/x/"); +assertThrowsInstanceOf(() => eval(` +a => {} /x/g; +`), SyntaxError); + +assertEq(eval(` +a => {}, +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => {} +, +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +false ? +a => {} : +/x/; +`).toString(), "/x/"); +assertEq(eval(` +false ? +a => {} +: +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +a => {}; +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => {} +; +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +a => 200 +/x/g; +`) instanceof Function, true); +assertEq(eval(` +a => 200 +/x/g; +`)(), 5); +assertEq(eval(` +a => 200 /x/g; +`)(), 5); + +assertEq(eval(` +a => 1, +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => 1 +, +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +false ? +a => 1 : +/x/; +`).toString(), "/x/"); +assertEq(eval(` +false ? +a => 1 +: +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +a => 1; +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => 1 +; +/x/; +`).toString(), "/x/"); diff --git a/js/src/jit-test/tests/parser/break-continue-errors.js b/js/src/jit-test/tests/parser/break-continue-errors.js new file mode 100644 index 0000000000..9d484506e9 --- /dev/null +++ b/js/src/jit-test/tests/parser/break-continue-errors.js @@ -0,0 +1,22 @@ +load(libdir + "asserts.js"); + +function test(s, expected) { + assertErrorMessage(() => Function(s), SyntaxError, expected); +} + +test("A: continue;", "continue must be inside loop"); +test("A: continue B;", "continue must be inside loop"); +test("A: if (false) { continue; }", "continue must be inside loop"); +test("A: if (false) { continue B; }", "continue must be inside loop"); +test("while (false) { (() => { continue B; })(); }", "continue must be inside loop"); +test("B: while (false) { (() => { continue B; })(); }", "continue must be inside loop"); + +test("do { continue B; } while (false);", "label not found"); +test("A: for (;;) { continue B; }", "label not found"); +test("A: while (false) { if (x) { continue B; } }", "label not found"); +test("A: while (false) { B: if (x) { continue B; } }", "label not found"); + +test("A: if (false) { break B; }", "label not found"); +test("A: while (false) { break B; }", "label not found"); +test("A: while (true) { if (x) { break B; } }", "label not found"); +test("B: while (false) { (() => { break B; })(); }", "label not found"); diff --git a/js/src/jit-test/tests/parser/bug-1090096.js b/js/src/jit-test/tests/parser/bug-1090096.js new file mode 100644 index 0000000000..3894630afe --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1090096.js @@ -0,0 +1,12 @@ +load(libdir + "asserts.js"); + +assertThrowsInstanceOf( + () => Function(` +for (let { + [ + function(x) {; + } + ]: {} +} in 0 +`), + SyntaxError) diff --git a/js/src/jit-test/tests/parser/bug-1161312.js b/js/src/jit-test/tests/parser/bug-1161312.js new file mode 100644 index 0000000000..c697471607 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1161312.js @@ -0,0 +1,3 @@ +// Test that lazy scripts can handle OOB column numbers. + +assertEq(evaluate(`var f = x=>saveStack().column; f()`, { columnNumber: 1729 }), 1741); diff --git a/js/src/jit-test/tests/parser/bug-1250192.js b/js/src/jit-test/tests/parser/bug-1250192.js new file mode 100644 index 0000000000..39b0ff0f54 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1250192.js @@ -0,0 +1,5 @@ +(function * YearFromTime(x, ... get) { +try {} catch (x) { + for (var x;;); +} +})(); diff --git a/js/src/jit-test/tests/parser/bug-1254164.js b/js/src/jit-test/tests/parser/bug-1254164.js new file mode 100644 index 0000000000..3b08180a78 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1254164.js @@ -0,0 +1,6 @@ +// |jit-test| slow; + +var s = ''; +for (var i = 0; i < 70000; i++) + s += 'function x' + i + '() { x' + i + '(); }\n'; +eval("(function() { " + s + " })();"); diff --git a/js/src/jit-test/tests/parser/bug-1263355-1.js b/js/src/jit-test/tests/parser/bug-1263355-1.js new file mode 100644 index 0000000000..e5dbb56450 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-1.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError + +for (let b in [0]) { + let b = b ? 0 : 1 +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-10.js b/js/src/jit-test/tests/parser/bug-1263355-10.js new file mode 100644 index 0000000000..1b7888d861 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-10.js @@ -0,0 +1,4 @@ +// |jit-test| error: TypeError + +function f(m, k = class C extends Array { }, p = m()) { } +f() diff --git a/js/src/jit-test/tests/parser/bug-1263355-11.js b/js/src/jit-test/tests/parser/bug-1263355-11.js new file mode 100644 index 0000000000..1e363dc79d --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-11.js @@ -0,0 +1,6 @@ +function assertNotSame(expected, actual, message = "") { } +function g3(h = () => arguments) { + function arguments() { } + assertNotSame(arguments, h()); +} +g3(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-12.js b/js/src/jit-test/tests/parser/bug-1263355-12.js new file mode 100644 index 0000000000..d2049bfa22 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-12.js @@ -0,0 +1,6 @@ + + +syntaxParse(` +if (scriptArgs.length === 0) { } +var file = scriptArgs[0]; +`); diff --git a/js/src/jit-test/tests/parser/bug-1263355-13.js b/js/src/jit-test/tests/parser/bug-1263355-13.js new file mode 100644 index 0000000000..96997c2dc0 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-13.js @@ -0,0 +1,26 @@ +// |jit-test| error: ReferenceError + +// jsfunfuzz-generated +gczeal(9); +for (var i in function(){}); +s = newGlobal({newCompartment: true}); +aa = f(); +function f(x) { + evalcx(x, s) +} +function h(x) { + f(x) +} +// Adapted from randomly chosen test: js/src/jit-test/tests/debug/resumption-05.js +h("\ + var g = newGlobal({newCompartment: true});\ + g.debuggeeGlobal = this;\ + g.eval(\"(\" + function() {\ + var dbg = Debugger(debuggeeGlobal);\ + dbg.onDebuggerStatement = function(frame) {\ + frame.eval(\"f\")\ + }\ + } + \")()\");\ + debugger;\ +"); +z; diff --git a/js/src/jit-test/tests/parser/bug-1263355-14.js b/js/src/jit-test/tests/parser/bug-1263355-14.js new file mode 100644 index 0000000000..23f7c160e8 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-14.js @@ -0,0 +1,28 @@ +// |jit-test| allow-unhandlable-oom +gczeal(0); +function g() { + for (var j = 0; j < 999; ++j) { + try { + k + } catch (e) { + try { + r + } catch (e) {} + } + } +} +function h(code) { + try { + f = Function(code) + } catch (r) {}; + try { + f() + } catch (r) {} + eval("") +} +h("m=function(){};g(m,[,])") +h("=") +h("=") +h("=") +h("startgc(1,'shrinking')") +h("gcparam(\"maxBytes\",gcparam(\"gcBytes\")+4);for(r;;i++){}") diff --git a/js/src/jit-test/tests/parser/bug-1263355-15.js b/js/src/jit-test/tests/parser/bug-1263355-15.js new file mode 100644 index 0000000000..409ead51d5 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-15.js @@ -0,0 +1,4 @@ +// Adapted from randomly chosen test: js/src/jit-test/tests/parser/yield-in-formal-destructuring.js +function f({ + [e]: {} +}) {} diff --git a/js/src/jit-test/tests/parser/bug-1263355-16.js b/js/src/jit-test/tests/parser/bug-1263355-16.js new file mode 100644 index 0000000000..9bf1a2412e --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-16.js @@ -0,0 +1,11 @@ +// |jit-test| error: ReferenceError + +let m = parseModule(` +var i = 0; +addThis(); +function addThis() { + return statusmessages[i] = Number; +} +`); +moduleLink(m); +moduleEvaluate(m); diff --git a/js/src/jit-test/tests/parser/bug-1263355-17.js b/js/src/jit-test/tests/parser/bug-1263355-17.js new file mode 100644 index 0000000000..f472efcd34 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-17.js @@ -0,0 +1,4 @@ +let m = parseModule(` + var expect = ''; + var [ ... of ] = ( ... of ) => expect; +`); diff --git a/js/src/jit-test/tests/parser/bug-1263355-18.js b/js/src/jit-test/tests/parser/bug-1263355-18.js new file mode 100644 index 0000000000..683c248514 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-18.js @@ -0,0 +1,4 @@ +function f14(g = 0) { + { function g() { return "g" } } +} +f14(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-19.js b/js/src/jit-test/tests/parser/bug-1263355-19.js new file mode 100644 index 0000000000..c3d118635b --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-19.js @@ -0,0 +1,4 @@ +(function(p = null){ + var q; + (function() { q })(); +})(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-2.js b/js/src/jit-test/tests/parser/bug-1263355-2.js new file mode 100644 index 0000000000..bb37715b61 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-2.js @@ -0,0 +1,2 @@ +eval(); +try {} catch (abc) {}; diff --git a/js/src/jit-test/tests/parser/bug-1263355-20.js b/js/src/jit-test/tests/parser/bug-1263355-20.js new file mode 100644 index 0000000000..f98cf7b44f --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-20.js @@ -0,0 +1,2 @@ +{ function c() {} } +class c { } diff --git a/js/src/jit-test/tests/parser/bug-1263355-21.js b/js/src/jit-test/tests/parser/bug-1263355-21.js new file mode 100644 index 0000000000..9dfa94e691 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-21.js @@ -0,0 +1,7 @@ +// |jit-test| error: TypeError + +(function() { + "use asm"; + var [] = 0; +})() + diff --git a/js/src/jit-test/tests/parser/bug-1263355-22.js b/js/src/jit-test/tests/parser/bug-1263355-22.js new file mode 100644 index 0000000000..69b7e77092 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-22.js @@ -0,0 +1,16 @@ +// |jit-test| error: ReferenceError + +// Adapted from randomly chosen test: js/src/jit-test/tests/debug/Frame-onPop-error-scope-unwind-02.js +var g = newGlobal({newCompartment: true}); +var dbg = new Debugger(g); +dbg.onEnterFrame = function(f) { + (f.environment.getVariable("e") == 0); +}; +g.eval("" + function f() { + try { + throw 42; + } catch (e) { + noSuchFn(e); + } +}); +g.eval("f();"); diff --git a/js/src/jit-test/tests/parser/bug-1263355-23.js b/js/src/jit-test/tests/parser/bug-1263355-23.js new file mode 100644 index 0000000000..802e58a785 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-23.js @@ -0,0 +1,7 @@ +let m = parseModule(` + const root = newGlobal(); + minorgc(); + root.eval(); +`); +moduleLink(m); +moduleEvaluate(m); diff --git a/js/src/jit-test/tests/parser/bug-1263355-24.js b/js/src/jit-test/tests/parser/bug-1263355-24.js new file mode 100644 index 0000000000..0c33ec3530 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-24.js @@ -0,0 +1,3 @@ +function TestFunction_4(get, b, [] = status, d, e) { + var arguments = "FAIL"; +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-26.js b/js/src/jit-test/tests/parser/bug-1263355-26.js new file mode 100644 index 0000000000..a3c09459ab --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-26.js @@ -0,0 +1,7 @@ +// |jit-test| error: TypeError + +function test(a, b, c, d, e, {} = "zmi") { + var r = 0 + r += Math.min(a, b, c, r.script.getLineOffsets(g.line0 + 3), e); +} +test(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-27.js b/js/src/jit-test/tests/parser/bug-1263355-27.js new file mode 100644 index 0000000000..ba334a3eb8 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-27.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError + +load(libdir + "evalInFrame.js"); +evalInFrame(1, "a = 43"); +let a = 42; diff --git a/js/src/jit-test/tests/parser/bug-1263355-28.js b/js/src/jit-test/tests/parser/bug-1263355-28.js new file mode 100644 index 0000000000..88c7b0653e --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-28.js @@ -0,0 +1,3 @@ +for (var i = 0; i < 1; i++) { + L: break; +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-29.js b/js/src/jit-test/tests/parser/bug-1263355-29.js new file mode 100644 index 0000000000..ace3e5faa9 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-29.js @@ -0,0 +1,6 @@ +// |jit-test| error: ReferenceError + +{ + for (var x = 0; i < 100; i++) a >>= i + let i = 1; +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-3.js b/js/src/jit-test/tests/parser/bug-1263355-3.js new file mode 100644 index 0000000000..00a1cef382 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-3.js @@ -0,0 +1,4 @@ +// |jit-test| error: ReferenceError + +f = ([a = class b extends b {}, b] = [void 0]) => {}; +f() diff --git a/js/src/jit-test/tests/parser/bug-1263355-30.js b/js/src/jit-test/tests/parser/bug-1263355-30.js new file mode 100644 index 0000000000..f3339ee5fa --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-30.js @@ -0,0 +1,19 @@ +// |jit-test| error: ReferenceError + +var g = newGlobal({newCompartment: true}); +var dbg = new Debugger; +g.toggle = function toggle(d) { + if (d) { + dbg.addDebuggee(g); + frame1.onPop = function() { + onPopExecuted = setJitCompilerOption('offthread-compilation.enable', 0) >> toggle('#2: x = null; x ^= true; x === 1. Actual: ' + (getObjectMetadata)) + (this); + }; + } +}; +g.eval("" + function f(d) { + toggle(d); +}); +g.eval("(" + function test() { + for (var i = 0; i < 5; i++) f(false); + f(true); +} + ")();"); diff --git a/js/src/jit-test/tests/parser/bug-1263355-31.js b/js/src/jit-test/tests/parser/bug-1263355-31.js new file mode 100644 index 0000000000..2ffe295d0c --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-31.js @@ -0,0 +1,6 @@ +try { + eval('"use strict"; var x = "a\\4";'); +} catch (e) { + var e = ''; + let arguments; +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-32.js b/js/src/jit-test/tests/parser/bug-1263355-32.js new file mode 100644 index 0000000000..db31a6b12d --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-32.js @@ -0,0 +1,4 @@ +// |jit-test| error: ReferenceError + +f = ([a = class target extends b {}, b] = [void 0]) => {}; +f() diff --git a/js/src/jit-test/tests/parser/bug-1263355-33.js b/js/src/jit-test/tests/parser/bug-1263355-33.js new file mode 100644 index 0000000000..e1732de594 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-33.js @@ -0,0 +1,22 @@ +// |jit-test| error: InternalError + +var lfLogBuffer = ` +if (lfCodeBuffer) loadFile(lfCodeBuffer); +function loadFile(await ) { + eval(lfVarx); +} +`; +lfLogBuffer = lfLogBuffer.split('\n'); +var lfCodeBuffer = ""; +while (true) { + var line = lfLogBuffer.shift(); + if (line == null) { + break; + } else { + lfCodeBuffer += line + "\n"; + } +} +if (lfCodeBuffer) loadFile(lfCodeBuffer); +function loadFile(lfVarx) { + eval(lfVarx); +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-34.js b/js/src/jit-test/tests/parser/bug-1263355-34.js new file mode 100644 index 0000000000..975c6d33dc --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-34.js @@ -0,0 +1,4 @@ +eval(` +var of; +let expect =false , assertEq; +`); diff --git a/js/src/jit-test/tests/parser/bug-1263355-35.js b/js/src/jit-test/tests/parser/bug-1263355-35.js new file mode 100644 index 0000000000..1bb5f44dd0 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-35.js @@ -0,0 +1,7 @@ +function f({get +} = (0), y) { + var stack = getBacktrace({ + args: true, + }); +} +f(1, 2); diff --git a/js/src/jit-test/tests/parser/bug-1263355-36.js b/js/src/jit-test/tests/parser/bug-1263355-36.js new file mode 100644 index 0000000000..b6d07c3ce9 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-36.js @@ -0,0 +1,9 @@ +// |jit-test| error: ReferenceError + +(function f() { + let x = (new function() { + x(() => { + f.ArrayType(1, 2); + }, "first argument of ctypes.cast must be a CData"); + }) +})(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-37.js b/js/src/jit-test/tests/parser/bug-1263355-37.js new file mode 100644 index 0000000000..c9829c01e7 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-37.js @@ -0,0 +1,7 @@ +// |jit-test| error: ReferenceError + +{ + while (x && 0) + if (!((x = 1) === x)) {} + let x = () => sym() +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-38.js b/js/src/jit-test/tests/parser/bug-1263355-38.js new file mode 100644 index 0000000000..4a42642762 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-38.js @@ -0,0 +1,9 @@ +// |jit-test| error: SyntaxError + +function crashMe2(n) { + var nasty = [], + fn + while (n--) nasty[n] = "a" + 1234567890 + fn = Function(nasty.join(), "void 0") +} +crashMe2(0x10000); diff --git a/js/src/jit-test/tests/parser/bug-1263355-39.js b/js/src/jit-test/tests/parser/bug-1263355-39.js new file mode 100644 index 0000000000..85d0f8aaef --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-39.js @@ -0,0 +1,8 @@ +function f() { + var init, first; + for (let i = (init = () => i = 1, 0); (first = () => i, i) < 0; ++i); + assertEq(init(), 1); + assertEq(first(), 0); +} + +f(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-4.js b/js/src/jit-test/tests/parser/bug-1263355-4.js new file mode 100644 index 0000000000..f2b855f7df --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-4.js @@ -0,0 +1,2 @@ +function f(a = (eval("var b"))) {} +f() diff --git a/js/src/jit-test/tests/parser/bug-1263355-40.js b/js/src/jit-test/tests/parser/bug-1263355-40.js new file mode 100644 index 0000000000..0142054d4a --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-40.js @@ -0,0 +1,5 @@ + + +function test(get, [] = Bool16x8(...w), ...of) { + var f; +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-41.js b/js/src/jit-test/tests/parser/bug-1263355-41.js new file mode 100644 index 0000000000..6c79054174 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-41.js @@ -0,0 +1,5 @@ +for (var i = 0; i < 200; i++) { + (function* get(undefined, ...get) { + g.apply(this, arguments); + })(); +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-42.js b/js/src/jit-test/tests/parser/bug-1263355-42.js new file mode 100644 index 0000000000..b874006a4b --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-42.js @@ -0,0 +1,11 @@ +// |jit-test| error: ReferenceError + +function f() { + switch (2) { + case 1: + x = 1; + case (x, 2): + let x; + } +} +f(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-43.js b/js/src/jit-test/tests/parser/bug-1263355-43.js new file mode 100644 index 0000000000..8605108aca --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-43.js @@ -0,0 +1,4 @@ +// |jit-test| error: ReferenceError + +function f(a = x, x = x) {} +f(/y/) diff --git a/js/src/jit-test/tests/parser/bug-1263355-44.js b/js/src/jit-test/tests/parser/bug-1263355-44.js new file mode 100644 index 0000000000..c2de49fd49 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-44.js @@ -0,0 +1,8 @@ +// |jit-test| skip-if: !('oomTest' in this) + +// Adapted from randomly chosen test: js/src/jit-test/tests/profiler/bug1231925.js +"use strict"; +enableGeckoProfiling(); +oomTest(function() { + eval("(function() {})()"); +}); diff --git a/js/src/jit-test/tests/parser/bug-1263355-45.js b/js/src/jit-test/tests/parser/bug-1263355-45.js new file mode 100644 index 0000000000..968c595664 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-45.js @@ -0,0 +1,8 @@ +// |jit-test| error: ReferenceError + +gczeal(4, 10); +f = ([a = class target extends b {}, b] = [void 0]) => { + class dbg {} + class get {} +}; +f() diff --git a/js/src/jit-test/tests/parser/bug-1263355-46.js b/js/src/jit-test/tests/parser/bug-1263355-46.js new file mode 100644 index 0000000000..e5c3ec1db1 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-46.js @@ -0,0 +1,23 @@ +setJitCompilerOption("ion.warmup.trigger", 4); +var lfLogBuffer = ` +function logProxy(object = {}, handler = {}) { + var log = []; + var proxy = new WeakMap(object, new Proxy(handler, { + get(proto) { + log.push(propertyKey); + } + })); +} +var {proxy, log} = logProxy(); +`; +loadFile(lfLogBuffer); +loadFile(lfLogBuffer); +loadFile(lfLogBuffer); +function loadFile(lfVarx) { + try { + function newFunc(x) { + new Function(x)(); + }; + newFunc(lfVarx); + } catch (lfVare) {} +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-47.js b/js/src/jit-test/tests/parser/bug-1263355-47.js new file mode 100644 index 0000000000..da6575e3f4 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-47.js @@ -0,0 +1,6 @@ + +for (let x = 0; x < 4; ++x) { + (function() { + for (var set = 0, get, get; eval("\tvar\tx\t=\t1\t");) {} + })() +}; diff --git a/js/src/jit-test/tests/parser/bug-1263355-48.js b/js/src/jit-test/tests/parser/bug-1263355-48.js new file mode 100644 index 0000000000..149db99878 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-48.js @@ -0,0 +1,18 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +function eval(source) { + offThreadCompileModuleToStencil(source); + let stencil = finishOffThreadStencil(); + let m = instantiateModuleStencil(stencil); + moduleLink(m); + return moduleEvaluate(m); +} +function runTestCase(testcase) { + if (testcase() !== true) {} +} +eval(` + function testcase() { + function set () {} + } + runTestCase(testcase); +`); diff --git a/js/src/jit-test/tests/parser/bug-1263355-49.js b/js/src/jit-test/tests/parser/bug-1263355-49.js new file mode 100644 index 0000000000..e5fad35322 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-49.js @@ -0,0 +1,4 @@ +load(libdir + "iteration.js"); +function* f4(get = [1], f2, ...each) {} +it = f4(); +assertIteratorResult(it.return(2), 2, true); diff --git a/js/src/jit-test/tests/parser/bug-1263355-5.js b/js/src/jit-test/tests/parser/bug-1263355-5.js new file mode 100644 index 0000000000..89fff8ea0e --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-5.js @@ -0,0 +1,3 @@ +// |jit-test| error: ReferenceError + +new class extends Object { constructor(a = (()=>{delete super[super()]})()) { } } diff --git a/js/src/jit-test/tests/parser/bug-1263355-50.js b/js/src/jit-test/tests/parser/bug-1263355-50.js new file mode 100644 index 0000000000..0416249ec1 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-50.js @@ -0,0 +1,4 @@ +// |jit-test| error: TypeError + +function* of([d] = eval("var MYVAR=new String('0Xf');++MYVAR"), ...get) { var x = 42;} +of(); diff --git a/js/src/jit-test/tests/parser/bug-1263355-51.js b/js/src/jit-test/tests/parser/bug-1263355-51.js new file mode 100644 index 0000000000..b2bdb680d0 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-51.js @@ -0,0 +1,9 @@ +// TDZ checks work in destructuring default expressions, +// even after the variables are initialized the first time. + +load(libdir + "asserts.js"); + +assertThrowsInstanceOf(() => { + // should throw the second time through: b is uninitialized + for (const {a=b, b} of [{a:1, b:2}, {b:3}]) {} +}, ReferenceError); diff --git a/js/src/jit-test/tests/parser/bug-1263355-52.js b/js/src/jit-test/tests/parser/bug-1263355-52.js new file mode 100644 index 0000000000..0b0cb4fa21 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-52.js @@ -0,0 +1,11 @@ +// |jit-test| error: ReferenceError + +(function() { + if ({}) {} + else if (x) {} + else {} + + return "" + x; + + let x; +})() diff --git a/js/src/jit-test/tests/parser/bug-1263355-6.js b/js/src/jit-test/tests/parser/bug-1263355-6.js new file mode 100644 index 0000000000..4297e33fba --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-6.js @@ -0,0 +1,3 @@ +// |jit-test| error: TypeError + +(new class extends Array {constructor(a=()=>eval("super()")){ var f = ()=>super(); f() }})(0) diff --git a/js/src/jit-test/tests/parser/bug-1263355-7.js b/js/src/jit-test/tests/parser/bug-1263355-7.js new file mode 100644 index 0000000000..b45f1a97ac --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-7.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError + +let a; +for(let {a = new class extends Array { constructor(){super(a)} }} of [[]]) { +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-8.js b/js/src/jit-test/tests/parser/bug-1263355-8.js new file mode 100644 index 0000000000..c6d01da9e9 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-8.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError + +let a; +for(let {a = new class extends Array { constructor(){super[a]} }} of [[]]) { +} diff --git a/js/src/jit-test/tests/parser/bug-1263355-9.js b/js/src/jit-test/tests/parser/bug-1263355-9.js new file mode 100644 index 0000000000..80e991eb05 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263355-9.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError + +let a; +for(let {a = new class extends Array { constructor(b = (a = eval("()=>super()"))){} }} of [[]]) { +} diff --git a/js/src/jit-test/tests/parser/bug-1263881-1.js b/js/src/jit-test/tests/parser/bug-1263881-1.js new file mode 100644 index 0000000000..f105946098 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263881-1.js @@ -0,0 +1,6 @@ +registerModule('a', parseModule("export let a = 1;")); +let s = ""; +let max = 65536; +for (let i = 0; i < max; i++) + s += "import * as ns" + i + " from 'a';\n"; +parseModule(s); diff --git a/js/src/jit-test/tests/parser/bug-1263881-2.js b/js/src/jit-test/tests/parser/bug-1263881-2.js new file mode 100644 index 0000000000..06c3049085 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263881-2.js @@ -0,0 +1,5 @@ +let s = ""; +let max = 65536; +for (let i = 0; i < max; i++) + s += "let ns" + i + " = "+ i +";\n"; +eval(s); diff --git a/js/src/jit-test/tests/parser/bug-1263881-3.js b/js/src/jit-test/tests/parser/bug-1263881-3.js new file mode 100644 index 0000000000..4d3573b6c5 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1263881-3.js @@ -0,0 +1,6 @@ +let s = "function foo() {\n"; +let max = 65536; +for (let i = 0; i < max; i++) + s += "let ns" + i + " = "+ i +";\n"; +s += "};"; +eval(s); diff --git a/js/src/jit-test/tests/parser/bug-1264568.js b/js/src/jit-test/tests/parser/bug-1264568.js new file mode 100644 index 0000000000..086a04aa94 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1264568.js @@ -0,0 +1,6 @@ +// |jit-test| error: SyntaxError +f = (function(stdlib, foreign, heap) { + "use asm"; + ({ "0" + () + { eval } diff --git a/js/src/jit-test/tests/parser/bug-1316832.js b/js/src/jit-test/tests/parser/bug-1316832.js new file mode 100644 index 0000000000..8b299dd00e --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1316832.js @@ -0,0 +1,10 @@ + +(function(x, x) { + eval(` + var y = 1; + function f() { + return delete y; + } + f(); + `); +})() diff --git a/js/src/jit-test/tests/parser/bug-1319443.js b/js/src/jit-test/tests/parser/bug-1319443.js new file mode 100644 index 0000000000..c2f01c3a8e --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1319443.js @@ -0,0 +1,11 @@ +// |jit-test| error: TypeError + +var global = newGlobal({ cloneSingletons: true }); + +var code = cacheEntry(` +function f() {} +Object.freeze(this); +`); + +evaluate(code, { global, saveIncrementalBytecode: true }); +evaluate(code, { global, saveIncrementalBytecode: true }); diff --git a/js/src/jit-test/tests/parser/bug-1324773-2.js b/js/src/jit-test/tests/parser/bug-1324773-2.js new file mode 100644 index 0000000000..bf485ee602 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1324773-2.js @@ -0,0 +1,15 @@ +// |jit-test| skip-if: !('gczeal' in this) + +var lfGlobal = newGlobal(); +lfGlobal.evaluate(` + for (var i = 0; i < 600; i++) + eval('function f' + i + '() {}'); +`); +var lfGlobal = newGlobal(); +lfGlobal.evaluate(` + if (!('gczeal' in this)) + quit(); + var dbg = new Debugger(); + gczeal(9, 10); + dbg.findScripts({}); +`); diff --git a/js/src/jit-test/tests/parser/bug-1324773.js b/js/src/jit-test/tests/parser/bug-1324773.js new file mode 100644 index 0000000000..1ab1a3fb9a --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1324773.js @@ -0,0 +1,15 @@ +// |jit-test| skip-if: !('gczeal' in this) + +var lfGlobal = newGlobal(); +lfGlobal.evaluate(` + for (var i = 0; i < 600; i++) + eval('function f' + i + '() {}'); +`); +var lfGlobal = newGlobal(); +lfGlobal.evaluate(` + if (!('gczeal' in this)) + quit(); + var dbg = new Debugger(); + gczeal(9, 1); + dbg.findScripts({}); +`); diff --git a/js/src/jit-test/tests/parser/bug-1355046.js b/js/src/jit-test/tests/parser/bug-1355046.js new file mode 100644 index 0000000000..86bf7bec92 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1355046.js @@ -0,0 +1,8 @@ +// |jit-test| error: ReferenceError + +var localstr = ""; +for (var i = 0; i < 0xFFFC; ++i) + localstr += ('\f') + i + "; "; +var arg = "x"; +var body = localstr + "for (var i = 0; i < 4; ++i) arr[i](x-1);"; +(new Function(arg, body))(1000); diff --git a/js/src/jit-test/tests/parser/bug-1357075.js b/js/src/jit-test/tests/parser/bug-1357075.js new file mode 100644 index 0000000000..47482e372b --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1357075.js @@ -0,0 +1,10 @@ +// |jit-test| error: TypeError + +var iterable = {}; +var iterator = { + return: 1 +}; +iterable[Symbol.iterator] = function() { + return iterator; +}; +for ([ class get {} ().iterator ] of [iterable]) {} diff --git a/js/src/jit-test/tests/parser/bug-1363191.js b/js/src/jit-test/tests/parser/bug-1363191.js new file mode 100644 index 0000000000..779e1a5d1a --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1363191.js @@ -0,0 +1,2 @@ +eval("{ function f() {} }"); +let f; diff --git a/js/src/jit-test/tests/parser/bug-1364648.js b/js/src/jit-test/tests/parser/bug-1364648.js new file mode 100644 index 0000000000..e9b7b1a4ea --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1364648.js @@ -0,0 +1 @@ +assertEq(evaluate("var f = x=>class { }; f()", { columnNumber: 1729 }).toString(), "class { }"); diff --git a/js/src/jit-test/tests/parser/bug-1366927.js b/js/src/jit-test/tests/parser/bug-1366927.js new file mode 100644 index 0000000000..45eb3e69f0 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1366927.js @@ -0,0 +1 @@ +evaluate("\n(y => 1)()", { columnNumber: 1729 }) diff --git a/js/src/jit-test/tests/parser/bug-1385112.js b/js/src/jit-test/tests/parser/bug-1385112.js new file mode 100644 index 0000000000..a84ecd1d26 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1385112.js @@ -0,0 +1 @@ +eval(`let \\u{${"0".repeat(0x8000)}65} = 123;`); diff --git a/js/src/jit-test/tests/parser/bug-1431353-2.js b/js/src/jit-test/tests/parser/bug-1431353-2.js new file mode 100644 index 0000000000..67e05d77a1 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1431353-2.js @@ -0,0 +1,57 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +// Test off-thread parsing correctly fixes up prototypes of special objects when +// merging back to the target compartment. + +function execOffThread(source) +{ + offThreadCompileToStencil(source); + var stencil = finishOffThreadStencil(); + return evalStencil(stencil); +} + +function parseModuleOffThread(source) +{ + offThreadCompileModuleToStencil(source); + var stencil = finishOffThreadStencil(); + return instantiateModuleStencil(stencil); +} + +let a = { x: 1 }; +let b = execOffThread("undefined, { x: 1 }") +let c = execOffThread("undefined, { x: 1 }") + +assertEq(Object.getPrototypeOf(a), Object.prototype); +assertEq(Object.getPrototypeOf(b), Object.prototype); +assertEq(Object.getPrototypeOf(c), Object.prototype); + +a = () => 1; +b = execOffThread("() => 1") +c = execOffThread("() => 1") + +assertEq(Object.getPrototypeOf(a), Function.prototype); +assertEq(Object.getPrototypeOf(b), Function.prototype); +assertEq(Object.getPrototypeOf(c), Function.prototype); + +a = [1, 2, 3]; +b = execOffThread("[1, 2, 3]") +c = execOffThread("[1, 2, 3]") + +assertEq(Object.getPrototypeOf(a), Array.prototype); +assertEq(Object.getPrototypeOf(b), Array.prototype); +assertEq(Object.getPrototypeOf(c), Array.prototype); + +a = /a/; +b = execOffThread("/a/") +c = execOffThread("/a/") + +assertEq(Object.getPrototypeOf(a), RegExp.prototype); +assertEq(Object.getPrototypeOf(b), RegExp.prototype); +assertEq(Object.getPrototypeOf(c), RegExp.prototype); + +a = parseModule(""); +b = parseModuleOffThread(""); +c = parseModuleOffThread(""); + +assertEq(Object.getPrototypeOf(b), Object.getPrototypeOf(a)); +assertEq(Object.getPrototypeOf(c), Object.getPrototypeOf(a)); diff --git a/js/src/jit-test/tests/parser/bug-1431353.js b/js/src/jit-test/tests/parser/bug-1431353.js new file mode 100644 index 0000000000..61c83136f2 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1431353.js @@ -0,0 +1,165 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +// Test multiple concurrent off-thread parse jobs. + +function assertFails(f) { + let failed = false; + try { + f(); + } catch (e) { + failed = true; + } + assertEq(failed, true); +} + +function encodeScript(source) +{ + let entry = cacheEntry(source); + let global = newGlobal({ cloneSingletons: true }); + evaluate(entry, { global: global, saveIncrementalBytecode: true }); + return entry; +} + +let a, b, c; +let stencil, stencilA, stencilB, stencilC; + +// Calling run functions without arguments assumes a single off-thread job. + +// Test run functions fail when no jobs exist. + +assertFails(() => finishOffThreadStencil()); + +assertFails(() => finishOffThreadStencil()); + +assertFails(() => finishOffThreadStencil()); + +// Test run functions fail when multiple jobs exist and no ID specified. + +a = offThreadCompileToStencil(""); +b = offThreadCompileToStencil(""); +assertFails(() => finishOffThreadStencil()); +stencilA = finishOffThreadStencil(a); +stencilB = finishOffThreadStencil(b); +evalStencil(stencilA); +evalStencil(stencilB); + +a = offThreadCompileModuleToStencil(""); +b = offThreadCompileModuleToStencil(""); +assertFails(() => finishOffThreadStencil()); +stencilA = finishOffThreadStencil(a); +stencilB = finishOffThreadStencil(b); +instantiateModuleStencil(stencilA); +instantiateModuleStencil(stencilB); + +a = offThreadDecodeStencil(encodeScript("")); +b = offThreadDecodeStencil(encodeScript("")); +assertFails(() => finishOffThreadStencil()); +stencilA = finishOffThreadStencil(a); +stencilB = finishOffThreadStencil(b); +evalStencil(stencilA); +evalStencil(stencilB); + +// Test fun functions succeed when a single job exist and no ID specified. + +offThreadCompileToStencil("42"); +stencil = finishOffThreadStencil(); +assertEq(evalStencil(stencil), 42); + +offThreadCompileModuleToStencil(""); +stencil = finishOffThreadStencil(); +assertEq(typeof instantiateModuleStencil(stencil), "object"); + +offThreadDecodeStencil(encodeScript("23")); +stencil = finishOffThreadStencil(); +assertEq(evalStencil(stencil), 23); + +// Run functions take an ID argument returned from the compile function. + +// Test bad ID type and unknown ID. + +offThreadCompileToStencil(""); +assertFails(() => finishOffThreadStencil("foo")); +assertFails(() => finishOffThreadStencil(42)); +stencil = finishOffThreadStencil(); +evalStencil(stencil); + +offThreadCompileModuleToStencil(""); +assertFails(() => finishOffThreadStencil("foo")); +assertFails(() => finishOffThreadStencil(42)); +stencil = finishOffThreadStencil(); +instantiateModuleStencil(stencil); + +offThreadDecodeStencil(encodeScript("")); +assertFails(() => finishOffThreadStencil("foo")); +assertFails(() => finishOffThreadStencil(42)); +stencil = finishOffThreadStencil(); +evalStencil(stencil); + +// Test stale ID. + +a = offThreadCompileToStencil(""); +stencilA = finishOffThreadStencil(a); +evalStencil(stencilA); +assertFails(() => finishOffThreadStencil(a)); + +a = offThreadCompileModuleToStencil(""); +stencilA = finishOffThreadStencil(a); +assertFails(() => finishOffThreadStencil(a)); +instantiateModuleStencil(stencilA); + +a = offThreadDecodeStencil(encodeScript("")); +stencilA = finishOffThreadStencil(a); +evalStencil(stencilA); +assertFails(() => finishOffThreadStencil(a)); + +// Test running multiple jobs. + +a = offThreadCompileToStencil("1"); +b = offThreadCompileToStencil("2"); +stencilA = finishOffThreadStencil(a); +stencilB = finishOffThreadStencil(b); +assertEq(evalStencil(stencilA), 1); +assertEq(evalStencil(stencilB), 2); + +a = offThreadCompileModuleToStencil(""); +b = offThreadCompileModuleToStencil(""); +stencilA = finishOffThreadStencil(a); +stencilB = finishOffThreadStencil(b); +assertEq(typeof instantiateModuleStencil(stencilA), "object"); +assertEq(typeof instantiateModuleStencil(stencilB), "object"); + +a = offThreadDecodeStencil(encodeScript("3")); +b = offThreadDecodeStencil(encodeScript("4")); +stencilA = finishOffThreadStencil(a); +stencilB = finishOffThreadStencil(b); +assertEq(evalStencil(stencilA), 3); +assertEq(evalStencil(stencilB), 4); + +// Test many jobs. + +const count = 100; +let jobs; + +jobs = new Array(count); +for (let i = 0; i < jobs.length; i++) + jobs[i] = offThreadCompileToStencil(`${i} * ${i}`); +for (let i = 0; i < jobs.length; i++) { + stencil = finishOffThreadStencil(jobs[i]); + assertEq(evalStencil(stencil), i * i); +} + +jobs = new Array(count); +for (let i = 0; i < jobs.length; i++) + jobs[i] = offThreadCompileModuleToStencil(""); +for (let i = 0; i < jobs.length; i++) { + stencil = finishOffThreadStencil(jobs[i]); + assertEq(typeof instantiateModuleStencil(stencil), "object"); +} + +jobs = new Array(count); +for (let i = 0; i < jobs.length; i++) + jobs[i] = offThreadDecodeStencil(encodeScript(`${i} * ${i}`)); +for (let i = 0; i < jobs.length; i++) { + stencil = finishOffThreadStencil(jobs[i]); + assertEq(evalStencil(stencil), i * i); +} diff --git a/js/src/jit-test/tests/parser/bug-1433014.js b/js/src/jit-test/tests/parser/bug-1433014.js new file mode 100644 index 0000000000..efb8ab98d3 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1433014.js @@ -0,0 +1,5 @@ +// |jit-test| skip-if: helperThreadCount() === 0 || !('oomTest' in this) +evaluate(` + oomTest(() => { + offThreadCompileToStencil(""); + });`); diff --git a/js/src/jit-test/tests/parser/bug-1465695.js b/js/src/jit-test/tests/parser/bug-1465695.js new file mode 100644 index 0000000000..9c63fcfd1b --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1465695.js @@ -0,0 +1,3 @@ +// |jit-test| skip-if: helperThreadCount() === 0 +for (let x = 0; x < 99; ++x) + evalInWorker("newGlobal().offThreadCompileToStencil(\"{}\");"); diff --git a/js/src/jit-test/tests/parser/bug-1470992.js b/js/src/jit-test/tests/parser/bug-1470992.js new file mode 100644 index 0000000000..6be1548590 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1470992.js @@ -0,0 +1,4 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +offThreadCompileModuleToStencil("export { x };"); +gcslice(10); diff --git a/js/src/jit-test/tests/parser/bug-1566974.js b/js/src/jit-test/tests/parser/bug-1566974.js new file mode 100644 index 0000000000..efd176daf0 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1566974.js @@ -0,0 +1,5 @@ +(() => { + (function() { + eval(''); + }()); +})(); diff --git a/js/src/jit-test/tests/parser/bug-1576865-1.js b/js/src/jit-test/tests/parser/bug-1576865-1.js new file mode 100644 index 0000000000..f31539b8ea --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1576865-1.js @@ -0,0 +1,49 @@ +// |jit-test| skip-if: !('oomTest' in this) +var sourceText = ` + function Outer() { + var X00, X01, X02, X03, X04, X05, X06, X07; + var X08, X09, X10, X11, X12, X13, X14, X15; + var X16, X17, X18, X19, X20, X21, X22, X23; + var X24, X25, X26, X27, X28, X29, X30, X31; + + function LazyFunction() { + // Lots of closed-over bindings. + { X00 = true; }; + { X01 = true; }; + { X02 = true; }; + { X03 = true; }; + { X04 = true; }; + { X05 = true; }; + { X06 = true; }; + { X07 = true; }; + { X08 = true; }; + { X09 = true; }; + { X10 = true; }; + { X11 = true; }; + { X12 = true; }; + { X13 = true; }; + { X14 = true; }; + { X15 = true; }; + { X16 = true; }; + { X17 = true; }; + { X18 = true; }; + { X19 = true; }; + { X20 = true; }; + { X21 = true; }; + { X22 = true; }; + { X23 = true; }; + { X24 = true; }; + { X25 = true; }; + { X26 = true; }; + { X27 = true; }; + { X28 = true; }; + { X29 = true; }; + { X30 = true; }; + { X31 = true; }; + } + } +`; + +oomTest(function() { + evaluate(sourceText); + }); diff --git a/js/src/jit-test/tests/parser/bug-1576865-2.js b/js/src/jit-test/tests/parser/bug-1576865-2.js new file mode 100644 index 0000000000..d053c24728 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1576865-2.js @@ -0,0 +1,44 @@ +// |jit-test| skip-if: !('oomTest' in this) +var sourceText = ` + function Outer() { + function LazyFunction() { + // Lots of inner functions. + function F00() { } + function F01() { } + function F02() { } + function F03() { } + function F04() { } + function F05() { } + function F06() { } + function F07() { } + function F08() { } + function F09() { } + function F10() { } + function F11() { } + function F12() { } + function F13() { } + function F14() { } + function F15() { } + function F16() { } + function F17() { } + function F18() { } + function F19() { } + function F20() { } + function F21() { } + function F22() { } + function F23() { } + function F24() { } + function F25() { } + function F26() { } + function F27() { } + function F28() { } + function F29() { } + function F30() { } + function F31() { } + } + } +`; + +oomTest(function() { + evaluate(sourceText); + }); diff --git a/js/src/jit-test/tests/parser/bug-1662260.js b/js/src/jit-test/tests/parser/bug-1662260.js new file mode 100644 index 0000000000..235737657e --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1662260.js @@ -0,0 +1,12 @@ +// |jit-test| skip-if: !('oomTest' in this) + +function loadX(lfVarx) { + oomTest(function() { + let m55 = parseModule(lfVarx); + }); +} +loadX(` + class B50 { + #priv() {} + } +`) diff --git a/js/src/jit-test/tests/parser/bug-1764737.js b/js/src/jit-test/tests/parser/bug-1764737.js new file mode 100644 index 0000000000..0fcc39e276 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-1764737.js @@ -0,0 +1,9 @@ +// |jit-test| skip-if: !('oomTest' in this); --fuzzing-safe; --ion-offthread-compile=off + +function r(src) { + oomTest(function() { + parseModule(src); + }); +} +r("export * from 'y';"); +r("export * from 'y';"); diff --git a/js/src/jit-test/tests/parser/bug-844805-1.js b/js/src/jit-test/tests/parser/bug-844805-1.js new file mode 100644 index 0000000000..b6bad21059 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-844805-1.js @@ -0,0 +1 @@ +if (Math["key"]) {} diff --git a/js/src/jit-test/tests/parser/bug-844805-2.js b/js/src/jit-test/tests/parser/bug-844805-2.js new file mode 100644 index 0000000000..5a278ef9b1 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-844805-2.js @@ -0,0 +1,10 @@ +// Constant folding does not affect strict delete. + +function f(x) { + "use strict"; + + // This senseless delete-expression is legal even in strict mode. Per ES5.1 + // 11.4.1 step 2, it does nothing and returns true. + return delete (1 ? x : x); +} +assertEq(f(), true); diff --git a/js/src/jit-test/tests/parser/bug-888002-1.js b/js/src/jit-test/tests/parser/bug-888002-1.js new file mode 100644 index 0000000000..44333e0bcf --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-888002-1.js @@ -0,0 +1 @@ +Function("var e = delete(false ? e : e)")(); diff --git a/js/src/jit-test/tests/parser/bug-888002-2.js b/js/src/jit-test/tests/parser/bug-888002-2.js new file mode 100644 index 0000000000..f0ccfca998 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-888002-2.js @@ -0,0 +1,12 @@ +// Constant folding doesn't affect non-strict delete. + +(function (x) { + // These senseless delete-expressions are legal. Per ES5.1 11.4.1 step 2, + // each one does nothing and returns true. + assertEq(delete (1 ? x : x), true); + assertEq(delete (0 || x), true); + assertEq(delete (1 && x), true); + + // This one is legal too, but returns false. + assertEq(delete x, false); +}()); diff --git a/js/src/jit-test/tests/parser/bug-888002-3.js b/js/src/jit-test/tests/parser/bug-888002-3.js new file mode 100644 index 0000000000..964ae2e1b9 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-888002-3.js @@ -0,0 +1,18 @@ +// Constant folding doesn't affect strict delete either. +// In particular, it doesn't affect whether |delete x| is a strict error. + +load(libdir + "asserts.js"); + +(function (x) { + "use strict"; + + // These senseless delete-expressions are legal even in strict mode. + // Per ES5.1 11.4.1 step 2, each one does nothing and returns true. + assertEq(delete (1 ? x : x), true); + assertEq(delete (0 || x), true); + assertEq(delete (1 && x), true); + + // Plain `delete x` is a SyntaxError though. + assertThrowsInstanceOf(() => eval('delete x'), SyntaxError); + assertThrowsInstanceOf(() => Function('"use strict"; delete x'), SyntaxError); +}()); diff --git a/js/src/jit-test/tests/parser/bug-888002.js b/js/src/jit-test/tests/parser/bug-888002.js new file mode 100644 index 0000000000..44333e0bcf --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-888002.js @@ -0,0 +1 @@ +Function("var e = delete(false ? e : e)")(); diff --git a/js/src/jit-test/tests/parser/bug-889628.js b/js/src/jit-test/tests/parser/bug-889628.js new file mode 100644 index 0000000000..bb337c35d7 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-889628.js @@ -0,0 +1,33 @@ +// Destructuring assignment to eval or arguments in destructuring is a SyntaxError +// in strict mode + +load(libdir + "asserts.js"); + +var patterns = [ + "[_]", + "[a, b, _]", + "[[_]]", + "[[], [{}, [_]]]", + "{x:_}", + "{x:y, z:_}", + "{0:_}", + "{_}", + "[..._]" +]; + +for (var pattern of patterns) { + var stmt = pattern + " = obj"; + if (stmt[0] == "{") + stmt = "(" + stmt + ")"; + stmt += ";" + + // stmt is a legal statement... + Function(stmt); + + // ...but not if you replace _ with one of these two names. + for (var name of ["eval", "arguments"]) { + var s = stmt.replace("_", name); + Function(s); + assertThrowsInstanceOf(() => Function("'use strict'; " + s), SyntaxError); + } +} diff --git a/js/src/jit-test/tests/parser/bug-896126.js b/js/src/jit-test/tests/parser/bug-896126.js new file mode 100644 index 0000000000..334ea33b92 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-896126.js @@ -0,0 +1,11 @@ +// |jit-test| error: SyntaxError +({ + r: function() { + function f() { + w[0xe56241c6 >> 3] + } + }, + s: function() { + "use asm" + return (1 for + diff --git a/js/src/jit-test/tests/parser/bug-975484.js b/js/src/jit-test/tests/parser/bug-975484.js new file mode 100644 index 0000000000..b164492240 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug-975484.js @@ -0,0 +1,7 @@ +var loc = Reflect.parse("f()").body[0].expression.loc; +assertEq(loc.start.column, 0); +assertEq(loc.end.column, 3); + +loc = Reflect.parse("f(x)").body[0].expression.loc; +assertEq(loc.start.column, 0); +assertEq(loc.end.column, 4); diff --git a/js/src/jit-test/tests/parser/bug1461034.js b/js/src/jit-test/tests/parser/bug1461034.js new file mode 100644 index 0000000000..84d6ae88ca --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1461034.js @@ -0,0 +1,2 @@ +// |jit-test| skip-if: !('oomTest' in this) +oomTest(function(){s[-1]}); diff --git a/js/src/jit-test/tests/parser/bug1547655.js b/js/src/jit-test/tests/parser/bug1547655.js new file mode 100644 index 0000000000..540e011d9a --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1547655.js @@ -0,0 +1,2 @@ +// |jit-test| allow-unhandlable-oom; allow-oom; skip-if: !('oomTest' in this) +oomTest(() => evaluate(`meta: { with({}) {} }`)); diff --git a/js/src/jit-test/tests/parser/bug1604952.js b/js/src/jit-test/tests/parser/bug1604952.js new file mode 100644 index 0000000000..66ccfe76e5 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1604952.js @@ -0,0 +1,4 @@ +// This is a leak test to ensure that a folded +// RegExp parse node doesn't leak data. + +/x/ diff --git a/js/src/jit-test/tests/parser/bug1605254.js b/js/src/jit-test/tests/parser/bug1605254.js new file mode 100644 index 0000000000..b8b1794785 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1605254.js @@ -0,0 +1,4 @@ +// This is a leak test to ensure that a folded +// BigInt parse node doesn't leak data. + +128n diff --git a/js/src/jit-test/tests/parser/bug1657557.js b/js/src/jit-test/tests/parser/bug1657557.js new file mode 100644 index 0000000000..6035035166 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1657557.js @@ -0,0 +1,7 @@ +setImmutablePrototype(Function.__proto__); + +if (helperThreadCount() > 0) { + offThreadCompileToStencil("function f() {}"); + var stencil = finishOffThreadStencil(); + evalStencil(stencil); +} diff --git a/js/src/jit-test/tests/parser/bug1661454.js b/js/src/jit-test/tests/parser/bug1661454.js new file mode 100644 index 0000000000..ca7792f4bc --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1661454.js @@ -0,0 +1,12 @@ +// |jit-test| skip-if: !('oomTest' in this) + +function oomTestEval(lfVarx) { + oomTest(() => eval(lfVarx)); +} + +oomTestEval(``); +oomTestEval(` + { + function bug1661454() { } + } +`); diff --git a/js/src/jit-test/tests/parser/bug1750935.js b/js/src/jit-test/tests/parser/bug1750935.js new file mode 100644 index 0000000000..e4f7440848 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1750935.js @@ -0,0 +1,11 @@ +// Parse-time static string lookup. +var s = "\ue531\ue531\ue531"; +assertEq(s.codePointAt(0), 0xe531); +assertEq(s.codePointAt(1), 0xe531); +assertEq(s.codePointAt(2), 0xe531); + +// Runtime static string lookup. +s = "\ue531\ue531\ue5310n".split(/\d[^]/)[0]; +assertEq(s.codePointAt(0), 0xe531); +assertEq(s.codePointAt(1), 0xe531); +assertEq(s.codePointAt(2), 0xe531); diff --git a/js/src/jit-test/tests/parser/bug1764715.js b/js/src/jit-test/tests/parser/bug1764715.js new file mode 100644 index 0000000000..b203925aa8 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1764715.js @@ -0,0 +1,4 @@ +// |jit-test| skip-if: !('oomTest' in this) +oomTest(function() { + let m = parseModule(`x = a?.b; x = a?.b; x = a?.b;`); +}); diff --git a/js/src/jit-test/tests/parser/bug1803036.js b/js/src/jit-test/tests/parser/bug1803036.js new file mode 100644 index 0000000000..f1ab09a1c6 --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1803036.js @@ -0,0 +1,22 @@ +// Test that parsing the given source text will throw an error with location set +// to last character in source, rather than after it. +function testErrorPosition(src) { + let failed = false; + + try { + parse(src) + } + catch (e) { + failed = true; + assertEq(e.lineNumber, 1) + assertEq(e.columnNumber, src.length - 1) + } + + assertEq(failed, true); +} + +testErrorPosition("0_") // No trailing separator - Zero +testErrorPosition("00_") // No trailing separator - Octal +testErrorPosition("1_") // No trailing separator - Number +testErrorPosition("1__") // No repeated separator +testErrorPosition("00n") // No octal BigInt diff --git a/js/src/jit-test/tests/parser/bug1835785.js b/js/src/jit-test/tests/parser/bug1835785.js new file mode 100644 index 0000000000..25317757ec --- /dev/null +++ b/js/src/jit-test/tests/parser/bug1835785.js @@ -0,0 +1,8 @@ +// |jit-test| allow-unhandlable-oom; allow-oom; skip-if: !('oomAtAllocation' in this) +function main() { + this + oomAtAllocation(7); + var v7 = /a/ + disassemble(); +} +main(); diff --git a/js/src/jit-test/tests/parser/bytecode-sharing.js b/js/src/jit-test/tests/parser/bytecode-sharing.js new file mode 100644 index 0000000000..26f0ac429c --- /dev/null +++ b/js/src/jit-test/tests/parser/bytecode-sharing.js @@ -0,0 +1,103 @@ +// Test that bytecode is still shared when expected. The expectations can be +// updated if necessary. + + +// Check the testing function. +evaluate(`function a01(){ return a + b; }`) +evaluate(`function a02(){ return a + b; }`) +evaluate(`function a03(){ return a + b + c; }`) +assertEq(hasSameBytecodeData(a01, a02), true) +assertEq(hasSameBytecodeData(a01, a03), false) + + +// Check effect of whitespace. +evaluate(`function b(){}`) +evaluate(`function b01(){}`) +evaluate(`function b02 (){}`) +evaluate(`function b03( ){}`) +evaluate(`function b04() {}`) +evaluate(`function b05(){ }`) +assertEq(hasSameBytecodeData(b, b01), true) +assertEq(hasSameBytecodeData(b, b02), true) +assertEq(hasSameBytecodeData(b, b03), false) +assertEq(hasSameBytecodeData(b, b04), false) +assertEq(hasSameBytecodeData(b, b05), false) + + +// Check effect of binding names. +evaluate(`function c01(){ return a; }`) +evaluate(`function c02(){ return b; }`) +evaluate(`function c03(){ return cc; }`) +assertEq(hasSameBytecodeData(c01, c02), true) +assertEq(hasSameBytecodeData(c01, c03), false) + + +// Check effect of string literals. +evaluate(`function d01(){ return "AA"; }`) +evaluate(`function d02(){ return "BB"; }`) +assertEq(hasSameBytecodeData(d01, d02), true) + + +// Check effect of string template literals. +evaluate("function e01(){ return a`AA`; }") +evaluate("function e02(){ return b`BB`; }") +assertEq(hasSameBytecodeData(e01, e02), true) + + +// Check effect of object literals. +evaluate(`function f01(){ return { a: 1 }; }`) +evaluate(`function f02(){ return { b: 1 }; }`) +evaluate(`function f03(){ return { b: 2 }; }`) +assertEq(hasSameBytecodeData(f01, f02), true) +assertEq(hasSameBytecodeData(f01, f03), false) + + +// Check effect of inner functions. +evaluate(`function g01(){ return () => 0; }`) +evaluate(`function g02(){ return () => 0; }`) +evaluate(`function g03(){ return () => a; }`) +assertEq(hasSameBytecodeData(g01, g02), true) +assertEq(hasSameBytecodeData(g01, g03), true) + + +// Check effect of line number. +evaluate(`function h01(){ return 0; }`) +evaluate(`\nfunction h02(){ return 0; }`) +evaluate(`\n\n\n\n\n\n\nfunction h03(){ return 0; }`) +assertEq(hasSameBytecodeData(h01, h02), true) +assertEq(hasSameBytecodeData(h01, h03), true) + + +// Check effect of line number when function has large gaps in it. This +// corresponds to SetLine source-notes. +evaluate(`function i01(){ return\n\n\n\n\n\n\n\n0; }`) +evaluate(`\nfunction i02(){ return\n\n\n\n\n\n\n\n0; }`) +evaluate(`\n\n\n\n\n\n\nfunction i03(){ return\n\n\n\n\n\n\n\n0; }`) +assertEq(hasSameBytecodeData(i01, i02), true) +assertEq(hasSameBytecodeData(i01, i03), true) + + +// Check effect of column number. +evaluate(`function j01(){ return 0; }`) +evaluate(` function j02(){ return 0; }`) +evaluate(` \tfunction j03(){ return 0; }`) +assertEq(hasSameBytecodeData(j01, j02), true) +assertEq(hasSameBytecodeData(j01, j03), true) + + +// Check different forms of functions. +evaluate(`function k01 () { return 0; }`) +evaluate(`var k02 = function() { return 0; }`) +evaluate(`var k03 = () => { return 0; }`) +assertEq(hasSameBytecodeData(k01, k02), true) +assertEq(hasSameBytecodeData(k01, k03), true) + + +// Check sharing across globals / compartments. +let l02_global = newGlobal({newCompartment: false}); +let l03_global = newGlobal({newCompartment: true}); +evaluate(`function l01() { return 0; }`) +l02_global.evaluate(`function l02() { return 0; }`) +l03_global.evaluate(`function l03() { return 0; }`) +assertEq(hasSameBytecodeData(l01, l02_global.l02), true) +assertEq(hasSameBytecodeData(l01, l03_global.l03), true) diff --git a/js/src/jit-test/tests/parser/columnNumber.js b/js/src/jit-test/tests/parser/columnNumber.js new file mode 100644 index 0000000000..051212c76b --- /dev/null +++ b/js/src/jit-test/tests/parser/columnNumber.js @@ -0,0 +1,52 @@ +// Simple tests for evaluate's "columnNumber" option. + +load(libdir + 'asserts.js'); + +assertEq(evaluate("saveStack().column"), 1); +assertEq(evaluate("saveStack().column", { columnNumber: 1729 }), 1730); +assertEq(evaluate("\nsaveStack().column", { columnNumber: 1729 }), 1); +assertEq(evaluate("saveStack().column", { columnNumber: "42" }), 43); +assertThrowsInstanceOf(() => evaluate("saveStack().column", { columnNumber: -10 }), + RangeError); +assertThrowsInstanceOf(() => evaluate("saveStack().column", { columnNumber: Math.pow(2,30) }), + RangeError); + +if (helperThreadCount() > 0) { + print("offThreadCompileToStencil 1"); + offThreadCompileToStencil("saveStack().column", { columnNumber: -10 }); + assertThrowsInstanceOf(() => { + var stencil = finishOffThreadStencil(); + evalStencil(stencil); + }, RangeError); + + print("offThreadCompileToStencil 2"); + offThreadCompileToStencil("saveStack().column", { columnNumber: Math.pow(2,30) }); + assertThrowsInstanceOf(() => { + var stencil = finishOffThreadStencil(); + evalStencil(); + }, RangeError); + + print("offThreadCompileToStencil 3"); + offThreadCompileToStencil("saveStack().column", { columnNumber: 10000 }); + stencil = finishOffThreadStencil(); + assertEq(evalStencil(stencil), 10001); +} + +// Check handling of columns near the limit of our ability to represent them. +// (This is hardly thorough, but since web content can't set column numbers, +// it's probably not worth it to be thorough.) +const maxColumn = Math.pow(2, 30) - 1; +assertEq(evaluate("saveStack().column", { columnNumber: maxColumn }), + maxColumn + 1); + +// Check the saturation behavior when we reach the limit of the column +// representation. +assertEq(evaluate(" saveStack().column", { columnNumber: maxColumn }), + maxColumn + 1); + +// Gathering source text for inclusion in error messages should not try to reach +// outside the buffer to find the start of the source line. The below should +// report the error without crashing. +assertThrowsInstanceOf(() => evaluate("function x(y,y) { 'use strict'; } x()", + { columnNumber: 10 }), + SyntaxError); diff --git a/js/src/jit-test/tests/parser/compile-script.js b/js/src/jit-test/tests/parser/compile-script.js new file mode 100644 index 0000000000..293d25632e --- /dev/null +++ b/js/src/jit-test/tests/parser/compile-script.js @@ -0,0 +1,50 @@ +// |jit-test| skip-if: !('oomTest' in this) + +load(libdir + "asserts.js"); + +let stencil = compileToStencil('314;'); +assertEq(evalStencil(stencil), 314); + +stencil = compileToStencil('let o = { a: 42, b: 2718 }["b"]; o', { prepareForInstantiate: true }); +assertEq(evalStencil(stencil), 2718); + +assertThrowsInstanceOf(() => compileToStencil('let fail ='), SyntaxError); +assertThrowsInstanceOf(() => compileToStencil('42;', 42), Error); + +oomTest(function() { + compileToStencil('"hello stencil!";', { prepareForInstantiate: false }); +}); + +oomTest(function() { + compileToStencil('"hello stencil!";', { prepareForInstantiate: true }); +}); + +// Modules +function compileAndEvaluateModule(script, options) { + if (!options) { + options = {}; + } + options.module = true; + let stencil = compileToStencil(script, options); + let m = instantiateModuleStencil(stencil); + moduleLink(m); + moduleEvaluate(m); + return m; +} + +var m = compileAndEvaluateModule('export let r = 314;'); +assertEq(getModuleEnvironmentValue(m, "r"), 314); + +m = compileAndEvaluateModule('export let r = { a: 42, b: 2718 }["b"];', { prepareForInstantiate: true }); +assertEq(getModuleEnvironmentValue(m, "r"), 2718); + +assertThrowsInstanceOf(() => compileAndEvaluateModule('let fail ='), SyntaxError); +assertThrowsInstanceOf(() => compileToStencil('42;', 42), Error); + +oomTest(function() { + compileAndEvaluateModule('export let r = "hello stencil!";', { prepareForInstantiate: false }); +}); + +oomTest(function() { + compileAndEvaluateModule('export let r = "hello stencil!";', { prepareForInstantiate: true }); +}); diff --git a/js/src/jit-test/tests/parser/dumpStencil-01.js b/js/src/jit-test/tests/parser/dumpStencil-01.js new file mode 100644 index 0000000000..5c06d579c0 --- /dev/null +++ b/js/src/jit-test/tests/parser/dumpStencil-01.js @@ -0,0 +1,24 @@ +dumpStencil("a"); +dumpStencil("ab"); +dumpStencil("abc"); +dumpStencil("/a/"); +dumpStencil("/ab/"); +dumpStencil("/abc/"); +dumpStencil("1"); +dumpStencil("1.2"); +dumpStencil("true"); +dumpStencil("[]"); +dumpStencil("[1]"); +dumpStencil("[1, 2]"); +dumpStencil("({})"); +dumpStencil("({x: 10})"); +dumpStencil("({x: a})"); +dumpStencil("({x:10, y: 20})"); +dumpStencil("({x:10, y: a})"); +dumpStencil("({x:10, [y]: a})"); +dumpStencil("function y() {}"); +dumpStencil("(function y() {})"); +dumpStencil("(function() {})"); +dumpStencil("1n"); +dumpStencil("100n"); +dumpStencil("export var z;", { module : true }); diff --git a/js/src/jit-test/tests/parser/fold-constant-index-access.js b/js/src/jit-test/tests/parser/fold-constant-index-access.js new file mode 100644 index 0000000000..eabe2c5787 --- /dev/null +++ b/js/src/jit-test/tests/parser/fold-constant-index-access.js @@ -0,0 +1,47 @@ +// Constant folding optimizes the element access with string that contains +// 32-bit unsignned integer. +// The result shouldn't be visible to the script, and the optimization shouldn't +// change the behavior. + +// Asserts that the property name and the value are same. +var validator = new Proxy({}, { + set(that, prop, value) { + assertEq(prop, value); + } +}); + +// Optimizable cases. +validator["0"] = "0"; +validator["1"] = "1"; +validator["10"] = "10"; +validator["123"] = "123"; + +// Not optimizable cases. + +// More than UINT32_MAX. +validator["4294967296"] = "4294967296"; +validator["10000000000000"] = "10000000000000"; + +// Leading 0. +validator["01"] = "01"; +validator["0000001"] = "0000001"; + +// Sign. +validator["+1"] = "+1"; +validator["-1"] = "-1"; + +// Non-decimal +validator["0b1"] = "0b1"; +validator["0o1"] = "0o1"; +validator["0x1"] = "0x1"; + +// Non-integer. +validator["1.1"] = "1.1"; +validator["1."] = "1."; +validator[".1"] = ".1"; +validator["0.1"] = "0.1"; + +// Extra character. +validator["1a"] = "1a"; +validator["1 "] = "1 "; +validator[" 1"] = " 1"; diff --git a/js/src/jit-test/tests/parser/home-object-getter.js b/js/src/jit-test/tests/parser/home-object-getter.js new file mode 100644 index 0000000000..d4ee62acc9 --- /dev/null +++ b/js/src/jit-test/tests/parser/home-object-getter.js @@ -0,0 +1,4 @@ +var o = {get a() { + return eval("5"); +}} +assertEq(o.a, 5); diff --git a/js/src/jit-test/tests/parser/lazy-flag-consistency.js b/js/src/jit-test/tests/parser/lazy-flag-consistency.js new file mode 100644 index 0000000000..06096beaa6 --- /dev/null +++ b/js/src/jit-test/tests/parser/lazy-flag-consistency.js @@ -0,0 +1,65 @@ +// These tests highlight potential differences between the lazy and non-lazy +// parse modes. The delazification process should be able to assert that script +// flags are consistent. + +function dead_inner_function_1() { + (function() {}) +} +dead_inner_function_1(); + +function dead_inner_function_2() { + if (false) { + function inner() {} + } +} +dead_inner_function_2(); + +function inner_eval_1() { + eval(""); +} +inner_eval_1(); + +function inner_eval_2() { + (function() { + eval(""); + }) +} +inner_eval_2(); + +function inner_eval_3() { + (() => eval("")); +} +inner_eval_3(); + +function inner_delete_1() { + var x; + (function() { delete x; }) +} +inner_delete_1(); + +function inner_delete_2() { + var x; + (() => delete x); +} +inner_delete_2(); + +function inner_this_1() { + (() => this); +} +inner_this_1(); + +function inner_arguments_1() { + (() => arguments); +} +inner_arguments_1(); + +function constructor_wrapper_1() { + return (function() { + this.initialize.apply(this, arguments); + }); +} +constructor_wrapper_1(); + +var runonce_lazy_1 = function (){}(); + +var runonce_lazy_2 = function* (){}(); diff --git a/js/src/jit-test/tests/parser/lazy-parse-bad-offset.js b/js/src/jit-test/tests/parser/lazy-parse-bad-offset.js new file mode 100644 index 0000000000..676fcd75cb --- /dev/null +++ b/js/src/jit-test/tests/parser/lazy-parse-bad-offset.js @@ -0,0 +1,4 @@ +// Bug 1098132: Shouldn't assert. + +function eval() {}; +eval(); diff --git a/js/src/jit-test/tests/parser/let-after-directive.js b/js/src/jit-test/tests/parser/let-after-directive.js new file mode 100644 index 0000000000..58864ab341 --- /dev/null +++ b/js/src/jit-test/tests/parser/let-after-directive.js @@ -0,0 +1,6 @@ +// 'let' after "use strict" directive without semicolon is lexed as TOK_NAME +// before parsing the directive. 'let' with TOK_NAME should be handled +// correctly in strict mode. + +"use strict" +let a = 1; diff --git a/js/src/jit-test/tests/parser/letContextualKeyword.js b/js/src/jit-test/tests/parser/letContextualKeyword.js new file mode 100644 index 0000000000..8bccfacf0f --- /dev/null +++ b/js/src/jit-test/tests/parser/letContextualKeyword.js @@ -0,0 +1,110 @@ +function expectError(str) { + var log = ""; + try { + eval(str); + } catch (e) { + log += "e"; + assertEq(e instanceof SyntaxError, true); + } + assertEq(log, "e"); +} + +eval(`let x = 42; assertEq(x, 42);`); +eval(`var let = 42; assertEq(let, 42);`); +eval(`let;`); +eval(`[...let] = [];`); +eval(`function let() { return 42; } assertEq(let(), 42);`) +eval(`let {x:x} = {x:42}; assertEq(x, 42);`); +eval(`let [x] = [42]; assertEq(x, 42);`); + +eval(`for (let x in [1]) { assertEq(x, "0"); }`); +eval(`for (const x in [1]) { assertEq(x, "0"); }`); + +eval(`for (let x of [1]) { assertEq(x, 1); }`); +eval(`for (const x of [1]) { assertEq(x, 1); }`); + +eval(`for (let i = 0; i < 1; i++) { assertEq(i, 0); }`); +eval(`var done = false; for (const i = 0; !done; done = true) { assertEq(i, 0); }`); + +eval(`for (let of of [1]) { assertEq(of, 1); }`); +eval(`for (const of of [1]) { assertEq(of, 1); }`); + +eval(`try { throw 17; } catch (let) { assertEq(let, 17); }`); +eval(`try { throw [17]; } catch ([let]) { assertEq(let, 17); }`); +eval(`try { throw { x: 17 }; } catch ({ x: let }) { assertEq(let, 17); }`); +eval(`try { throw {}; } catch ({ x: let = 17 }) { assertEq(let, 17); }`); + +expectError(`try { throw [17, 42]; } catch ([let, let]) {}`); + +eval(`for (let in [1]) { assertEq(let, "0"); }`); +eval(`for (let / 1; ; ) { break; }`); +expectError(`let = {}; for (let.x of;;);`); +expectError(`for (let of [1]) { }`); + +expectError(`for (let let in [1]) { }`); +expectError(`for (const let in [1]) { }`); + +expectError(`for (let let of [1]) { }`); +expectError(`for (const let of [1]) { }`); + +expectError(`for (let let = 17; false; ) { }`); +expectError(`for (const let = 17; false; ) { }`); + +expectError(`for (let [let] = 17; false; ) { }`); +expectError(`for (const [let] = 17; false; ) { }`); + +expectError(`for (let [let = 42] = 17; false; ) { }`); +expectError(`for (const [let = 42] = 17; false; ) { }`); + +expectError(`for (let { x: let } = 17; false; ) { }`); +expectError(`for (const { x: let } = 17; false; ) { }`); + +expectError(`for (let { x: let = 42 } = 17; false; ) { }`); +expectError(`for (const { x: let = 42 } = 17; false; ) { }`); + +expectError("let\nlet;"); +expectError("const\nlet;"); + +expectError(`let let = 17;`); +expectError(`const let = 17;`); + +expectError(`let [let] = 17;`); +expectError(`const [let] = 17;`); + +expectError(`let [let = 42] = 17;`); +expectError(`const [let = 42] = 17;`); + +expectError(`let {let} = 17;`); +expectError(`const {let} = 17;`); + +expectError(`let { let = 42 } = 17;`); +expectError(`const { let = 42 } = 17;`); + +expectError(`let { x: let } = 17;`); +expectError(`const { x: let } = 17;`); + +expectError(`let { x: let = 42 } = 17;`); +expectError(`const { x: let = 42 } = 17;`); + +expectError(`let { ['y']: let } = 17;`); +expectError(`const { ['y']: let } = 17;`); + +expectError(`let { ['y']: let = 42 } = 17;`); +expectError(`const { ['y']: let = 42 } = 17;`); + +expectError(`let { x: [let] } = { x: 17 };`); +expectError(`const { x: [let] } = { x: 17 };`); + +expectError(`let { x: [let = 42] } = { x: 17 };`); +expectError(`const { x: [let = 42] } = { x: 17 };`); + +expectError(`let [foo, let] = 42;`); +expectError(`const [foo, let] = 42;`); + +expectError(`let [foo, { let }] = [17, {}];`); +expectError(`const [foo, { let }] = [17, {}];`); + +expectError(`"use strict"; var let = 42;`); +expectError(`"use strict"; function let() {}`); +expectError(`"use strict"; for (let of [1]) {}`); +expectError(`"use strict"; try {} catch (let) {}`); diff --git a/js/src/jit-test/tests/parser/lineNumber.js b/js/src/jit-test/tests/parser/lineNumber.js new file mode 100644 index 0000000000..f86efbc03e --- /dev/null +++ b/js/src/jit-test/tests/parser/lineNumber.js @@ -0,0 +1,37 @@ + +// Simple tests for evaluate's "lineNumber" option. + +load(libdir + 'asserts.js'); + +const maxLine = Math.pow(2,32) - 1; + +assertEq(evaluate("saveStack().line"), 1); +assertEq(evaluate("saveStack().line", { lineNumber: maxLine }), maxLine); +assertEq(evaluate("\nsaveStack().line"), 2); +assertEq(evaluate("\nsaveStack().line", { lineNumber: 1000 }), 1001); +assertThrowsInstanceOf(() => evaluate("\nsaveStack().line", { lineNumber: maxLine }), + RangeError); + +if (helperThreadCount() > 0) { + offThreadCompileToStencil("saveStack().line"); + var stencil = finishOffThreadStencil(); + assertEq(evalStencil(stencil), 1); + + offThreadCompileToStencil("saveStack().line", { lineNumber: maxLine }); + stencil = finishOffThreadStencil(); + assertEq(evalStencil(stencil), maxLine); + + offThreadCompileToStencil("\nsaveStack().line"); + stencil = finishOffThreadStencil(); + assertEq(evalStencil(stencil), 2); + + offThreadCompileToStencil("\nsaveStack().line", { lineNumber: 1000 }); + stencil = finishOffThreadStencil(); + assertEq(evalStencil(stencil), 1001); + + offThreadCompileToStencil("\nsaveStack().line", { lineNumber: maxLine }); + assertThrowsInstanceOf(() => { + stencil = finishOffThreadStencil(); + evalStencil(stencil); + }, RangeError); +} diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js new file mode 100644 index 0000000000..6820954aeb --- /dev/null +++ b/js/src/jit-test/tests/parser/missing-closing-brace.js @@ -0,0 +1,90 @@ +function test(source, [lineNumber, columnNumber], openType = "{", closeType = "}") { + let caught = false; + try { + Reflect.parse(source, { source: "foo.js" }); + } catch (e) { + assertEq(e.message.includes("missing " + closeType + " "), true); + let notes = getErrorNotes(e); + assertEq(notes.length, 1); + let note = notes[0]; + assertEq(note.message, openType + " opened at line " + lineNumber + ", column " + columnNumber); + assertEq(note.fileName, "foo.js"); + assertEq(note.lineNumber, lineNumber); + assertEq(note.columnNumber, columnNumber); + caught = true; + } + assertEq(caught, true); +} + +// Function + +test(` +function test1() { +} +function test2() { + if (true) { + //} +} +function test3() { +} +`, [4, 17]); + +// Block statement. +test(` +{ + if (true) { +} +`, [2, 0]); +test(` +if (true) { + if (true) { +} +`, [2, 10]); +test(` +for (;;) { + if (true) { +} +`, [2, 9]); +test(` +while (true) { + if (true) { +} +`, [2, 13]); +test(` +do { + do { +} while(true); +`, [2, 3]); + +// try-catch-finally. +test(` +try { + if (true) { +} +`, [2, 4]); +test(` +try { +} catch (e) { + if (true) { +} +`, [3, 12]); +test(` +try { +} finally { + if (true) { +} +`, [3, 10]); + +// Object literal. +test(` +var x = { + foo: { +}; +`, [2, 8]); + +// Array literal. +test(` +var x = [ + [ +]; +`, [2, 8], "[", "]"); diff --git a/js/src/jit-test/tests/parser/modifier-arrow-rest.js b/js/src/jit-test/tests/parser/modifier-arrow-rest.js new file mode 100644 index 0000000000..e66aa5c37d --- /dev/null +++ b/js/src/jit-test/tests/parser/modifier-arrow-rest.js @@ -0,0 +1,11 @@ +load(libdir + "syntax.js"); + +var postfixes = [ + "...foo) => 1 @", +]; + +function check_syntax_error(e, code) { + assertEq(e instanceof SyntaxError, true); +} + +test_syntax(postfixes, check_syntax_error, true); diff --git a/js/src/jit-test/tests/parser/modifier-do-while.js b/js/src/jit-test/tests/parser/modifier-do-while.js new file mode 100644 index 0000000000..9fa9b06dfe --- /dev/null +++ b/js/src/jit-test/tests/parser/modifier-do-while.js @@ -0,0 +1,12 @@ +do 1 +while(false); + +do if (1) { +} while(false); + +do if (1) 1 +while(false); + +do try { +} catch(ex) { +} while(false); diff --git a/js/src/jit-test/tests/parser/modifier-regexp-vs-div.js b/js/src/jit-test/tests/parser/modifier-regexp-vs-div.js new file mode 100644 index 0000000000..7754bcb191 --- /dev/null +++ b/js/src/jit-test/tests/parser/modifier-regexp-vs-div.js @@ -0,0 +1,12 @@ +load(libdir + "syntax.js"); + +var postfixes = [ + "/bar/g; @", + "\n/bar/g; @", +]; + +function check_syntax_error(e, code) { + assertEq(e instanceof SyntaxError, true); +} + +test_syntax(postfixes, check_syntax_error, true); diff --git a/js/src/jit-test/tests/parser/modifier-semicolon-insertion.js b/js/src/jit-test/tests/parser/modifier-semicolon-insertion.js new file mode 100644 index 0000000000..5a5dfee0f2 --- /dev/null +++ b/js/src/jit-test/tests/parser/modifier-semicolon-insertion.js @@ -0,0 +1,48 @@ +Reflect.parse(` +let a +f2() +`); +Reflect.parse(` +let a=1 +f2() +`); +Reflect.parse(` +import 'a' +f2() +`, {target: "module"}); +Reflect.parse(` +export { a } from 'a' +f2() +`, {target: "module"}); +Reflect.parse(` +var a +f2() +`); +Reflect.parse(` +var a=1 +f2() +`); +Reflect.parse(` +f1() +f2() +`); +Reflect.parse(` +while(false) { continue +f2() } +`); +Reflect.parse(` +while(false) { break +f2() } +`); +Reflect.parse(` +function a() { return +f2() } +`); +Reflect.parse(` +throw 1 +f2() +`); +Reflect.parse(` +debugger +f2() +`); diff --git a/js/src/jit-test/tests/parser/modifier-yield-without-operand-1.js b/js/src/jit-test/tests/parser/modifier-yield-without-operand-1.js new file mode 100644 index 0000000000..635acbe323 --- /dev/null +++ b/js/src/jit-test/tests/parser/modifier-yield-without-operand-1.js @@ -0,0 +1,12 @@ +load(libdir + "syntax.js"); + +var postfixes = [ + "yield, @", + "yield; @", +]; + +function check_syntax_error(e, code) { + // No need to check exception type +} + +test_syntax(postfixes, check_syntax_error, true); diff --git a/js/src/jit-test/tests/parser/modifier-yield-without-operand-2.js b/js/src/jit-test/tests/parser/modifier-yield-without-operand-2.js new file mode 100644 index 0000000000..2b7a8ddedb --- /dev/null +++ b/js/src/jit-test/tests/parser/modifier-yield-without-operand-2.js @@ -0,0 +1,13 @@ +load(libdir + "syntax.js"); + +var postfixes = [ + "yield) @", + "yield} @", + "yield] @", +]; + +function check_syntax_error(e, code) { + // No need to check exception type +} + +test_syntax(postfixes, check_syntax_error, true); diff --git a/js/src/jit-test/tests/parser/off_thread_compile_throws_error.js b/js/src/jit-test/tests/parser/off_thread_compile_throws_error.js new file mode 100644 index 0000000000..7b4323f908 --- /dev/null +++ b/js/src/jit-test/tests/parser/off_thread_compile_throws_error.js @@ -0,0 +1,7 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +load(libdir + "asserts.js"); + +offThreadCompileToStencil("var shouldFailToParse ="); + +assertThrowsInstanceOf(() => finishOffThreadStencil(), SyntaxError); diff --git a/js/src/jit-test/tests/parser/oom-tracking-line-starts-in-tokenizer.js b/js/src/jit-test/tests/parser/oom-tracking-line-starts-in-tokenizer.js new file mode 100644 index 0000000000..46aa1dbd04 --- /dev/null +++ b/js/src/jit-test/tests/parser/oom-tracking-line-starts-in-tokenizer.js @@ -0,0 +1,143 @@ +// Constraints on this test's appearance: +// +// * |TokenStream::SourceCoords::add| must try to allocate memory. (This test +// ensures this happens by making the function below >=128 lines long so +// that |SourceCoords::lineStartOffsets_| must convert to heap storage. The +// precise approach doesn't matter.) +// * That allocation attempt must fail (by forced simulated OOM, here). +// +// It'd be nice to build up the function programmatically, but it appears that +// the above only happens if the provided function has a lazy script. Cursory +// attempts to relazify |Function("...")| didn't work, so this fuzzer-like +// version had to be used instead. +if ("oomTest" in this) { + oomTest(function() { + try { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } catch(e) { + ; + } + }) +} diff --git a/js/src/jit-test/tests/parser/optimized-out-functions.js b/js/src/jit-test/tests/parser/optimized-out-functions.js new file mode 100644 index 0000000000..10c225d548 --- /dev/null +++ b/js/src/jit-test/tests/parser/optimized-out-functions.js @@ -0,0 +1,7 @@ +// Functions optimized out by constant-folding should have correct +// stencil data. +// This shouldn't hit any assertion while iterating stencil while instantiation. +(function() { + (function() { + }); +}); diff --git a/js/src/jit-test/tests/parser/parse-module.js b/js/src/jit-test/tests/parser/parse-module.js new file mode 100644 index 0000000000..3303be2253 --- /dev/null +++ b/js/src/jit-test/tests/parser/parse-module.js @@ -0,0 +1 @@ +parse("1", {module: true}); diff --git a/js/src/jit-test/tests/parser/parse-non-ascii-latin1.js b/js/src/jit-test/tests/parser/parse-non-ascii-latin1.js new file mode 100644 index 0000000000..91d0c8bd20 --- /dev/null +++ b/js/src/jit-test/tests/parser/parse-non-ascii-latin1.js @@ -0,0 +1,5 @@ +load(libdir + "asserts.js"); + +parse("10"); +assertThrowsInstanceOf(() => parse("10_"), SyntaxError); +assertThrowsInstanceOf(() => parse("10_\xff"), SyntaxError); diff --git a/js/src/jit-test/tests/parser/redeclaration-message.js b/js/src/jit-test/tests/parser/redeclaration-message.js new file mode 100644 index 0000000000..29de3cf7ba --- /dev/null +++ b/js/src/jit-test/tests/parser/redeclaration-message.js @@ -0,0 +1,10 @@ +var aVar = 56; +try { + console.log(aLet); + let aLet = 56; + // We cannot add `caught` variable on the toplevel for this testcase. + // We use assertEq here to catch non-throwing case. + assertEq(true, false); +} catch (e) { + assertEq(e.message, "can't access lexical declaration 'aLet' before initialization"); +} diff --git a/js/src/jit-test/tests/parser/redeclaration.js b/js/src/jit-test/tests/parser/redeclaration.js new file mode 100644 index 0000000000..f719021ac7 --- /dev/null +++ b/js/src/jit-test/tests/parser/redeclaration.js @@ -0,0 +1,230 @@ +// Error message for redeclaration should show the position where the variable +// was declared. + +const npos = -1; + +function test_one(fun, filename, name, + [prevLineNumber, prevColumnNumber], + [lineNumber, columnNumber]) { + let caught = false; + try { + fun(); + } catch (e) { + assertEq(e.message.includes("redeclaration"), true); + assertEq(e.lineNumber, lineNumber); + assertEq(e.columnNumber, columnNumber); + let notes = getErrorNotes(e); + if (prevLineNumber == npos) { + assertEq(notes.length, 0); + } else { + assertEq(notes.length, 1); + let note = notes[0]; + assertEq(note.message, + `Previously declared at line ${prevLineNumber}, column ${prevColumnNumber}`); + assertEq(note.lineNumber, prevLineNumber); + assertEq(note.columnNumber, prevColumnNumber); + if (filename) + assertEq(note.fileName, filename); + } + caught = true; + } + assertEq(caught, true); +} + +function test_parse(source, ...args) { + test_one(() => { + Reflect.parse(source, { source: "foo.js" }); + }, "foo.js", ...args); +} + +function test_eval(source, ...args) { + test_one(() => { + eval(source); + }, undefined, ...args); +} + +function test(...args) { + test_parse(...args); + test_eval(...args); +} + +// let + +test(` +let a, a; +`, "a", [2, 4], [2, 7]); + +test(` +let a; +let a; +`, "a", [2, 4], [3, 4]); + +test(` +let a; +const a = 1; +`, "a", [2, 4], [3, 6]); + +test(` +let a; +var a; +`, "a", [2, 4], [3, 4]); + +test(` +let a; +function a() { +} +`, "a", [2, 4], [3, 9]); + +test(` +{ + let a; + function a() { + } +} +`, "a", [3, 6], [4, 11]); + +// const + +test(` +const a = 1, a = 2; +`, "a", [2, 6], [2, 13]); + +test(` +const a = 1; +const a = 2; +`, "a", [2, 6], [3, 6]); + +test(` +const a = 1; +let a; +`, "a", [2, 6], [3, 4]); + +test(` +const a = 1; +var a; +`, "a", [2, 6], [3, 4]); + +test(` +const a = 1; +function a() { +} +`, "a", [2, 6], [3, 9]); + +test(` +{ + const a = 1; + function a() { + } +} +`, "a", [3, 8], [4, 11]); + +// var + +test(` +var a; +let a; +`, "a", [2, 4], [3, 4]); + +test(` +var a; +const a = 1; +`, "a", [2, 4], [3, 6]); + +// function + +test(` +function a() {}; +let a; +`, "a", [2, 9], [3, 4]); + +test(` +function a() {}; +const a = 1; +`, "a", [2, 9], [3, 6]); + +// Annex B lexical function + +test(` +{ + function a() {}; + let a; +} +`, "a", [3, 11], [4, 6]); + +test(` +{ + function a() {}; + const a = 1; +} +`, "a", [3, 11], [4, 8]); + +// catch parameter + +test(` +try { +} catch (a) { + let a; +} +`, "a", [3, 9], [4, 6]); + +test(` +try { +} catch (a) { + const a = 1; +} +`, "a", [3, 9], [4, 8]); + +test(` +try { +} catch (a) { + function a() { + } +} +`, "a", [3, 9], [4, 11]); + +// parameter + +test(` +function f(a) { + let a; +} +`, "a", [2, 11], [3, 6]); + +test(` +function f(a) { + const a = 1; +} +`, "a", [2, 11], [3, 8]); + +test(` +function f([a]) { + let a; +} +`, "a", [2, 12], [3, 6]); + +test(` +function f({a}) { + let a; +} +`, "a", [2, 12], [3, 6]); + +test(` +function f(...a) { + let a; +} +`, "a", [2, 14], [3, 6]); + +test(` +function f(a=1) { + let a; +} +`, "a", [2, 11], [3, 6]); + +// eval +// We don't have position information at runtime. +// No note should be shown. + +test_eval(` +let a; +eval("var a"); +`, "a", [npos, npos], [1, 4]); diff --git a/js/src/jit-test/tests/parser/regexp-after-do-while.js b/js/src/jit-test/tests/parser/regexp-after-do-while.js new file mode 100644 index 0000000000..e94f8ac24d --- /dev/null +++ b/js/src/jit-test/tests/parser/regexp-after-do-while.js @@ -0,0 +1,8 @@ +// RegExp after do-while get parsed. + +load(libdir + "asserts.js"); + +assertNoWarning(() => Function("do {} while (true) \n /bar/g"), SyntaxError, + "RegExp in next line should be parsed"); +assertNoWarning(() => Function("do {} while (true) /bar/g"), SyntaxError, + "RegExp in same line should be parsed"); diff --git a/js/src/jit-test/tests/parser/regexp-after-variable.js b/js/src/jit-test/tests/parser/regexp-after-variable.js new file mode 100644 index 0000000000..3ba2206c1f --- /dev/null +++ b/js/src/jit-test/tests/parser/regexp-after-variable.js @@ -0,0 +1,8 @@ +// RegExp after variable name get parsed or throws error correctly. + +load(libdir + "asserts.js"); + +assertNoWarning(() => Function("var foo \n /bar/g"), SyntaxError, + "RegExp in next line should be parsed"); +assertThrowsInstanceOf(() => Function("var foo /bar/g"), SyntaxError, + "RegExp in same line should be error"); diff --git a/js/src/jit-test/tests/parser/regexp-error-location.js b/js/src/jit-test/tests/parser/regexp-error-location.js new file mode 100644 index 0000000000..4f9b11e4f5 --- /dev/null +++ b/js/src/jit-test/tests/parser/regexp-error-location.js @@ -0,0 +1,16 @@ +// Check that error location for RegExp points to the actual line/column inside +// the script instead of inside the pattern. +var line, column; +try { + eval(` + + /aaa(/; +012345678; +`); +} catch (e) { + line = e.lineNumber; + column = e.columnNumber; +} + +assertEq(line, 3); +assertEq(column, 6); diff --git a/js/src/jit-test/tests/parser/script-source-extent.js b/js/src/jit-test/tests/parser/script-source-extent.js new file mode 100644 index 0000000000..db440621e9 --- /dev/null +++ b/js/src/jit-test/tests/parser/script-source-extent.js @@ -0,0 +1,337 @@ +// |jit-test| + +// Test that the sourceStart/sourceEnd values of scripts match the current +// expectations. These values are internal details and slightly arbitrary so +// these tests expectations can be updated as needed. +// +// We don't check lineno/column here since they are reasonably robustly +// determined from source start offset. + +// We use the Debugger API to introspect locate (possibly hidden) scripts and +// inspect their internal source coordinates. While we want new globals for each +// test case, they can share the same debuggee compartment. +let dbg = new Debugger(); +let debuggeeCompartment = newGlobal({newCompartment: true}); + +// Some static class field initializer lambdas may be thrown away by GC. +gczeal(0); + +function getScriptSourceExtent(source) { + // NOTE: We will _evaluate_ the source below which may introduce dynamic + // scripts which are also reported. This is intended so that we may test + // those cases too. + + let g = newGlobal({sameCompartmentAs: debuggeeCompartment}); + dbg.addDebuggee(g); + + g.evaluate(source); + + // Use Debugger.findScripts to locate scripts, including hidden ones that + // are implementation details. + let scripts = dbg.findScripts(); + + // Ignore the top-level script since it may or may not be GC'd and is + // otherwise uninteresting to us here. + scripts = scripts.filter(script => (script.sourceStart > 0) || script.isFunction); + + // Sanity-check that line/column are consistent with sourceStart. If we need + // to test multi-line sources, this will need to be updated. + for (let script of scripts) { + assertEq(script.startLine, 1); + assertEq(script.startColumn, script.sourceStart); + } + + // Map each found script to a source extent string. + function getExtentString(script) { + let start = script.sourceStart; + let end = script.sourceStart + script.sourceLength; + let length = script.sourceLength; + + let resultLength = source.length; + assertEq(start < resultLength, true); + assertEq(end <= resultLength, true); + + // The result string takes one of following forms: + // ` ^ `, when start == end. + // ` ^--^ `, typical case. + // ` ^----`, when end == resultLength. + let result = " ".repeat(start) + "^"; + if (end > start) { + result += "^".padStart(length, "-"); + } + return result.padEnd(resultLength) + .substring(0, resultLength); + } + let results = scripts.map(getExtentString); + + // Sort results since `findScripts` does not have deterministic ordering. + results.sort(); + + dbg.removeDebuggee(g); + + return results; +} + +function testSourceExtent(source, ...expectations) { + let actual = getScriptSourceExtent(source); + + // Check that strings of each array match. These should have been presorted. + assertEq(actual.length, expectations.length); + for (let i = 0; i < expectations.length; ++i) { + assertEq(actual[i], expectations[i]); + } +} + +//////////////////// + +// Function statements. +testSourceExtent(`function foo () { }`, + ` ^-----`); +testSourceExtent(`function foo (a) { }`, + ` ^------`); +testSourceExtent(`function foo (a, b) { }`, + ` ^---------`); + +// Function expressions. +testSourceExtent(`let foo = function () { }`, + ` ^-----`); +testSourceExtent(`let foo = function (a) { }`, + ` ^------`); +testSourceExtent(`let foo = function (a, b) { }`, + ` ^---------`); + +// Named function expressions. +testSourceExtent(`let foo = function bar () { }`, + ` ^-----`); +testSourceExtent(`let foo = function bar (a) { }`, + ` ^------`); +testSourceExtent(`let foo = function bar (a, b) { }`, + ` ^---------`); + +// Arrow functions. +testSourceExtent(`let foo = x => { }`, + ` ^-------`); +testSourceExtent(`let foo = x => { };`, + ` ^-------^`); +testSourceExtent(`let foo = () => { }`, + ` ^--------`); +testSourceExtent(`let foo = (a, b) => { }`, + ` ^------------`); +testSourceExtent(`let foo = x => x`, + ` ^-----`); +testSourceExtent(`let foo = () => 0`, + ` ^------`); + +// Async / Generator functions. +testSourceExtent(`function * foo () { }`, + ` ^-----`); +testSourceExtent(`async function foo () { }`, + ` ^-----`); +testSourceExtent(`async function * foo () { }`, + ` ^-----`); + +// Async arrow functions. +testSourceExtent(`let foo = async x => { }`, + ` ^-------`); +testSourceExtent(`let foo = async () => { }`, + ` ^--------`); + +// Basic inner functions. +testSourceExtent(`function foo() { function bar () {} }`, + ` ^----^ `, + ` ^------------------------`); + +// Default parameter expressions. +// NOTE: Arrow function parser back-tracking may generate multiple scripts for +// the same source text. Delazification expects these copies to have correct +// range information for `skipInnerLazyFunction` to work. If syntax parsing is +// disabled (such as for coverage builds), these extra functions are not +// generated. +if (!isLcovEnabled()) { + testSourceExtent(`function foo(a = b => c) {}`, + ` ^-----^ `, + ` ^--------------`); + testSourceExtent(`let foo = (a = (b = c => 1) => 2) => 3;`, + ` ^-----^ `, + ` ^----------------^ `, + ` ^---------------------------^`); +} + +// Object methods, getters, setters. +testSourceExtent(`let obj = { x () {} };`, + ` ^----^ `); +testSourceExtent(`let obj = { * x () {} };`, + ` ^----^ `); +testSourceExtent(`let obj = { async x () {} };`, + ` ^----^ `); +testSourceExtent(`let obj = { async * x () {} };`, + ` ^----^ `); +testSourceExtent(`let obj = { get x () {} };`, + ` ^----^ `); +testSourceExtent(`let obj = { set x (v) {} };`, + ` ^-----^ `); +testSourceExtent(`let obj = { x: function () {} };`, + ` ^----^ `); +testSourceExtent(`let obj = { x: y => z };`, + ` ^-----^ `); + +// Classes without user-defined constructors. +testSourceExtent(` class C { } `, + ` ^----------^`); +testSourceExtent(` let C = class { } `, + ` ^--------^`); +testSourceExtent(` class C { }; class D extends C { } `, + ` ^--------------------^`, + ` ^----------^ `); +testSourceExtent(` class C { }; let D = class extends C { } `, + ` ^------------------^`, + ` ^----------^ `); +testSourceExtent(`let C = class extends class { } { }`, + ` ^--------^ `, + ` ^--------------------------`); + +// Classes with user-defined constructors. +testSourceExtent(` class C { constructor() { } } `, + ` ^-----^ `); +testSourceExtent(` let C = class { constructor() { } } `, + ` ^-----^ `); +testSourceExtent(` class C { }; class D extends C { constructor() { } } `, + ` ^-----^ `, + ` ^----------^ `); +testSourceExtent(` class C { }; let D = class extends C { constructor() { } } `, + ` ^-----^ `, + ` ^----------^ `); +testSourceExtent(`let C = class extends class { } { constructor() { } }`, + ` ^-----^ `, + ` ^--------^ `); + +// Class field initializers lambdas. +// NOTE: These are an implementation detail and may be optimized away in future. +testSourceExtent(`class C { field }`, + ` ^----^ `, + `^----------------`); +testSourceExtent(`class C { field; }`, + ` ^----^ `, + `^-----------------`); +testSourceExtent(`class C { "field" }`, + ` ^------^ `, + `^------------------`); +testSourceExtent(`class C { 0 }`, + ` ^^ `, + `^------------`); +testSourceExtent(`class C { [1n] }`, + ` ^---^ `, + `^---------------`); +testSourceExtent(`class C { field = 1 }`, + ` ^--------^ `, + `^--------------------`); +testSourceExtent(`class C { "field" = 1 }`, + ` ^----------^ `, + `^----------------------`); +testSourceExtent(`class C { 0 = 1 }`, + ` ^----^ `, + `^----------------`); +testSourceExtent(`class C { [1n] = 1}`, + ` ^-------^`, + `^------------------`); + +// Static class field initializer lambdas. +// NOTE: These are an implementation detail and may be optimized away in future. +testSourceExtent(`class C { static field }`, + ` ^----^ `, + `^-----------------------`); +testSourceExtent(`class C { static field; }`, + ` ^----^ `, + `^------------------------`); +testSourceExtent(`class C { static field = 1 }`, + ` ^--------^ `, + `^---------------------------`); +testSourceExtent(`class C { static [0] = 1 }`, + ` ^------^ `, + `^-------------------------`); + +// Static class methods, getters, setters. +testSourceExtent(`class C { static mtd() {} }`, + ` ^----^ `, + `^--------------------------`); +testSourceExtent(`class C { static * mtd() {} }`, + ` ^----^ `, + `^----------------------------`); +testSourceExtent(`class C { static async mtd() {} }`, + ` ^----^ `, + `^--------------------------------`); +testSourceExtent(`class C { static async * mtd() {} }`, + ` ^----^ `, + `^----------------------------------`); +testSourceExtent(`class C { static get prop() {} }`, + ` ^----^ `, + `^-------------------------------`); +testSourceExtent(`class C { static get [0]() {} }`, + ` ^----^ `, + `^------------------------------`); +testSourceExtent(`class C { static set prop(v) {} }`, + ` ^-----^ `, + `^--------------------------------`); + +// Private class field initializer lambdas. +// NOTE: These are an implementation detail and may be optimized away in future. +testSourceExtent(`class C { #field }`, + ` ^-----^ `, + `^-----------------`); +testSourceExtent(`class C { #field = 1 }`, + ` ^---------^ `, + `^---------------------`); +testSourceExtent(`class C { static #field }`, + ` ^-----^ `, + `^------------------------`); +testSourceExtent(`class C { static #field = 1 }`, + ` ^---------^ `, + `^----------------------------`); + +// Private class methods, getters, setters. +// NOTE: These generate both a field initializer lambda and a method script. +testSourceExtent(` class C { #field() { } }`, + ` ^-----^ `, + ` ^-----------------------`); +testSourceExtent(` class C { get #field() { } }`, + ` ^-----^ `, + ` ^---------------^ `, + ` ^---------------------------`); +testSourceExtent(` class C { set #field(v) { } }`, + ` ^------^ `, + ` ^----------------^ `, + ` ^----------------------------`); +testSourceExtent(` class C { * #field() { } }`, + ` ^-----^ `, + ` ^-------------------------`); +testSourceExtent(` class C { async #field() { } }`, + ` ^-----^ `, + ` ^-----------------------------`); +testSourceExtent(` class C { async * #field() { } }`, + ` ^-----^ `, + ` ^-------------------------------`); + +// Private static class methods. +testSourceExtent(` class C { static #mtd() { } }`, + ` ^-----^ `, + ` ^----------------------------`); +testSourceExtent(` class C { static * #mtd() { } }`, + ` ^-----^ `, + ` ^------------------------------`); +testSourceExtent(` class C { static async #mtd() { } }`, + ` ^-----^ `, + ` ^----------------------------------`); +testSourceExtent(` class C { static async * #mtd() { } }`, + ` ^-----^ `, + ` ^------------------------------------`); +testSourceExtent(` class C { static get #prop() { } }`, + ` ^-----^ `, + ` ^---------------------------------`); +testSourceExtent(` class C { static set #prop(v) { } }`, + ` ^------^ `, + ` ^----------------------------------`); + +// Static Class Blocks +testSourceExtent(` class C { static { 10; } }`, + ` ^-------------^ `, + ` ^-------------------------`);
\ No newline at end of file diff --git a/js/src/jit-test/tests/parser/standalone-function-name.js b/js/src/jit-test/tests/parser/standalone-function-name.js new file mode 100644 index 0000000000..e676d7cb9c --- /dev/null +++ b/js/src/jit-test/tests/parser/standalone-function-name.js @@ -0,0 +1,22 @@ +function test(name) { + eval(` +function ${name}(stdlib, foreign, heap) { + "use asm"; + var ffi = foreign.t; + return {}; +} +${name}(15, 10); +`); +} + +test("as"); +test("async"); +test("await"); +test("each"); +test("from"); +test("get"); +test("let"); +test("of"); +test("set"); +test("static"); +test("target"); diff --git a/js/src/jit-test/tests/parser/stencil-asmjs.js b/js/src/jit-test/tests/parser/stencil-asmjs.js new file mode 100644 index 0000000000..0379fa05eb --- /dev/null +++ b/js/src/jit-test/tests/parser/stencil-asmjs.js @@ -0,0 +1,28 @@ +// |jit-test| skip-if: isLcovEnabled() + +let source = ` + var m = function() { + "use asm" + function g(){} + return g; + } + + function check() { + var objM = new m; + var g = m(); + // g is a ctor returning an primitive value, thus an empty object + assertEq(Object.getOwnPropertyNames(new g).length, 0); + } + + check() +`; + +// Check that on-demand delazification and concurrent delazification are not +// attempting to parse "use asm" functions. +const options = { + fileName: "tests/asm.js/testBug999790.js", + lineNumber: 1, + eagerDelazificationStrategy: "CheckConcurrentWithOnDemand", + newContext: true, +}; +evaluate(source, options); diff --git a/js/src/jit-test/tests/parser/stencil-compile-invalid-argument.js b/js/src/jit-test/tests/parser/stencil-compile-invalid-argument.js new file mode 100644 index 0000000000..26ed7b9eb4 --- /dev/null +++ b/js/src/jit-test/tests/parser/stencil-compile-invalid-argument.js @@ -0,0 +1,14 @@ +// Passing non-object to `options` argument of stencil testing functions should +// throw. + +load(libdir + "asserts.js"); + +const stencil = compileToStencil(""); +const xdr = compileToStencilXDR(""); + +for (const arg of [0, 1.1, "foo", true, false, null, Symbol.iterator]) { + assertThrowsInstanceOf(() => compileToStencil("", arg), Error); + assertThrowsInstanceOf(() => evalStencil(stencil, arg), Error); + assertThrowsInstanceOf(() => compileToStencilXDR("", arg), Error); + assertThrowsInstanceOf(() => evalStencilXDR(xdr, arg), Error); +} diff --git a/js/src/jit-test/tests/parser/stencil-eager-delazify-empty.js b/js/src/jit-test/tests/parser/stencil-eager-delazify-empty.js new file mode 100644 index 0000000000..3121f5491b --- /dev/null +++ b/js/src/jit-test/tests/parser/stencil-eager-delazify-empty.js @@ -0,0 +1,22 @@ +// |jit-test| skip-if: helperThreadCount() === 0 || isLcovEnabled() + +// Extra GCs can empty the StencilCache to reclaim memory. This lines +// re-configure the gc-zeal setting to prevent this from happening in this test +// case which waits for the cache to contain some entry. +if ('gczeal' in this) + gczeal(0); + +// Generate a source code with no inner functions. +function justVariables(n) { + let text = ""; + for (let i = 0; i < n; i++) { + text += `let v${i} = ${i};`; + } + return text; +}; + +// Create an extra task to test the case where there is nothing to delazify. +let job = offThreadCompileToStencil(justVariables(10000), options); + +const stencil = finishOffThreadStencil(job); +evalStencil(stencil, options); diff --git a/js/src/jit-test/tests/parser/stencil-eager-delazify.js b/js/src/jit-test/tests/parser/stencil-eager-delazify.js new file mode 100644 index 0000000000..d638b16e78 --- /dev/null +++ b/js/src/jit-test/tests/parser/stencil-eager-delazify.js @@ -0,0 +1,75 @@ +// |jit-test| skip-if: helperThreadCount() === 0 || isLcovEnabled() + +// Extra GCs can empty the StencilCache to reclaim memory. This lines +// re-configure the gc-zeal setting to prevent this from happening in this test +// case which waits for the cache to contain some entry. +if ('gczeal' in this) + gczeal(0); + +let u = 0; + +// At each function, create `width` inner functions. +let width = 2; +// Depth of inner functions. +let depth = 4; +// Number of additional parser & delazification workload running concurrently +// with the one we are attempting to measure, such that we can see differences +// in the report of `isInStencilCache`. +let load = 14; + +// Return the number of function generated by a to `depthFirstExec` given the +// same parameters. +function count(w, d) { + return (Math.pow(w, d + 1) - 1) / (w - 1); +} + +// Generate a source code with a large number of inner functions, such that +// eager delazification can be observe while running JS code concurrently. +function depthFirstExec(indent, name, w, d) { + let fun = `${indent}function ${name} (arg) {\n`; + let inner = ""; + let val = `arg + isInStencilCache(${name})`; + if (d > 0) { + for (let i = 0; i < w; i++) { + inner += depthFirstExec(`${indent} `, `${name}_${i}`, w, d - 1); + val = `${name}_${i}(${val})`; + } + } + fun += inner; + fun += `${indent} return ${u} + ${val} - ${u};\n`; + fun += `${indent}}\n`; + u += 1; + return fun; +}; + +const options = { + fileName: "depthFirstExec.js", + lineNumber: 1, + eagerDelazificationStrategy: "ConcurrentDepthFirst", +}; +let script = depthFirstExec("", "raceMe", width, depth); + +let jobs = []; +for (let i = 0; i < load; i++) { + // Spin up extra compilation workload... + jobs.push(offThreadCompileToStencil(script, options)); +} + +const stencil = finishOffThreadStencil(jobs[0]); +evalStencil(stencil, options); + +waitForStencilCache(raceMe); +let start = raceMe(0); +let mid = raceMe(0); +let end = raceMe(0); + +// The garbage collector should clear the cache and suppress all delazification +// tasks. +gc(); +let afterGc = raceMe(0); + +assertEq(1 <= start, true); +assertEq(start <= mid, true); +assertEq(mid <= end, true); +assertEq(end <= count(width, depth), true); +assertEq(afterGc, 0); diff --git a/js/src/jit-test/tests/parser/stencil-scope.js b/js/src/jit-test/tests/parser/stencil-scope.js new file mode 100644 index 0000000000..0dc562147a --- /dev/null +++ b/js/src/jit-test/tests/parser/stencil-scope.js @@ -0,0 +1,134 @@ +const optionsFull = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "ParseEverythingEagerly", +}; + +const optionsLazy = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "OnDemandOnly", +}; + +const optionsLazyCache = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "ConcurrentDepthFirst", +}; + +const optionsLazyCache2 = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "ConcurrentLargeFirst", +}; + +let result = 0; + +function testMainThread(script_str) { + const stencil = compileToStencil(script_str, optionsFull); + result = evalStencil(stencil, optionsFull); + assertEq(result, 1); +} + +function testMainThreadDelazifyAll(script_str) { + if (isLcovEnabled()) { + // Code-coverage implies forceFullParse = true, and as such it cannot be + // used while testing to incrementally delazify. + return; + } + const stencil = compileToStencil(script_str, optionsLazy); + result = evalStencil(stencil, optionsLazy); + assertEq(result, 1); +} + +function testMainThreadCacheAll(script_str) { + if (isLcovEnabled() || helperThreadCount() === 0) { + // Code-coverage implies forceFullParse = true, and as such it cannot be + // used while testing to incrementally delazify. + // Similarly, concurrent delazification requires off-threads processing. + return; + } + const stencil = compileToStencil(script_str, optionsLazyCache); + result = evalStencil(stencil, optionsLazyCache); + assertEq(result, 1); +} + +function testMainThreadCacheAll2(script_str) { + if (isLcovEnabled() || helperThreadCount() === 0) { + // Code-coverage implies forceFullParse = true, and as such it cannot be + // used while testing to incrementally delazify. + // Similarly, concurrent delazification requires off-threads processing. + return; + } + const stencil = compileToStencil(script_str, optionsLazyCache2); + result = evalStencil(stencil, optionsLazyCache2); + assertEq(result, 1); +} + +function testOffThread(script_str) { + const job = offThreadCompileToStencil(script_str, optionsFull); + const stencil = finishOffThreadStencil(job); + result = evalStencil(stencil, optionsFull); + assertEq(result, 1); +} + +// These patches are meant to wrap the inner code given as argument into one +// kind of scope. The freeVars specify one way to retrieve the variable name +// added in this process if any. +const scopeCases = [ + { code: inner => `{ ${inner} }`, freeVars: [] }, + { code: inner => `{ var v = 1; ${inner} }`, freeVars: ["v"] }, + { code: inner => `{ let l = 1; ${inner} }`, freeVars: ["l"] }, + { code: inner => `{ const c = 1; ${inner} }`, freeVars: ["c"] }, + { code: inner => `with ({ p: 1 }) { ${inner} }`, freeVars: ["p"], + inClass: false }, + { code: inner => `(a => { ${inner} })(1)`, freeVars: ["a"] }, + { code: inner => `function fun(a) { ${inner} }; fun(1)`, freeVars: ["a"], + inClass: false}, + { code: inner => `try { ${inner} } catch(unused) { }`, freeVars: [] }, + { code: inner => `try { throw 1; } catch(t) { ${inner} }`, freeVars: ["t"] }, + { code: inner => `{ class C { #m = 1; constructor() { ${inner} }}; new C() }`, + freeVars: ["this.#m"], isClass: true }, +]; + +// This function is used to generate code which mostly exercise the various kind +// of scopes to cover ScopeContext class in CompilationStencil.h +function generateCode(seed) { + let start = inner => ` + ${inner}; + result + `; + + let prog = [start]; + let freeVars = ["1"]; + let inClass = false; + + while (seed >= freeVars.length) { + let index = seed % scopeCases.length; + seed = (seed / scopeCases.length) | 0; + let scope = scopeCases[index]; + if (inClass && !(scope.inClass ?? false)) { + // Skip illegal code (non-strict) or code which might not accept + // this to work. + continue; + } + inClass ||= scope.isClass ?? false; + prog.push(scope.code); + freeVars = freeVars.concat(scope.freeVars); + } + + let name = freeVars[seed]; + return prog.reduceRight((inner, f) => f(inner), `result = ${name}`); +} + +for (let s = 0; s < 3000; s++) { + let code = generateCode(s); + // console.log(s, ":", code); + testMainThread(code); + testMainThreadDelazifyAll(code); + testMainThreadCacheAll(code); + testMainThreadCacheAll2(code); + if (helperThreadCount() > 0) { + testOffThread(code); + } +} diff --git a/js/src/jit-test/tests/parser/stencil.js b/js/src/jit-test/tests/parser/stencil.js new file mode 100644 index 0000000000..0001ebaca1 --- /dev/null +++ b/js/src/jit-test/tests/parser/stencil.js @@ -0,0 +1,111 @@ +const optionsFull = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "ParseEverythingEagerly", +}; + +const optionsLazy = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "OnDemandOnly", +}; + +const optionsLazyCache = { + fileName: "compileToStencil-DATA.js", + lineNumber: 1, + eagerDelazificationStrategy: "ConcurrentDepthFirst", +}; + +function testMainThread(script_str) { + const eval_f = eval; + const stencil = compileToStencil(script_str, optionsFull); + const result = evalStencil(stencil, optionsFull); + assertEq(result, eval_f(script_str)); +} + +function testMainThreadDelazifyAll(script_str) { + if (isLcovEnabled()) { + // Code-coverage implies forceFullParse = true, and as such it cannot be + // used while testing to incrementally delazify. + return; + } + const eval_f = eval; + const stencil = compileToStencil(script_str, optionsLazy); + const result = evalStencil(stencil, optionsLazy); + assertEq(result, eval_f(script_str)); +} + +function testMainThreadCacheAll(script_str) { + if (isLcovEnabled() || helperThreadCount() === 0) { + // Code-coverage implies forceFullParse = true, and as such it cannot be + // used while testing to incrementally delazify. + // Similarly, concurrent delazification requires off-threads processing. + return; + } + const eval_f = eval; + const stencil = compileToStencil(script_str, optionsLazyCache); + const result = evalStencil(stencil, optionsLazyCache); + assertEq(result, eval_f(script_str)); +} + +function testOffThread(script_str) { + const eval_f = eval; + const job = offThreadCompileToStencil(script_str, optionsFull); + const stencil = finishOffThreadStencil(job); + const result = evalStencil(stencil, optionsFull); + assertEq(result, eval_f(script_str)); +} + +testMainThread(` +var a = 10; +let b = 20, c = 30; +const d = 40; +function f() { + return a + b + c + d; +} +f(); +`); + +testMainThreadDelazifyAll(` +var a1 = 10; +let b1 = 20, c1 = 30; +const d1 = 40; +function g1() { + function h1() { + return a1 + b1; + } + return h1() + c1; +} +function f1() { + return a1 + b1 + c1 + d1; +} +f1(); +`); + +testMainThreadCacheAll(` +var a3 = 10; +let b3 = 20, c3 = 30; +const d3 = 40; +function g3() { + function h3() { + return a3 + b3; + } + return h3() + c3; +} +function f3() { + return a3 + b3 + c3 + d3; +} +f3(); +`); + +if (helperThreadCount() > 0) { + testOffThread(` +var a2 = 10; +let b2 = 20, c2 = 30; +const d2 = 40; +function f2() { + return a2 + b2 + c2 + d2; +} +f2(); +`); +} diff --git a/js/src/jit-test/tests/parser/strict-with-asi-and-deprecated-octal.js b/js/src/jit-test/tests/parser/strict-with-asi-and-deprecated-octal.js new file mode 100644 index 0000000000..cb09ac5849 --- /dev/null +++ b/js/src/jit-test/tests/parser/strict-with-asi-and-deprecated-octal.js @@ -0,0 +1,4 @@ +// |jit-test| error: SyntaxError +"use strict" +010 + diff --git a/js/src/jit-test/tests/parser/syntax-error-illegal-character.js b/js/src/jit-test/tests/parser/syntax-error-illegal-character.js new file mode 100644 index 0000000000..e1db1b7f3c --- /dev/null +++ b/js/src/jit-test/tests/parser/syntax-error-illegal-character.js @@ -0,0 +1,22 @@ +load(libdir + "syntax.js"); + +if (!getBuildConfiguration()['decorators']) { + function check_syntax_error_at(e, code, name) { + assertEq(e instanceof SyntaxError, true, name + ": " + code); + assertEq(e.message, "illegal character U+0040", name + ": " + code); + } + test_syntax(["@"], check_syntax_error_at, false); +} + +function check_syntax_error_ellipsis(e, code, name) { + assertEq(e instanceof SyntaxError, true, name + ": " + code); + assertEq(e.message, "illegal character U+2026", name + ": " + code); +} +test_syntax(["…"], check_syntax_error_ellipsis, false); + +function check_syntax_error_clown(e, code, name) { + assertEq(e instanceof SyntaxError, true, name + ": " + code); + assertEq(e.message, "illegal character U+1F921", name + ": " + code); +} +test_syntax(["🤡"], check_syntax_error_clown, false); + diff --git a/js/src/jit-test/tests/parser/syntax-parse-error.js b/js/src/jit-test/tests/parser/syntax-parse-error.js new file mode 100644 index 0000000000..4d13989a1e --- /dev/null +++ b/js/src/jit-test/tests/parser/syntax-parse-error.js @@ -0,0 +1,4 @@ +load(libdir + "asserts.js"); + +assertThrowsInstanceOf(() => syntaxParse(">"), SyntaxError); + diff --git a/js/src/jit-test/tests/parser/truncation.js b/js/src/jit-test/tests/parser/truncation.js new file mode 100644 index 0000000000..3cfc6e37f6 --- /dev/null +++ b/js/src/jit-test/tests/parser/truncation.js @@ -0,0 +1,73 @@ +load(libdir + "asserts.js"); + +var cases = [ + "{", + "{ ;", + "var", + "var x,", + "var x =", + "let x,", + "let x =", + "const", + "const x =", + "const x = 1,", + "if", + "if (", + "if (0) ; else", + "do", + "do ;", + "do ; while", + "do ; while (", + "do ; while (1", + "while", + "while (", + "while (1", + "while (1)", + "for", + "for (", + "for (;", + "for (;;", + "for (;;)", + "for (var", + "for (x", + "for (x in", + "for (x in y", + "for (x in y)", + "for (x of", + "for (x of y", + "for (x of y)", + "switch", + "switch (", + "switch (x", + "switch (x)", + "with", + "with (", + "with (x", + "with (x)", + "a:", + "throw", + "try", + "try {", + "try {} catch", + "try {} catch (", + "try {} catch (exc", + "try {} catch (exc if", + "try {} catch (exc if 1", + "try {} finally", + "try {} finally {", + + "function", + "function f", + "function f(", + "function f()", + "function f() {", + "(function", + "(function f", + "(function f(", + "(function f()", + +]; + +for (var s of cases) + assertThrowsInstanceOf(() => Function(s), SyntaxError); + diff --git a/js/src/jit-test/tests/parser/warning-oom.js b/js/src/jit-test/tests/parser/warning-oom.js new file mode 100644 index 0000000000..baf91cb9c9 --- /dev/null +++ b/js/src/jit-test/tests/parser/warning-oom.js @@ -0,0 +1,7 @@ +// |jit-test| skip-if: !('oomTest' in this) + +// OOM during reporting warning should be handled. + +oomTest(function(){ + new Function("return; 0;"); +}); diff --git a/js/src/jit-test/tests/parser/yield-in-formal-destructuring.js b/js/src/jit-test/tests/parser/yield-in-formal-destructuring.js new file mode 100644 index 0000000000..08e4ed5fd8 --- /dev/null +++ b/js/src/jit-test/tests/parser/yield-in-formal-destructuring.js @@ -0,0 +1 @@ +function d([{ [yield]: {} } ]) { f } |