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