summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/fields/private-field-basics.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/fields/private-field-basics.js')
-rw-r--r--js/src/jit-test/tests/fields/private-field-basics.js236
1 files changed, 236 insertions, 0 deletions
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);
+ }
+}