diff options
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.js | 257 |
1 files changed, 257 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..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); + } +} |