summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/fields
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/fields')
-rw-r--r--js/src/jit-test/tests/fields/access.js9
-rw-r--r--js/src/jit-test/tests/fields/basic.js7
-rw-r--r--js/src/jit-test/tests/fields/bug1540787.js4
-rw-r--r--js/src/jit-test/tests/fields/bug1540789.js3
-rw-r--r--js/src/jit-test/tests/fields/bug1540798.js14
-rw-r--r--js/src/jit-test/tests/fields/bug1547129.js19
-rw-r--r--js/src/jit-test/tests/fields/bug1547130.js1
-rw-r--r--js/src/jit-test/tests/fields/bug1547133.js3
-rw-r--r--js/src/jit-test/tests/fields/bug1547136.js1
-rw-r--r--js/src/jit-test/tests/fields/bug1547467.js17
-rw-r--r--js/src/jit-test/tests/fields/bug1547915.js4
-rw-r--r--js/src/jit-test/tests/fields/bug1551454.js12
-rw-r--r--js/src/jit-test/tests/fields/bug1551454_2.js6
-rw-r--r--js/src/jit-test/tests/fields/bug1552022.js22
-rw-r--r--js/src/jit-test/tests/fields/bug1552229.js15
-rw-r--r--js/src/jit-test/tests/fields/bug1552875.js13
-rw-r--r--js/src/jit-test/tests/fields/bug1555979.js8
-rw-r--r--js/src/jit-test/tests/fields/bug1562146.js10
-rw-r--r--js/src/jit-test/tests/fields/bug1571289.js6
-rw-r--r--js/src/jit-test/tests/fields/bug1664550.js13
-rw-r--r--js/src/jit-test/tests/fields/bug1683784.js10
-rw-r--r--js/src/jit-test/tests/fields/bug1702420.js11
-rw-r--r--js/src/jit-test/tests/fields/bug1702423.js6
-rw-r--r--js/src/jit-test/tests/fields/bug1702424.js249
-rw-r--r--js/src/jit-test/tests/fields/bug1703782.js11
-rw-r--r--js/src/jit-test/tests/fields/bug1706923.js28
-rw-r--r--js/src/jit-test/tests/fields/ergonomic-1.js69
-rw-r--r--js/src/jit-test/tests/fields/error.js116
-rw-r--r--js/src/jit-test/tests/fields/field-initializer-position.js52
-rw-r--r--js/src/jit-test/tests/fields/field_types.js43
-rw-r--r--js/src/jit-test/tests/fields/initprop.js25
-rw-r--r--js/src/jit-test/tests/fields/ion-private-idempotent.js31
-rw-r--r--js/src/jit-test/tests/fields/literal.js45
-rw-r--r--js/src/jit-test/tests/fields/mixed_methods.js9
-rw-r--r--js/src/jit-test/tests/fields/multi-line-name.js15
-rw-r--r--js/src/jit-test/tests/fields/private-error-location.js10
-rw-r--r--js/src/jit-test/tests/fields/private-eval-in-frame.js14
-rw-r--r--js/src/jit-test/tests/fields/private-field-basics.js257
-rw-r--r--js/src/jit-test/tests/fields/private-field-destructuring.js41
-rw-r--r--js/src/jit-test/tests/fields/private-field-details.js39
-rw-r--r--js/src/jit-test/tests/fields/private-field-error-messages.js39
-rw-r--r--js/src/jit-test/tests/fields/private-field-symbol-debugger-access.js37
-rw-r--r--js/src/jit-test/tests/fields/private-method-static.js28
-rw-r--r--js/src/jit-test/tests/fields/private-proxy-oom.js48
-rw-r--r--js/src/jit-test/tests/fields/private-reflect-01.js56
-rw-r--r--js/src/jit-test/tests/fields/private-right-side-1.js18
-rw-r--r--js/src/jit-test/tests/fields/private-right-side-2.js13
-rw-r--r--js/src/jit-test/tests/fields/private-throwing-initializer.js62
-rw-r--r--js/src/jit-test/tests/fields/quirks.js17
-rw-r--r--js/src/jit-test/tests/fields/super.js76
-rw-r--r--js/src/jit-test/tests/fields/superproperty.js31
-rw-r--r--js/src/jit-test/tests/fields/transplant.js48
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..7944642f28
--- /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, 21);
+
+ // Check that source length matches expectations.
+ assertEq(script.startColumn + script.sourceLength + ';'.length, lineText.length + 1);
+}
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