diff options
Diffstat (limited to 'js/src/jit-test/tests/fields')
40 files changed, 1226 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/fields/access.js b/js/src/jit-test/tests/fields/access.js new file mode 100644 index 0000000000..e24ddefaef --- /dev/null +++ b/js/src/jit-test/tests/fields/access.js @@ -0,0 +1,9 @@ +class C { + x = 5; +} + +c = new C(); +assertEq(5, c.x); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/basic.js b/js/src/jit-test/tests/fields/basic.js new file mode 100644 index 0000000000..af8d0f860c --- /dev/null +++ b/js/src/jit-test/tests/fields/basic.js @@ -0,0 +1,7 @@ +class C { + x; + y = 2; +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/bug1540787.js b/js/src/jit-test/tests/fields/bug1540787.js new file mode 100644 index 0000000000..2b57e31373 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1540787.js @@ -0,0 +1,4 @@ +class C { + x = 1; + constructor() {}; +} diff --git a/js/src/jit-test/tests/fields/bug1540789.js b/js/src/jit-test/tests/fields/bug1540789.js new file mode 100644 index 0000000000..67beb177ac --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1540789.js @@ -0,0 +1,3 @@ +class C { + y = () => this.x; +} diff --git a/js/src/jit-test/tests/fields/bug1540798.js b/js/src/jit-test/tests/fields/bug1540798.js new file mode 100644 index 0000000000..9c6b61205c --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1540798.js @@ -0,0 +1,14 @@ +try { evaluate(` +class constructor { get; } // Long line is long +// Long line XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +test(); +function test() { + try { + x; + } catch (v) { + gc(); + } +} +test(); +`); } catch(exc) {} +constructor.toString(); diff --git a/js/src/jit-test/tests/fields/bug1547129.js b/js/src/jit-test/tests/fields/bug1547129.js new file mode 100644 index 0000000000..a543d58846 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1547129.js @@ -0,0 +1,19 @@ +load(libdir + "asserts.js"); + +new class foo extends Array { + e = function() {} +} + +source = `new class bar extends Promise { e = function() {} }`; +// Calling the Promise constructor with empty args fails with TypeError. +assertThrowsInstanceOf(() => eval(source), TypeError); + +class Base { + constructor() { + return new Proxy({}, {}); + } +} + +new class prox extends Base { + e = function () {} +} diff --git a/js/src/jit-test/tests/fields/bug1547130.js b/js/src/jit-test/tests/fields/bug1547130.js new file mode 100644 index 0000000000..a87d545e62 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1547130.js @@ -0,0 +1 @@ +[ class { i32a = [ i32a ] = c27 } ] && class { c27 = [ c27 ] = c27 } diff --git a/js/src/jit-test/tests/fields/bug1547133.js b/js/src/jit-test/tests/fields/bug1547133.js new file mode 100644 index 0000000000..31e9aa48f2 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1547133.js @@ -0,0 +1,3 @@ +class C47 { + static method(s = class { [y75] = 42; }) {} +} diff --git a/js/src/jit-test/tests/fields/bug1547136.js b/js/src/jit-test/tests/fields/bug1547136.js new file mode 100644 index 0000000000..979ec0885d --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1547136.js @@ -0,0 +1 @@ +try {} catch ([ c = class { ["s"] }]) {} diff --git a/js/src/jit-test/tests/fields/bug1547467.js b/js/src/jit-test/tests/fields/bug1547467.js new file mode 100644 index 0000000000..b3578bb0fd --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1547467.js @@ -0,0 +1,17 @@ +load(libdir + "asserts.js"); + +assertThrowsInstanceOf(() => { + class foo extends null { + constructor(a = class bar extends bar {}) {} + } + new foo(); + }, + ReferenceError +) + +class B { } +class C extends B { + constructor(a = class D { [super()] = 5; }) { + } +} +new C() diff --git a/js/src/jit-test/tests/fields/bug1547915.js b/js/src/jit-test/tests/fields/bug1547915.js new file mode 100644 index 0000000000..e589ebd260 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1547915.js @@ -0,0 +1,4 @@ +load(libdir + "asserts.js"); + +source = `#_\\u200C`; +assertThrowsInstanceOf(() => eval(source), SyntaxError); diff --git a/js/src/jit-test/tests/fields/bug1551454.js b/js/src/jit-test/tests/fields/bug1551454.js new file mode 100644 index 0000000000..5bb77af46d --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1551454.js @@ -0,0 +1,12 @@ +class C { + 1 = eval(); +} +new C(); + +class D { + 1.5 = eval(); +} +new D(); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/bug1551454_2.js b/js/src/jit-test/tests/fields/bug1551454_2.js new file mode 100644 index 0000000000..ad92b36d50 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1551454_2.js @@ -0,0 +1,6 @@ +let f = 1; +class X { f=f; } +assertEq(new X().f, 1); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/bug1552022.js b/js/src/jit-test/tests/fields/bug1552022.js new file mode 100644 index 0000000000..86a0f75cf5 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1552022.js @@ -0,0 +1,22 @@ +load(libdir + "eqArrayHelper.js"); + +let expected = []; +class B { + constructor(...args) { + assertEqArray(expected, args); + } +} + +class C extends B { + asdf = 2; +} + +expected = []; +new C(); +expected = [1]; +new C(1); +expected = [1, 2]; +new C(1, 2); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/bug1552229.js b/js/src/jit-test/tests/fields/bug1552229.js new file mode 100644 index 0000000000..e9374ff057 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1552229.js @@ -0,0 +1,15 @@ +let i = 0; +function f(x) { + assertEq(++i, x); + return x; +} +class C{ + [f(1)](){} + [f(2)] = "hi"; + [f(3)](){} + [f(4)] = "hi"; +} +new C(); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/bug1552875.js b/js/src/jit-test/tests/fields/bug1552875.js new file mode 100644 index 0000000000..4e44e83945 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1552875.js @@ -0,0 +1,13 @@ +class C { + x = function(){}; + 0 = function(){}; + ["y" + 0] = function(){}; +} + +let c = new C(); +assertEq(c["x"].name, "x"); +assertEq(c[0].name, "0"); +assertEq(c["y0"].name, "y0"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/bug1555979.js b/js/src/jit-test/tests/fields/bug1555979.js new file mode 100644 index 0000000000..1612bf128d --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1555979.js @@ -0,0 +1,8 @@ +(function() { + "use asm"; + function f() { + class X { + constructor() {}; + } + } +})(); diff --git a/js/src/jit-test/tests/fields/bug1562146.js b/js/src/jit-test/tests/fields/bug1562146.js new file mode 100644 index 0000000000..74a62a00e6 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1562146.js @@ -0,0 +1,10 @@ +// |jit-test| skip-if: !('disassemble' in this) +/*********************************************************************** +************************************************************************ +*****************************************************/ +class z { + m +} +gcslice(0); +gc(); +if (typeof disassemble === 'function') +disassemble('-r'); diff --git a/js/src/jit-test/tests/fields/bug1571289.js b/js/src/jit-test/tests/fields/bug1571289.js new file mode 100644 index 0000000000..8ae8c38d36 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1571289.js @@ -0,0 +1,6 @@ +class C66 { + 0 = class { + static set name(x) {} + }; +} +new C66(); diff --git a/js/src/jit-test/tests/fields/bug1664550.js b/js/src/jit-test/tests/fields/bug1664550.js new file mode 100644 index 0000000000..8c6e98b5e0 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1664550.js @@ -0,0 +1,15 @@ +// |jit-test| --enable-private-methods; + +class OverrideBase { + constructor(o30) { + return o30; + } +}; + +class A3 extends OverrideBase { + get #m() {} +} + +var obj = {}; +Object.seal(obj); +new A3(obj); diff --git a/js/src/jit-test/tests/fields/bug1683784.js b/js/src/jit-test/tests/fields/bug1683784.js new file mode 100644 index 0000000000..02dd277cfb --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1683784.js @@ -0,0 +1,12 @@ +// |jit-test| --enable-private-methods; + +class C { + #x() { } + constructor() { this.#x = 1; } +} + +try { + new C +} catch (e) { + assertEq(e.message, "#x is read-only") +} diff --git a/js/src/jit-test/tests/fields/error.js b/js/src/jit-test/tests/fields/error.js new file mode 100644 index 0000000000..12d392425e --- /dev/null +++ b/js/src/jit-test/tests/fields/error.js @@ -0,0 +1,131 @@ +load(libdir + 'asserts.js'); + +let source = `class C { + x = +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + -2; + -2 = 2; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + x += 2; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + #2; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +// The following stop being syntax errors if private fields are +// enabled. +if (!getRealmConfiguration()['privateFields']) { + source = `class C { + #x; + }`; + assertErrorMessage(() => Function(source), SyntaxError, /./); + + source = `class C { + #y = 2; + }`; + assertErrorMessage(() => Function(source), SyntaxError, /./); +} + +source = `class C { + #["h" + "i"]; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + #"hi"; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + constructor; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + "constructor"; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + x = arguments; +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + x = super(); +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `function f() { +class C { + #"should still throw error during lazy parse"; +} +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +// TODO +// source = `#outside;`; +// assertErrorMessage(() => eval(source), SyntaxError); + +source = `class C { + x = super(); +}`; +assertErrorMessage(() => Function(source), SyntaxError, /./); + +source = `class C { + x = sper(); +}`; +eval(source); + + +// The following test cases fail to parse because ASI does not happen if the +// next token might be valid, even if it leads to a SyntaxError further down +// the road. + +source = `class C { + x = 0 + ["computedMethodName"](){} +}`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { + x = 0 + *f(){} +}`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + + +// The following test cases fail to parse because ASI doesn't happen without a +// newline. + +source = `class C { x y }`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { if var } // identifiers that look like keywords`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { x = 1 y }`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { x async f() {} }`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { x static f() {} }`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { field1 static field2 }`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +source = `class C { x get f() {} }`; +assertThrowsInstanceOf(() => Function(source), SyntaxError); + +if (typeof reportCompare === 'function') reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/field-initializer-position.js b/js/src/jit-test/tests/fields/field-initializer-position.js new file mode 100644 index 0000000000..f1c7f6f2d3 --- /dev/null +++ b/js/src/jit-test/tests/fields/field-initializer-position.js @@ -0,0 +1,52 @@ +// Test class field initializers have reasonable lineno/column values + +gczeal(0); + +// Use the Debugger API to introspect the line / column. +let d = new Debugger(); +let g = newGlobal({newCompartment: true}) +let gw = d.addDebuggee(g); + +let source = ` + let A = "A"; + let B = "B"; + + class C { + // START----v + 'field_str'; + 'field_str_with_init' = 1; + [A]; + [B] = 2; + static x; + static y = 3; + static [A + "static"]; + static [B + "static"] = 4; + // END + } +`; + +let NumInitializers = 8; + +// Compute (1-based) line number of 'START' and 'END' markers. +let START = source.split('\n').findIndex(x => x.includes("START")) + 1; +let END = source.split('\n').findIndex(x => x.includes("END")) + 1; +assertEq(END - START - 1, NumInitializers); + +// Use debugger to locate internal field-initializer scripts. +g.evaluate(source); +let scripts = d.findScripts() + .filter(script => (script.startLine >= START && + script.startLine <= END)); +scripts.sort((x, y) => (x.sourceStart - y.sourceStart)) + +for (var i = 0; i < NumInitializers; ++i) { + let script = scripts[i]; + let lineText = source.split('\n')[START + i]; + + // Check the initializer lambda has expected line/column + assertEq(script.startLine, START + 1 + i); + assertEq(script.startColumn, 20); + + // Check that source length matches expectations. + assertEq(script.startColumn + script.sourceLength + ';'.length, lineText.length); +} diff --git a/js/src/jit-test/tests/fields/field_types.js b/js/src/jit-test/tests/fields/field_types.js new file mode 100644 index 0000000000..f93991c321 --- /dev/null +++ b/js/src/jit-test/tests/fields/field_types.js @@ -0,0 +1,43 @@ +class C { + [Math.sqrt(16)]; + [Math.sqrt(8)] = 5 + 2; + "hi"; + "bye" = {}; + 2 = 2; + 0x101 = 2; + 0o101 = 2; + 0b101 = 2; + NaN = 0; // actually the field called "NaN", not the number + Infinity = 50; // actually the field called "Infinity", not the number + // all the keywords below are proper fields (?!?) + with = 0; + //static = 0; // doesn't work yet + async = 0; + get = 0; + set = 0; + export = 0; + function = 0; +} + +let obj = new C(); +assertEq(Math.sqrt(16) in obj, true); +assertEq(obj[Math.sqrt(16)], undefined); +assertEq(obj[Math.sqrt(8)], 7); +assertEq("hi" in obj, true); +assertEq(obj["hi"], undefined); +assertEq(typeof obj["bye"], "object"); +assertEq(obj[2], 2); +assertEq(obj[0x101], 2); +assertEq(obj[0o101], 2); +assertEq(obj[0b101], 2); +assertEq(obj.NaN, 0); +assertEq(obj.Infinity, 50); +assertEq(obj.with, 0); +assertEq(obj.async, 0); +assertEq(obj.get, 0); +assertEq(obj.set, 0); +assertEq(obj.export, 0); +assertEq(obj.function, 0); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/initprop.js b/js/src/jit-test/tests/fields/initprop.js new file mode 100644 index 0000000000..fd18d5a48d --- /dev/null +++ b/js/src/jit-test/tests/fields/initprop.js @@ -0,0 +1,25 @@ +let called = false +class base { + set x(arg) { + called = true; + } + get x() { + called = true; + return 0; + } +} + +class c extends base { + x = 2; +} +assertEq(new c().x, 2); + +class d extends base { + ["x"] = 2; +} +assertEq(new d().x, 2); + +assertEq(called, false); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/ion-private-idempotent.js b/js/src/jit-test/tests/fields/ion-private-idempotent.js new file mode 100644 index 0000000000..24d7c1793e --- /dev/null +++ b/js/src/jit-test/tests/fields/ion-private-idempotent.js @@ -0,0 +1,33 @@ +// |jit-test| --enable-private-fields; + +var acc = 0; +const loopCount = 100; + +class A { + #x = 1; + static loopRead(o) { + for (var i = 0; i < loopCount; i++) { + // If this getelem were hoisted out of the loop, + // we need the IC that is attached to that to + // correctly throw if .#x is not in o. + var b = o.#x; + acc += 1; + } + } +}; + +// Two non-A objects, because we're concerned not about the first +// attempt to read .#x from a non A, but the second, because if +// we attach the wrong IC, we'll attach an IC that provides +// regular object semantics, which would be to return undefined. +var array = [new A, new A, new A, {}, {}]; +for (var e of array) { + acc = 0; + try { + A.loopRead(e); + assertEq(acc, loopCount); + } catch (e) { + assertEq(e instanceof TypeError, true); + assertEq(acc, 0); + } +} diff --git a/js/src/jit-test/tests/fields/literal.js b/js/src/jit-test/tests/fields/literal.js new file mode 100644 index 0000000000..6ebb40b188 --- /dev/null +++ b/js/src/jit-test/tests/fields/literal.js @@ -0,0 +1,46 @@ +load(libdir + "asserts.js"); + +source = `var y = { + x; +}`; +assertErrorMessage(() => eval(source), SyntaxError, /./); + +// This is legal, and is equivalent to `var y = { x: x };` +// source = `var y = { +// x +// }`; +// assertThrowsInstanceOf(() => eval(source), SyntaxError); + +source = `var y = { + #x; +}`; +assertErrorMessage(() => eval(source), SyntaxError, /./); + +// Temporarily disabled due to the same reason above. +// source = `var y = { +// #x +// }`; +// assertThrowsInstanceOf(() => eval(source), SyntaxError); + +source = `var y = { + x = 2; +}`; +assertErrorMessage(() => eval(source), SyntaxError, /./); + +source = `var y = { + x = 2 +}`; +assertErrorMessage(() => eval(source), SyntaxError, /./); + +source = `var y = { + #x = 2; +}`; +assertErrorMessage(() => eval(source), SyntaxError, /./); + +source = `var y = { + #x = 2 +}`; +assertErrorMessage(() => eval(source), SyntaxError, /./); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/mixed_methods.js b/js/src/jit-test/tests/fields/mixed_methods.js new file mode 100644 index 0000000000..ae66cd9129 --- /dev/null +++ b/js/src/jit-test/tests/fields/mixed_methods.js @@ -0,0 +1,9 @@ +class C { + x; + y(){} + z = 2; + w(){}; +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/multi-line-name.js b/js/src/jit-test/tests/fields/multi-line-name.js new file mode 100644 index 0000000000..4697703a32 --- /dev/null +++ b/js/src/jit-test/tests/fields/multi-line-name.js @@ -0,0 +1,15 @@ +// Test that multi-line property names don't trip up source location asserts. + +class C { + 'line \ + continuation'; + + 'line \ + continuation with init' = 1; + + [1 + + "bar"]; + + [2 + + "baz"] = 2; +} diff --git a/js/src/jit-test/tests/fields/private-eval-in-frame.js b/js/src/jit-test/tests/fields/private-eval-in-frame.js new file mode 100644 index 0000000000..e9dea6957e --- /dev/null +++ b/js/src/jit-test/tests/fields/private-eval-in-frame.js @@ -0,0 +1,15 @@ +// |jit-test| --enable-private-fields; +load(libdir + 'asserts.js'); +load(libdir + 'evalInFrame.js'); + +class B { + #x = 12; + x = 'his'; + ef(str) { + return evalInFrame(0, str); + } +} + +var b = new B(); +assertEq(b.ef(`this.x`), 'his'); +assertEq(b.ef(`this.#x`), 12); diff --git a/js/src/jit-test/tests/fields/private-field-basics.js b/js/src/jit-test/tests/fields/private-field-basics.js new file mode 100644 index 0000000000..9b1fb2431c --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-basics.js @@ -0,0 +1,236 @@ +// |jit-test| --enable-private-fields; + + +class A { + #x = 10 + + x() { + return this.#x; + } + ix() { + this.#x++; + } + static readx(o) { + return o.#x; + } + static optionalx(o) { + return o?.#x; + } + + #y = () => 'hi'; + invoke() { + return this.#y(); + } + + static #z = 'static'; + gz() { + return A.#z; + } + + sz(o) { + A.#z = o; + } + + static sgz() { + return this.#z; + } + + static ssz(o) { + this.#z = o; + } + + static six(o) { + o.#x++; + } + + static dix(o) { + o.#x--; + } +}; + +for (var i = 0; i < 1000; i++) { + var a = new A(); + assertEq(a.x(), 10); + a.ix(); + assertEq(a.x(), 11); + assertEq(A.readx(a), 11); + assertEq(a.invoke(), 'hi'); + assertEq(a.gz(), 'static'); + assertEq(A.sgz(), 'static'); + A.ssz(i); + assertEq(A.sgz(), i); + a.sz(i + 1); + assertEq(A.sgz(), i + 1); + A.ssz('static'); // reset for next iteration! + + assertEq(A.optionalx(a), 11); + assertEq(A.optionalx(null), undefined); + try { + A.optionalx({}); // Should throw type error + assertEq(0, 1); + } catch (TypeError) { + } +} + +function assertThrows(fun, errorType) { + try { + fun(); + throw 'Expected error, but none was thrown'; + } catch (e) { + if (!(e instanceof errorType)) { + throw 'Wrong error type thrown'; + } + } +} + +function testTypeErrors(v) { + assertThrows(() => A.readx(v), TypeError); // Read value + assertThrows(() => A.six(v), TypeError); // increment + assertThrows(() => A.dix(v), TypeError); // decrement +} + +testTypeErrors(undefined); // Undefined +testTypeErrors({}); // Random object +testTypeErrors(1); // Random primitive + +assertThrows( + () => eval('class B extends class { #x; } { g() { return super.#x; } }'), + SyntaxError); // Access super.#private +assertThrows( + () => eval('class C { #x = 10; static #x = 14; }'), + SyntaxError); // Duplicate name declaration. +assertThrows( + () => eval('delete this.#x'), + SyntaxError); // deleting a private field in non-strict mode. + +class B extends class { + constructor(o) { + return o; + } +} +{ + #x = 12; + static gx(o) { + return o.#x; + } + static sx(o) { + o.#x++; + } +} + +var bn = new B(1); +var bu = new B(undefined); + +// Test we can read an outer classes private fields. +class Outer { + #outer = 3; + test() { + let outerThis = this; + class Inner { + #inner = 2; + test() { + return outerThis.#outer; + } + } + return new Inner().test(); + } +} + +var o = new Outer; +assertEq(o.test(), 3); + +// IC tests: + +var alreadyConstructedB = new B(); +assertEq(B.gx(alreadyConstructedB), 12); + +function initIC(o) { + new B(o); +} +var array = []; +// warm up init IC +for (var i = 1; i < 1000; i++) { + var newB = {}; + initIC(newB); +} + +// Successfully catch double initialization type error. +assertThrows(() => initIC(alreadyConstructedB), TypeError); +// Do it again, to make sure we didn't attach a stub that is invalid. +assertThrows(() => initIC(alreadyConstructedB), TypeError); + +// Test getters work, and ICs can't be tricked. Setup an array of +// +// [B, B, B, B, ..., {}, {}] +// +// Then test that as we execute the sudden appearance of {} doesn't +// trick our ICs into setting or getting anything -- do it twice +// to make sure that we didn't get a stub that is invalid. +var elements = []; +for (var i = 0; i < 99; i++) { + elements.push(new B); +} +elements.push({}); +elements.push({}); + +function getterCheck(e) { + assertEq(B.gx(e), 12); +} + +function setterCheck(e) { + B.sx(e); +} + +var checksPassed = 0; +try { + for (var e of elements) { + getterCheck(e); + checksPassed++; + } + throw `Shouldn't arrive here`; +} catch (e) { + if (!(e instanceof TypeError)) { + throw e; + } + // All but last element should have done the right thing. + assertEq(checksPassed, elements.length - 2); +} + +checksPassed = 0; +try { + for (var e of elements) { + setterCheck(e); + checksPassed++; + } + throw `Shouldn't arrive here`; +} catch (e) { + if (!(e instanceof TypeError)) { + throw e; + } + // All but last element should have done the right thing. + assertEq(checksPassed, elements.length - 2); +} + +// Verify setter did the thing, but throws in the correct places +for (var index in elements) { + if (index < elements.length - 2) { + assertEq(B.gx(elements[index]), 13); + } else { + assertThrows(() => { + B.gx(elements[index]); + }, TypeError); + } +} + +// Megamorphic Cache Testing: +for (var i = 0; i < 100; i++) { + var inputs = [{a: 1}, {b: 2}, {c: 3}, {d: 4}, {e: 5}, new Proxy({}, {})]; + for (var o of inputs) { + assertThrows(() => B.gx(o), TypeError); + assertThrows(() => B.sx(o), TypeError); + new B(o); + assertEq(B.gx(o), 12); + B.sx(o); + assertEq(B.gx(o), 13); + } +} diff --git a/js/src/jit-test/tests/fields/private-field-destructuring.js b/js/src/jit-test/tests/fields/private-field-destructuring.js new file mode 100644 index 0000000000..6f1aeacf94 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-destructuring.js @@ -0,0 +1,43 @@ +// |jit-test| --enable-private-fields; + +function assertThrows(fun, errorType) { + try { + fun(); + throw 'Expected error, but none was thrown'; + } catch (e) { + if (!(e instanceof errorType)) { + throw 'Wrong error type thrown'; + } + } +} + +class A { + #a; + #b; + #c; + #d; + #e; + static destructure(o, x) { + [o.#a, o.#b, o.#c, o.#d, ...o.#e] = x; + } + + static get(o) { + return {a: o.#a, b: o.#b, c: o.#c, d: o.#d, e: o.#e}; + } +}; + +for (var i = 0; i < 1000; i++) { + var a = new A(); + A.destructure(a, [1, 2, 3, 4, 5]); + var res = A.get(a); + assertEq(res.a, 1); + assertEq(res.b, 2); + assertEq(res.c, 3); + assertEq(res.d, 4); + assertEq(res.e.length, 1); + assertEq(res.e[0], 5); + + var obj = {}; + assertThrows(() => A.destructure(obj, [1, 2, 3, 4, 5]), TypeError); + assertThrows(() => A.get(obj), TypeError); +}
\ No newline at end of file diff --git a/js/src/jit-test/tests/fields/private-field-details.js b/js/src/jit-test/tests/fields/private-field-details.js new file mode 100644 index 0000000000..4d63e21d47 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-details.js @@ -0,0 +1,41 @@ +// |jit-test| --enable-private-fields; + +var shouldBeThis; + +class A { + #nullReturn = false; + constructor(nullReturn) { + this.#nullReturn = nullReturn; + } + + #calls = 0; + + #z = + () => { + assertEq(this, shouldBeThis); + this.#calls++; + + // To test the second optional below. + if (this.#nullReturn && this.#calls == 2) { + return null; + } + + return this; + } + + static chainTest(o) { + o?.#z().#z()?.#z(); + } +}; + +for (var i = 0; i < 1000; i++) { + var a = new A(); + shouldBeThis = a; + + A.chainTest(a); + A.chainTest(null); + + var b = new A(true); + shouldBeThis = b; + A.chainTest(b); +} diff --git a/js/src/jit-test/tests/fields/private-proxy-oom.js b/js/src/jit-test/tests/fields/private-proxy-oom.js new file mode 100644 index 0000000000..75e63b7864 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-proxy-oom.js @@ -0,0 +1,48 @@ +// |jit-test| skip-if: !('oomTest' in this); --enable-private-fields +// Check for proxy expando OOM issues. + +function assertThrowsTypeError(f) { + assertThrowsInstanceOf(f, TypeError); +} + + +function testing() { + var target = {}; + var p1 = new Proxy(target, {}); + var p2 = new Proxy(target, {}); + + class A extends class { + constructor(o) { + return o; + } + } + { + #field = 10; + static gf(o) { + return o.#field; + } + static sf(o) { + o.#field = 15; + } + } + + // Verify field handling on the proxy we install it on. + new A(p1); + assertEq(A.gf(p1), 10); + A.sf(p1) + assertEq(A.gf(p1), 15); + + // Should't be on the target + assertThrowsTypeError(() => A.gf(target)); + + // Can't set the field, doesn't exist + assertThrowsTypeError(() => A.sf(p2)); + + // Definitely can't get the field, doesn't exist. + assertThrowsTypeError(() => A.gf(p2)); + + // Still should't be on the target. + assertThrowsTypeError(() => A.gf(target)); +} + +oomTest(testing);
\ No newline at end of file diff --git a/js/src/jit-test/tests/fields/private-reflect-01.js b/js/src/jit-test/tests/fields/private-reflect-01.js new file mode 100644 index 0000000000..5a85cbcfd8 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-reflect-01.js @@ -0,0 +1,49 @@ +// |jit-test| --enable-private-fields; + +function rp(x) { + return Reflect.parse(x); +}; + +rp(`( + class { + static #m = 'test262'; + } + )`); + +rp(`( + class { + #m = 'test262'; + } + )`); + +rp(`( + class { + #m = 'test262'; + gm() { + this.#m++; + this.#m--; + this.#m?.x; + o[this.#m]; + return this.#m; + } + sm() { + this.#m = 12; + } + } + )`); + +rp(`( + class { + static #m = 'test262'; + static gm() { + this.#m++; + this.#m--; + this.#m?.x; + o[this.#m]; + return this.#m; + } + static sm() { + this.#m = 12; + } + } + )`); diff --git a/js/src/jit-test/tests/fields/private-throwing-initializer.js b/js/src/jit-test/tests/fields/private-throwing-initializer.js new file mode 100644 index 0000000000..ac5d94b343 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-throwing-initializer.js @@ -0,0 +1,64 @@ +// |jit-test| --enable-private-fields; + +// Ensure private fields are stamped in order and that +// we can successfully partially initialize objects. + +class Base { + constructor(o) { + return o; + } +} + +let constructorThrow = false; + +function maybeThrow() { + if (constructorThrow) { + throw 'fail' + } + return 'sometimes' +} + +class A extends Base { + constructor(o) { + super(o); + constructorThrow = !constructorThrow; + } + + #x = 'always'; + #y = maybeThrow(); + + static gx(o) { + return o.#x; + } + + static gy(o) { + return o.#y; + } +}; + +var obj1 = {}; +var obj2 = {}; + +new A(obj1); + +var threw = true; +try { + new A(obj2); + threw = false; +} catch (e) { + assertEq(e, 'fail'); +} +assertEq(threw, true); + +A.gx(obj1) +A.gx(obj2); // Both objects get x; +A.gy(obj1); // obj1 gets y + +try { + A.gy(obj2); // shouldn't have x. + threw = false; +} catch (e) { + assertEq(e instanceof TypeError, true); +} + +assertEq(threw, true); diff --git a/js/src/jit-test/tests/fields/quirks.js b/js/src/jit-test/tests/fields/quirks.js new file mode 100644 index 0000000000..4f8dfa9f75 --- /dev/null +++ b/js/src/jit-test/tests/fields/quirks.js @@ -0,0 +1,17 @@ +class C { + x;;;; + y + ; +} + +class D { + x = 5; + y = (this.x += 1) + 2; +} + +let val = new D(); +assertEq(6, val.x); +assertEq(8, val.y); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/jit-test/tests/fields/super.js b/js/src/jit-test/tests/fields/super.js new file mode 100644 index 0000000000..5031271ab2 --- /dev/null +++ b/js/src/jit-test/tests/fields/super.js @@ -0,0 +1,76 @@ +class Base { +} + +class C extends Base { + field; +} +let c = new C(); +assertEq(true, "field" in c); + +var D = class extends Base { + field; +}; +let d = new D(); +assertEq(true, "field" in d); + +class E extends Base { + field; + constructor() { + super(); + } +}; +let e = new E(); +assertEq(true, "field" in e); + +class F extends Base { + constructor() { + super(); + } + field; +}; +let f = new F(); +assertEq(true, "field" in f); + +class G extends Base { + field2 = 2; + constructor() { + super(); + } + field3 = 3; +}; +let g = new G(); +assertEq(2, g.field2); +assertEq(3, g.field3); + +class H extends Base { + field = 2; + constructor() { + eval("super()"); + } +}; +let h = new H(); +assertEq(2, h.field); + +class I extends Base { + field = 2; + constructor() { + class Tmp { + field = 10; + [super()]; + } + } +}; +let i = new I(); +assertEq(2, i.field); + +class J extends Base { + field = 2; + constructor() { + class Tmp { + field = 10; + [super()](){} + } + } +}; +let j = new J(); +assertEq(2, j.field); diff --git a/js/src/jit-test/tests/fields/superproperty.js b/js/src/jit-test/tests/fields/superproperty.js new file mode 100644 index 0000000000..406df449d6 --- /dev/null +++ b/js/src/jit-test/tests/fields/superproperty.js @@ -0,0 +1,31 @@ +// SuperProperty syntax is allowed in fields. + +class Base { + get accessor() { + return this.constructor.name; + } + method() { + return this.constructor.name; + } +} + +class Derived extends Base { + constructor() { + super(); + } + get accessor() { + throw new Error("don't call this"); + } + method() { + throw new Error("don't call this"); + } + field1 = super.accessor; + field2 = super.method(); +} + +assertEq(new Derived().field1, "Derived"); +assertEq(new Derived().field2, "Derived"); + +if (typeof reportCompare === "function") { + reportCompare(true, true); +} diff --git a/js/src/jit-test/tests/fields/transplant.js b/js/src/jit-test/tests/fields/transplant.js new file mode 100644 index 0000000000..477994912a --- /dev/null +++ b/js/src/jit-test/tests/fields/transplant.js @@ -0,0 +1,51 @@ +// |jit-test| --enable-private-fields; + + +class Base { + constructor(o) { + return o; + } +} + +class A extends Base { + #x = 10; + static gx(o) { + return o.#x + } + static sx(o, v) { + o.#x = v; + } +} + +function transplantTest(transplantOptions, global) { + var {object, transplant} = transplantableObject(transplantOptions); + + new A(object); + assertEq(A.gx(object), 10); + A.sx(object, 15); + assertEq(A.gx(object), 15); + + transplant(global); + + assertEq(A.gx(object), 15); + A.sx(object, 29); + assertEq(A.gx(object), 29); +} + +// Structure helpfully provided by bug1403679.js +const thisGlobal = this; +const otherGlobalSameCompartment = newGlobal({sameCompartmentAs: thisGlobal}); +const otherGlobalNewCompartment = newGlobal({newCompartment: true}); + +const globals = + [thisGlobal, otherGlobalSameCompartment, otherGlobalNewCompartment]; + +function testWithOptions(fn) { + for (let global of globals) { + for (let options of [{}, {proxy: true}, {object: new FakeDOMObject()}, ]) { + fn(options, global); + } + } +} + +testWithOptions(transplantTest)
\ No newline at end of file |