diff options
Diffstat (limited to '')
52 files changed, 1741 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..57c0836594 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1664550.js @@ -0,0 +1,13 @@ +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..c496bd0e5b --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1683784.js @@ -0,0 +1,10 @@ +class C { + #x() { } + constructor() { this.#x = 1; } +} + +try { + new C +} catch (e) { + assertEq(e.message, "cannot assign to private method"); +} diff --git a/js/src/jit-test/tests/fields/bug1702420.js b/js/src/jit-test/tests/fields/bug1702420.js new file mode 100644 index 0000000000..9212911448 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1702420.js @@ -0,0 +1,11 @@ +// |jit-test| --more-compartments + +a = newGlobal() +b = a.Debugger(this) +function c() { + b.getNewestFrame().eval("") +} +c() +d = class { + #e +}
\ No newline at end of file diff --git a/js/src/jit-test/tests/fields/bug1702423.js b/js/src/jit-test/tests/fields/bug1702423.js new file mode 100644 index 0000000000..fe9ab49910 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1702423.js @@ -0,0 +1,6 @@ +// Bug 1702423 + +for (let a of []); +b = class { + static [1] // Computed field name 1, no initializer. +} diff --git a/js/src/jit-test/tests/fields/bug1702424.js b/js/src/jit-test/tests/fields/bug1702424.js new file mode 100644 index 0000000000..34136cad94 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1702424.js @@ -0,0 +1,249 @@ +load(libdir + "asserts.js"); + +// Ensure BytecodeGeneration respects stack depth assertions: Private Methods +class a { + b + // original test case below. + #c() { + d.#c ^= 'x' + } + + // Operator list: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators + // + // Compound Assignments + t() { + d.#c = 'x'; + d.#c += 'x'; + d.#c -= 'x'; + d.#c *= 'x'; + d.#c /= 'x'; + d.#c %= 'x'; + d.#c **= 'x'; + d.#c <<= 'x'; + d.#c >>= 'x'; + d.#c >>>= 'x'; + + d.#c &= 'x'; + d.#c ^= 'x'; + d.#c |= 'x'; + + } + + // Compound Logical Assignments + e() { + d.#c &&= 'x'; + d.#c ??= 'x'; + d.#c ||= 'x'; + } + + // Destructruring assignment. + ds() { + [d.#c, b] = [1, 2]; + } + + // Increment/Decrement + incDec() { + d.#c++; + d.#c--; + ++d.#c; + --d.#c; + } +} + +class b { + b + // original test case below. + #c = 10; + + // Operator list: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators + // + // Compound Assignments + t() { + d.#c = 'x'; + d.#c += 'x'; + d.#c -= 'x'; + d.#c *= 'x'; + d.#c /= 'x'; + d.#c %= 'x'; + d.#c **= 'x'; + d.#c <<= 'x'; + d.#c >>= 'x'; + d.#c >>>= 'x'; + + d.#c &= 'x'; + d.#c ^= 'x'; + d.#c |= 'x'; + + } + + // Compound Logical Assignments + e() { + d.#c &&= 'x'; + d.#c ??= 'x'; + d.#c ||= 'x'; + } + + // Destructruring assignment. + ds() { + [d.#c, b] = [1, 2]; + } + + + // Increment/Decrement + incDec() { + d.#c++; + d.#c--; + ++d.#c; + --d.#c; + } +} + +// Ensure we correctly throw for all compound private method assignments +class LiveTest { + #c() { } + + test(lambdas) { + for (let func of lambdas) { + assertThrowsInstanceOf(() => func(this), Error); + } + } + + // Operator list: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators + // + // Compound Assignments + compound() { + let tests = [ + (d) => d.#c = 'x', + (d) => d.#c += 'x', + (d) => d.#c -= 'x', + (d) => d.#c *= 'x', + (d) => d.#c /= 'x', + (d) => d.#c %= 'x', + (d) => d.#c **= 'x', + (d) => d.#c <<= 'x', + (d) => d.#c >>= 'x', + (d) => d.#c >>>= 'x', + (d) => d.#c &= 'x', + (d) => d.#c ^= 'x', + (d) => d.#c |= 'x', + ]; + + this.test(tests); + } + + // Compound Logical Assignments + compoundLogical() { + let tests = [ + (d) => d.#c &&= 'x', + ] + this.test(tests); + // These don't throw because they don't + // process the assignment. + this.#c ??= 'x'; + this.#c ||= 'x'; + } + + // Destructruring assignment. + destructuring() { + let tests = [ + (d) => [d.#c, b] = [1, 2], + ] + this.test(tests); + } + + + // Increment/Decrement + incDec() { + let tests = [ + (d) => d.#c++, + (d) => d.#c--, + (d) => ++d.#c, + (d) => --d.#c, + ]; + this.test(tests); + } +} + +var l = new LiveTest; +l.compound(); +l.compoundLogical(); +l.destructuring(); +l.incDec(); + +// Ensure we correctly throw for all compound private method assignments +class LiveTestField { + #c = 0; + + // Operator list: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators + // + // Compound Assignments + compound() { + assertEq(this.#c = 1, 1); + assertEq(this.#c += 1, 2); + assertEq(this.#c -= 1, 1); + assertEq(this.#c *= 2, 2); + assertEq(this.#c /= 2, 1); + assertEq(this.#c %= 1, 0); + this.#c = 1; + assertEq(this.#c **= 1, 1); + assertEq(this.#c <<= 1, 2); + assertEq(this.#c >>= 1, 1); + assertEq(this.#c >>>= 1, 0); + assertEq(this.#c &= 2, 0); + assertEq(this.#c ^= 2, 2); + assertEq(this.#c |= 1, 3); + } + + // Compound Logical Assignments + compoundLogical() { + this.#c = undefined; + this.#c ||= 10; + assertEq(this.#c, 10); + this.#c ||= 15; + assertEq(this.#c, 10); + + this.#c = false; + this.#c &&= 10; + assertEq(this.#c, false); + this.#c = 10; + this.#c &&= 15; + assertEq(this.#c, 15); + + this.#c = null; + this.#c ??= 10; + assertEq(this.#c, 10); + + this.#c ??= 15 + assertEq(this.#c, 10); + } + + // Destructruring assignment. + destructuring() { + [this.#c, b] = [1, 2]; + + assertEq(this.#c, 1); + } + + + // Increment/Decrement + incDec() { + this.#c = 0; + assertEq(++this.#c, 1); + assertEq(--this.#c, 0); + this.#c++; + assertEq(this.#c, 1); + this.#c--; + assertEq(this.#c, 0); + + } +} + +var k = new LiveTestField; +k.compound(); +k.compoundLogical() +k.destructuring() +k.incDec();
\ No newline at end of file diff --git a/js/src/jit-test/tests/fields/bug1703782.js b/js/src/jit-test/tests/fields/bug1703782.js new file mode 100644 index 0000000000..20ef1a3586 --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1703782.js @@ -0,0 +1,11 @@ +// Bug 1703782 - Assertion failure: this->is<T>(), at vm/JSObject.h:467 +var g7 = newGlobal({ newCompartment: true }); +g7.parent = this; +g7.eval(` + Debugger(parent).onEnterFrame = function(frame) { + let v = frame.environment.getVariable('var0'); + }; +`); +class C144252 { + static #x; +} diff --git a/js/src/jit-test/tests/fields/bug1706923.js b/js/src/jit-test/tests/fields/bug1706923.js new file mode 100644 index 0000000000..0d0c855efe --- /dev/null +++ b/js/src/jit-test/tests/fields/bug1706923.js @@ -0,0 +1,28 @@ +var error = undefined; +try { + eval(`class a { + static #x() { } + [b.#x] + }`); +} catch (e) { + error = e; +} + +assertEq(error instanceof ReferenceError, true); + +var error = undefined; +try { + eval(`class Base {}; + + class B extends Base { + static #x() { } + [Base.#x] = 1; + constructor() { + super(); + } + }`); +} catch (e) { + error = e; +} + +assertEq(error instanceof TypeError, true); diff --git a/js/src/jit-test/tests/fields/ergonomic-1.js b/js/src/jit-test/tests/fields/ergonomic-1.js new file mode 100644 index 0000000000..7aa75ab30b --- /dev/null +++ b/js/src/jit-test/tests/fields/ergonomic-1.js @@ -0,0 +1,69 @@ +class Base { + constructor(o) { + return o; + } +} + +class A extends Base { + #x = 12; + #y = 13; + static has(o) { + return A.evalStr(o, '#x in o'); + } + + static evalStr(o, str) { + return eval(str); + } +} + +var obj = {}; +assertEq(A.has(obj), false); +new A(obj); +assertEq(A.has(obj), true); + +A.evalStr(obj, `#x in o in o`) // 'false' in o + +function assertSyntaxError(functionText) { + let threw = false; + let exception = undefined; + try { + A.evalStr({}, functionText) + } catch (e) { + exception = e; + threw = true; + } + assertEq(threw, true); + assertEq(exception instanceof SyntaxError, true); +} + +assertSyntaxError(`#x`); +assertSyntaxError(`#x == undefined`); +assertSyntaxError(`1 + #x in o`) +assertSyntaxError(`#z in o`); + +assertSyntaxError(`for (#x in o) { return 1;}`) +assertSyntaxError(`!#x in o`) +assertSyntaxError(`+#x in o`) +assertSyntaxError(`-#x in o`) +assertSyntaxError(`~#x in o`) +assertSyntaxError(`void #x in o`) +assertSyntaxError(`typeof #x in o`) +assertSyntaxError(`++#x in o`) +assertSyntaxError(`--#x in o`) + +assertSyntaxError(`#x in #y in o`) +assertSyntaxError(`{} instanceof #x in o`) +assertSyntaxError(`10 > #x in o`) +var threw = true +try { + eval(`class Async { + #x; + async func(o) { + await #x in o; + } + }`); + threw = false; +} catch (e) { + assertEq(e instanceof SyntaxError, true); +} +assertEq(threw, true); 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..4c164b2bbc --- /dev/null +++ b/js/src/jit-test/tests/fields/error.js @@ -0,0 +1,116 @@ +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, /./); + +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, /./); + +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..139735d62d --- /dev/null +++ b/js/src/jit-test/tests/fields/ion-private-idempotent.js @@ -0,0 +1,31 @@ +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..d8b46bd0a9 --- /dev/null +++ b/js/src/jit-test/tests/fields/literal.js @@ -0,0 +1,45 @@ +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, /./); + +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-error-location.js b/js/src/jit-test/tests/fields/private-error-location.js new file mode 100644 index 0000000000..7c784c6fb9 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-error-location.js @@ -0,0 +1,10 @@ +// Bug 1770609 - Ensure the line number reported is correctly the source of the +// syntax error, not just the first observation of the name. +try { + eval(`class A { #declared; } + m.#declared;`) +} catch (e) { + assertEq(e instanceof SyntaxError, true) + assertEq(e.lineNumber, 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..b0f2591e98 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-eval-in-frame.js @@ -0,0 +1,14 @@ +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);
\ No newline at end of file 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..b138190607 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-basics.js @@ -0,0 +1,257 @@ +class A { + #x = 10 + + x() { + return this.#x; + } + ix() { + this.#x++; + } + static readx(o) { + return o.#x; + } + static optionalx(o) { + return o?.#x; + } + + static orEqual(o, v) { + o.#x ||= v; + return o.#x; + } + + setX(v) { + this.#x = v; + } + + compoundInc() { + this.#x += 1; + return this.#x; + } + + compoundDec() { + this.#x -= 1; + return this.#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.compoundInc(), 12); + assertEq(A.orEqual(a, 13), 12); + a.setX(null); + assertEq(A.orEqual(a, 12), 12); + assertEq(a.compoundDec(), 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..82aa032a8c --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-destructuring.js @@ -0,0 +1,41 @@ +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..1d746c33c8 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-details.js @@ -0,0 +1,39 @@ +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-field-error-messages.js b/js/src/jit-test/tests/fields/private-field-error-messages.js new file mode 100644 index 0000000000..4f7bfe0ae2 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-error-messages.js @@ -0,0 +1,39 @@ +load(libdir + "asserts.js"); + +class C { + #f = 1; + static test() { + assertTypeErrorMessage( + () => [].#f, + "can't access private field or method: object is not the right class" + ); + assertTypeErrorMessage( + () => "ok".#f, + "can't access private field or method: object is not the right class" + ); + assertTypeErrorMessage( + () => { [].#f = 3; }, + "can't set private field: object is not the right class" + ); + assertTypeErrorMessage( + () => { [].#f += 3; }, + "can't set private field: object is not the right class" + ); + assertTypeErrorMessage( + () => { [].#f++; }, + "can't set private field: object is not the right class" + ); + + assertTypeErrorMessage( + () => "".#f, + "can't access private field or method: object is not the right class" + ); + assertTypeErrorMessage( + () => { "".#f = 3; }, + "can't set private field: object is not the right class" + ); + } +} + +C.test(); + diff --git a/js/src/jit-test/tests/fields/private-field-symbol-debugger-access.js b/js/src/jit-test/tests/fields/private-field-symbol-debugger-access.js new file mode 100644 index 0000000000..cd960a3be1 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-field-symbol-debugger-access.js @@ -0,0 +1,37 @@ +// Make a new global to debug +const global = newGlobal({ newCompartment: true }); + +// Create an object in that global with a private field. +global.eval("\nclass MyClass {\n #privateProperty1\n }\nobj = new MyClass();"); + +// Debug said global. +const debug = Debugger(); +const globalDebugObject = debug.addDebuggee(global); + +// Leak the private name symbol backing the private field. +var otherGlobalObj = globalDebugObject.getOwnPropertyDescriptor("obj").value +var privateSymbol = otherGlobalObj.getOwnPrivateProperties()[0] + +// Create a different proxy. +var p = new Proxy({}, {}); + +// Try to look up the leaked private symbol on the new proxy. +// This crashes, as it violates the assumption baked into the proxy code +// that all accesses are scripted, and thus creation and symbol management +// invariants are correctly observed. +fail = false; +try { + p[privateSymbol] = 1; + fail = true; +} catch (e) { + assertEq(e instanceof TypeError, true); +} +assertEq(fail, false); + +try { + p[privateSymbol]; + fail = true; +} catch (e) { + assertEq(e instanceof TypeError, true); +} +assertEq(fail, false); diff --git a/js/src/jit-test/tests/fields/private-method-static.js b/js/src/jit-test/tests/fields/private-method-static.js new file mode 100644 index 0000000000..17b5f1e130 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-method-static.js @@ -0,0 +1,28 @@ + +class B { + static #smethod() { + return 14; + } + + static f() { + return this.#smethod(); + } +} +assertEq(B.f(), 14); + + + +class OuterStatic { + static #outerMethod() { return "ok"; } + + static test() { + class Inner { + #innerMethod() { } + static test(outer) { + return outer.#outerMethod(); + } + } + return Inner.test(this); + } +} +assertEq(OuterStatic.test(), "ok");
\ No newline at end of file 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..dd5200d9a6 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-proxy-oom.js @@ -0,0 +1,48 @@ +// |jit-test| skip-if: !('oomTest' in this); +// 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..79d5b95b83 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-reflect-01.js @@ -0,0 +1,56 @@ +function rp(x) { + return Reflect.parse(x); +}; + +rp(`( + class { + static #m = 'test262'; + } + )`); + +rp(`( + class { + static #m = 'test262'; + constructor() { + #m in {}; + } + } +)`); + +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-right-side-1.js b/js/src/jit-test/tests/fields/private-right-side-1.js new file mode 100644 index 0000000000..5be84db09d --- /dev/null +++ b/js/src/jit-test/tests/fields/private-right-side-1.js @@ -0,0 +1,18 @@ +let hit = false; + +function f() { + hit = true; +} + +class C { + #f = 1; + static m(x) { + x.#f = f(); // f() should be called before the brand check for x.#f + } +} + +try { + C.m({}); // throws a TypeError +} catch { } + +assertEq(hit, true); diff --git a/js/src/jit-test/tests/fields/private-right-side-2.js b/js/src/jit-test/tests/fields/private-right-side-2.js new file mode 100644 index 0000000000..08958ff303 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-right-side-2.js @@ -0,0 +1,13 @@ +class B { + constructor(obj) { return obj; } +} + +class C extends B { + #f = 1; + static m(obj) { + obj.#f = new C(obj); // ok, obj.#f brand check happens after RHS is evaluated + assertEq(obj.#f, obj); + } +} + +C.m({}); 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..b3e67d6cd6 --- /dev/null +++ b/js/src/jit-test/tests/fields/private-throwing-initializer.js @@ -0,0 +1,62 @@ +// 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..1c21281017 --- /dev/null +++ b/js/src/jit-test/tests/fields/transplant.js @@ -0,0 +1,48 @@ +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 |