diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jit-test/tests/class | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.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/class')
25 files changed, 829 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/class/bug1169746.js b/js/src/jit-test/tests/class/bug1169746.js new file mode 100644 index 0000000000..1e63ca48f9 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1169746.js @@ -0,0 +1,10 @@ +class C { } +class D extends C { } + +function f() +{ + for (var i = 0; i < 2000; ++i) + new D(); +} + +f(); diff --git a/js/src/jit-test/tests/class/bug1357506.js b/js/src/jit-test/tests/class/bug1357506.js new file mode 100644 index 0000000000..52a5643e62 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1357506.js @@ -0,0 +1,8 @@ +// Test that constructors that abort due to asm.js do not assert due to the +// parser keeping track of the FunctionBox corresponding to the constructor. + +class a { + constructor() { + "use asm"; + } +} diff --git a/js/src/jit-test/tests/class/bug1359622.js b/js/src/jit-test/tests/class/bug1359622.js new file mode 100644 index 0000000000..cbea4a4f7c --- /dev/null +++ b/js/src/jit-test/tests/class/bug1359622.js @@ -0,0 +1,4 @@ +var g = newGlobal({ discardSource: true }); +g.evaluate(` + unescape(class get { static staticMethod() {} }); +`); diff --git a/js/src/jit-test/tests/class/bug1473272-default-constructors.js b/js/src/jit-test/tests/class/bug1473272-default-constructors.js new file mode 100644 index 0000000000..e9bd5c1889 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1473272-default-constructors.js @@ -0,0 +1,24 @@ +// Test the source location info in a derived-class default constructor. + +function W() { test(); } +class Z extends W {} // line 4 +class Y extends Z {} // line 5 + +class X extends Y {} // line 7 + +function test() { + for (let frame of new Error().stack.split('\n')) { + function lineNumber(frame) { + return +frame.match(/(\d+):\d+$/)[1]; + } + + if (frame.startsWith("Z@")) + assertEq(lineNumber(frame), 4); + if (frame.startsWith("Y@")) + assertEq(lineNumber(frame), 5); + if (frame.startsWith("X@")) + assertEq(lineNumber(frame), 7); + } +} + +new X; diff --git a/js/src/jit-test/tests/class/bug1488385.js b/js/src/jit-test/tests/class/bug1488385.js new file mode 100644 index 0000000000..46a15c0611 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1488385.js @@ -0,0 +1,13 @@ +// Default class constructors should no longer be marked as self-hosted +// functions. They should be munged to appear in every respect as if they +// originated with the class definition. + +load(libdir + 'asserts.js'); + +function f() { + return f.caller.p; +} + +// Since default constructors are strict mode code, this should get: +// TypeError: access to strict mode caller function is censored +assertThrowsInstanceOf(() => new class extends f {}, TypeError); diff --git a/js/src/jit-test/tests/class/bug1567579.js b/js/src/jit-test/tests/class/bug1567579.js new file mode 100644 index 0000000000..240279ceda --- /dev/null +++ b/js/src/jit-test/tests/class/bug1567579.js @@ -0,0 +1,4 @@ +var res = "class { constructor() {} }"; +var test = eval("(" + res + ").toString()"); + +assertEq(test, res);
\ No newline at end of file diff --git a/js/src/jit-test/tests/class/bug1616535.js b/js/src/jit-test/tests/class/bug1616535.js new file mode 100644 index 0000000000..feeec19e65 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1616535.js @@ -0,0 +1,3 @@ +// |jit-test| error:TypeError + +class C extends (/x/) {} diff --git a/js/src/jit-test/tests/class/bug1628719.js b/js/src/jit-test/tests/class/bug1628719.js new file mode 100644 index 0000000000..76d3b97664 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1628719.js @@ -0,0 +1,28 @@ +class BaseOne { + static build() { return 'BaseOne'; } +} + +class BaseTwo { + static build() { return 'BaseTwo'; } +} + +class ClassOne extends BaseOne { + constructor() { super(); } +} + +class ClassTwo extends BaseTwo { + constructor() { super(); } +} + +const ClassMap = { 1: ClassOne, 2: ClassTwo }; +const TimeLine = [2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2]; + +function run() { + for (var i = 0; i < TimeLine.length; ++i) { + var j = TimeLine[i]; + var expected = j === 1 ? 'BaseOne' : 'BaseTwo'; + var actual = ClassMap[j].build(); + assertEq(actual, expected); + } +} +run(); diff --git a/js/src/jit-test/tests/class/checkreturn-optimized-out.js b/js/src/jit-test/tests/class/checkreturn-optimized-out.js new file mode 100644 index 0000000000..10025c9c27 --- /dev/null +++ b/js/src/jit-test/tests/class/checkreturn-optimized-out.js @@ -0,0 +1,23 @@ +function h() {} + +class Base {} + +class C extends Base { + constructor(cond) { + if (cond) { + // Never entered. + for (var i = 0; i < args.length; ++i) h(); + } + super(); + } +} + +function f() { + for (var i = 0; i < 10; i++) { + var x = new C(false); + } +} + +for (var i = 0; i < 3; i++) { + f(); +} diff --git a/js/src/jit-test/tests/class/classconstructor.js b/js/src/jit-test/tests/class/classconstructor.js new file mode 100644 index 0000000000..2d926b48ca --- /dev/null +++ b/js/src/jit-test/tests/class/classconstructor.js @@ -0,0 +1,27 @@ +function customconstructor() { + class X { + constructor() {} + a() {} + }; + + assertEq(Object.getOwnPropertyDescriptor(X, "prototype").configurable, false); + assertEq(Object.getOwnPropertyDescriptor(X.prototype, "constructor").enumerable, false); +} + +function defaultconstructor() { + class X { + a() {} + }; + + assertEq(Object.getOwnPropertyDescriptor(X, "prototype").configurable, false); + assertEq(Object.getOwnPropertyDescriptor(X.prototype, "constructor").enumerable, false); +} + +function run() { + for (var i = 0; i < 100; i++) { + customconstructor(); + defaultconstructor(); + } +} + +run(); diff --git a/js/src/jit-test/tests/class/compProp.js b/js/src/jit-test/tests/class/compProp.js new file mode 100644 index 0000000000..f98727c718 --- /dev/null +++ b/js/src/jit-test/tests/class/compProp.js @@ -0,0 +1,15 @@ +load(libdir + "asserts.js"); + +function f(tag) { return {[tag]: 1}; } +a = []; +for (var i = 0; i < 2000; i++) + a[i] = f("first"); + +for (var i = 0; i < 2000; i++) + assertEq(a[i].first, 1); + +for (var i = 0; i < 2000; i++) + a[i] = f("second"); + +for (var i = 0; i < 2000; i++) + assertEq(a[i].second, 1); diff --git a/js/src/jit-test/tests/class/default-constructor-position.js b/js/src/jit-test/tests/class/default-constructor-position.js new file mode 100644 index 0000000000..bff3bbd42d --- /dev/null +++ b/js/src/jit-test/tests/class/default-constructor-position.js @@ -0,0 +1,68 @@ +// Test default class constructors have reasonable lineno/column values + +const source = ` + /* JSOp::ClassConstructor */ class A { + } + + /* JSOp::DerivedConstructor */ class B extends A { + } + + /* GeneralParser::synthesizeConstructor */ class C { + field = "default value"; + } + + /* GeneralParser::synthesizeConstructor (derived) */ class D extends A { + field = "default value"; + } +`; + +// Use the Debugger API to introspect the line / column. +let d = new Debugger(); +let g = newGlobal({newCompartment: true}) +let gw = d.addDebuggee(g); + +g.evaluate(source); + +function getStartLine(name) { + return gw.makeDebuggeeValue(g.eval(name)).script.startLine; +} + +function getStartColumn(name) { + return gw.makeDebuggeeValue(g.eval(name)).script.startColumn; +} + +function getSourceStart(name) { + return gw.makeDebuggeeValue(g.eval(name)).script.sourceStart; +} + +function getSourceLength(name) { + return gw.makeDebuggeeValue(g.eval(name)).script.sourceLength; +} + +// Compute the expected line/column from source. +matches = ""; +lineno = 0; +for (text of source.split("\n")) { + lineno++; + + column = text.indexOf("class"); + if (column < 0) { + continue; + } + + className = text[column + 6]; + matches += className; + + // Check lineno/column. + assertEq(getStartLine(className), lineno); + assertEq(getStartColumn(className), column); + + // Check sourceStart/sourceEnd. + offset = source.indexOf("class " + className) + length = source.substring(offset).indexOf("}") + 1 + assertEq(getSourceStart(className), offset) + assertEq(getSourceLength(className), length) +} + +// Sanity check to did actual matches +assertEq(matches, "ABCD"); diff --git a/js/src/jit-test/tests/class/methDefn.js b/js/src/jit-test/tests/class/methDefn.js new file mode 100644 index 0000000000..f8a6d883a4 --- /dev/null +++ b/js/src/jit-test/tests/class/methDefn.js @@ -0,0 +1,15 @@ +load(libdir + "asserts.js"); + +function f(tag) { return {[tag](){return 1;}}; } +a = []; +for (var i = 0; i < 2000; i++) + a[i] = f("first"); + +for (var i = 0; i < 2000; i++) + assertEq(a[i].first(), 1); + +for (var i = 0; i < 2000; i++) + a[i] = f("second"); + +for (var i = 0; i < 2000; i++) + assertEq(a[i].second(), 1); diff --git a/js/src/jit-test/tests/class/regress-merge-descriptors-simple.js b/js/src/jit-test/tests/class/regress-merge-descriptors-simple.js new file mode 100644 index 0000000000..57ea9a9f3a --- /dev/null +++ b/js/src/jit-test/tests/class/regress-merge-descriptors-simple.js @@ -0,0 +1,37 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var extend = function (d, b) { + function foo() { this.constructor = d; } + foo.prototype = b.prototype; + d.prototype = new foo(); +}; + +var Car = (function (Super) { + var Car = function () {} + extend(Car, Super); +}(Object)); diff --git a/js/src/jit-test/tests/class/regress-merge-descriptors.js b/js/src/jit-test/tests/class/regress-merge-descriptors.js new file mode 100644 index 0000000000..f56adcabd2 --- /dev/null +++ b/js/src/jit-test/tests/class/regress-merge-descriptors.js @@ -0,0 +1,92 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var extend = function (d, b) { + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; + +var Car = (function (Super) { + var Car = function () { + var self = this; + + Super.call(self); + + Object.defineProperties(self, { + "make": { + enumerable: true, + configurable: true, + get: function () { + return "Ford"; + } + } + }); + + self.copy = function () { + throw new Error("Meant to be overriden"); + }; + + return self; + }; + + extend(Car, Super); + + return Car; +}(Object)); + + +var SuperCar = ((function (Super) { + var SuperCar = function (make) { + var self = this; + + Super.call(self); + + + Object.defineProperties(self, { + "make": { + enumerable: true, + configurable: true, + get: function () { + return make; + } + } + }); + + // Convert self.copy from DATA_CONSTANT to DATA. + self.copy = function () { }; + + return self; + }; + extend(SuperCar, Super); + return SuperCar; +})(Car)); + +assertEq("Ford", new Car().make); +assertEq("Bugatti", new SuperCar("Bugatti").make); +assertEq("Lambo", new SuperCar("Lambo").make); +assertEq("Shelby", new SuperCar("Shelby").make); diff --git a/js/src/jit-test/tests/class/relazify-constructor.js b/js/src/jit-test/tests/class/relazify-constructor.js new file mode 100644 index 0000000000..2066898886 --- /dev/null +++ b/js/src/jit-test/tests/class/relazify-constructor.js @@ -0,0 +1,22 @@ +class WithConstructor { + constructor() {} +} + +class DefaultConstructor { +} + +class WithConstructorDerived extends DefaultConstructor { + constructor() { + super() + } +} + +class DefaultConstructorDerived extends DefaultConstructor { +} + +relazifyFunctions(); + +let a = new WithConstructor; +let b = new DefaultConstructor; +let c = new WithConstructorDerived; +let d = new DefaultConstructorDerived; diff --git a/js/src/jit-test/tests/class/super-in-nested-eval.js b/js/src/jit-test/tests/class/super-in-nested-eval.js new file mode 100644 index 0000000000..c0f9e4fd66 --- /dev/null +++ b/js/src/jit-test/tests/class/super-in-nested-eval.js @@ -0,0 +1,34 @@ +// |jit-test| allow-overrecursed + +// Test super() and super.foo() calls in deeply nested eval. + +class C { + constructor(x) { this.x = x; } + foo() { this.x++; } +} +class D extends C { + constructor(depth) { + var d = depth; + var callsuper = 'super(depth); super.foo();'; + var s = "if (d-- > 0) { eval(s) } else { eval(callsuper); }"; + eval(s); + } +} + +const MAX_DEPTH = 252; + +// These values should work. +var depths = [0, 1, 10, 200, MAX_DEPTH]; +for (var d of depths) { + var o = new D(d); + assertEq(o.x, d + 1); +} + +// This should fail. +var ex; +try { + new D(MAX_DEPTH + 1); +} catch(e) { + ex = e; +} +assertEq(ex instanceof InternalError, true); diff --git a/js/src/jit-test/tests/class/super-this-env.js b/js/src/jit-test/tests/class/super-this-env.js new file mode 100644 index 0000000000..9faca9b745 --- /dev/null +++ b/js/src/jit-test/tests/class/super-this-env.js @@ -0,0 +1,34 @@ +for (let forceFullParse of [true, false]) { + assertEq(Object.prototype.toString, evaluate(`{ + class C extends Object { + f() { + let x = "toString"; + return () => super[x]; + } + } + + (new C).f()() + }`, { forceFullParse })); + + assertEq(Object.prototype.toString, evaluate(`{ + class C extends Object { + f() { + let x = "toString"; + return () => eval("super[x]"); + } + } + + (new C).f()() + }`, { forceFullParse })); + + assertEq(Object.prototype.toString, evaluate(`{ + class C extends Object { + f() { + let x = "toString"; + return () => eval("() => super[x]"); + } + } + + (new C).f()()() + }`, { forceFullParse })); +} diff --git a/js/src/jit-test/tests/class/superElemMegamorphic.js b/js/src/jit-test/tests/class/superElemMegamorphic.js new file mode 100644 index 0000000000..8601cc472a --- /dev/null +++ b/js/src/jit-test/tests/class/superElemMegamorphic.js @@ -0,0 +1,33 @@ +class C { }; +C.prototype.a = "a"; +C.prototype.b = "b"; +C.prototype.c = "c"; +C.prototype.d = "d"; +C.prototype.e = "e"; +C.prototype.f = "f"; +C.prototype.g = "g"; +C.prototype.h = "h"; +C.prototype.i = "i"; +C.prototype.j = "j"; +C.prototype.k = "k"; +C.prototype.l = "l"; +C.prototype.m = "m"; +C.prototype.n = "n"; +C.prototype.o = "o"; +C.prototype.p = "p"; +C.prototype.q = "q"; +C.prototype.r = "r"; + +class D extends C { + foo(p) { + return super[p]; + } +} + +var d = new D(); + +for (let i = 0; i < 20; ++i) { + for (let p in C.prototype) { + assertEq(p, d.foo(p)); + } +} diff --git a/js/src/jit-test/tests/class/superProp.js b/js/src/jit-test/tests/class/superProp.js new file mode 100644 index 0000000000..37b85ab652 --- /dev/null +++ b/js/src/jit-test/tests/class/superProp.js @@ -0,0 +1,62 @@ +var g_get_this = "get_this"; +var g_prop_this = "prop_this"; + +class Base +{ + get get_prop() { return 7; } + get get_this() { return this; } + prop_call() { return 11; } + prop_this() { return this.x; } +} +Base.prototype.prop_proto = 5; +Base.prototype.x = (-1); +Base.prototype[0] = 100; +Base.prototype[1] = 101; +Base.prototype[2] = 102; + +class Derived extends Base +{ + get get_prop() { throw "Bad"; } + get get_this() { throw "Bad"; } + prop_call() { throw "Bad"; } + prop_this() { throw "Bad"; } + + do_test_getprop() + { + this.x = 13; + + assertEq(super.prop_proto, 5); + + assertEq(super.get_prop, 7); + assertEq(super.get_this, this); + + assertEq(super.prop_call(), 11); + assertEq(super.prop_this(), 13); + } + + do_test_getelem() + { + this.x = 13; + + assertEq(super[g_get_this], this); + + assertEq(super[g_prop_this](), 13); + assertEq(super[0], 100); + assertEq(super[1], 101); + assertEq(super[2], 102); + } +} +Derived.prototype.prop_proto = (-1); +Derived.prototype.x = (-2); +Derived.prototype[0] = (-3); +Derived.prototype[1] = (-4); +Derived.prototype[2] = (-5); + +for (var i = 0; i < 20; ++i) { + let t = new Derived(); + + for (var j = 0; j < 20; ++j) { + t.do_test_getprop(); + t.do_test_getelem(); + } +} diff --git a/js/src/jit-test/tests/class/superPropMegamorphic.js b/js/src/jit-test/tests/class/superPropMegamorphic.js new file mode 100644 index 0000000000..489f6ececb --- /dev/null +++ b/js/src/jit-test/tests/class/superPropMegamorphic.js @@ -0,0 +1,42 @@ +// Test GETPROP_SUPER with megamorphic variation +const NCLASS = 20; + +var g_prop = "prop"; +var g_THIS = "THIS"; + +// Define array of base classes with a data property and a getter property. +let C = []; +for (let i = 0; i < NCLASS; ++i) { + let klass = class { + get THIS() { return this; } + }; + klass.prototype.prop = i; + + C.push(klass); +} + +// Derive class using super property access +class D extends C[0] { + get prop() { return super.prop; } + get elem() { return super[g_prop]; } + + get prop_this() { return super.THIS; } + get elem_this() { return super[g_THIS]; } +} + +let d = new D(); + +for (var j = 0; j < 4; ++j) { + for (var i = 0; i < 15; ++i) { + // Change base class by overriding [[HomeObject]].[[Prototype]] + Object.setPrototypeOf(D.prototype, C[j].prototype); + + // Check we get property of correct class + assertEq(d.prop, j); + assertEq(d.elem, j); + + // Check super getter gets |this| of object not base class + assertEq(d.prop_this, d); + assertEq(d.elem_this, d); + } +} diff --git a/js/src/jit-test/tests/class/superPropProxy.js b/js/src/jit-test/tests/class/superPropProxy.js new file mode 100644 index 0000000000..fe0e5369a4 --- /dev/null +++ b/js/src/jit-test/tests/class/superPropProxy.js @@ -0,0 +1,23 @@ +// Define constructor with a proxy as prototype +let hook = { get: function(target, name, receiver) { return receiver; } } +let Base = function() { } +Base.prototype = new Proxy(Base.prototype, hook); + +class Derived extends Base { + test() { + // Check proxy receiver is |this|, rather than Base.[[Prototype]] + assertEq(super.x, this); + } + + test_elem() { + // Check proxy receiver is |this|, rather than Base.[[Prototype]] + assertEq(super[0], this); + } +} + +let d = new Derived(); + +for (let i = 0; i < 20; ++i) { + d.test(); + d.test_elem(); +} diff --git a/js/src/jit-test/tests/class/superSetPropThrow.js b/js/src/jit-test/tests/class/superSetPropThrow.js new file mode 100644 index 0000000000..c3b16ac8af --- /dev/null +++ b/js/src/jit-test/tests/class/superSetPropThrow.js @@ -0,0 +1,64 @@ +var g_foo = "foo"; +var g_bar = "bar"; + +// Define base class with a read-only and a writable data property +class Base +{ +} +Object.defineProperty(Base.prototype, "foo", { value: "Base", writable: true }); +Object.defineProperty(Base.prototype, "bar", { value: "Base", writable: false }); + +// Test various cases that should throw during SETPROP_SUPER +class Derived extends Base +{ + // ECMA-2018 9.1.9.1, step 4.a + testReadonly() { + super.bar = "Derived"; + } + testReadonlyElem() { + super[g_bar] = "Derived"; + } + + // ECMA-2018 9.1.9.1, step 4.b + testPrimitiveReceiver() { + super.foo = "Derived"; + } + testPrimitiveReceiverElem() { + super[g_foo] = "Derived"; + } + + // ECMA-2018 9.1.9.1, step 4.d.i + testAccessorShadow() { + Object.defineProperty(this, "foo", { get: function() { } }); + super.foo = "Derived"; + } + testAccessorShadowElem() { + Object.defineProperty(this, "foo", { get: function() { } }); + super[g_foo] = "Derived"; + } + + // ECMA-2018 9.1.9.1, step 4.d.ii + testReadonlyShadow() { + Object.defineProperty(this, "foo", { writable: false }); + super.foo = "Derived"; + } + testReadonlyShadowElem() { + Object.defineProperty(this, "foo", { writable: false }); + super[g_foo] = "Derived"; + } +} + +for (let i = 0; i < 10; ++i) { + var cnt = 0; + + try { new Derived().testReadonly(); } catch(e) { cnt++; } + try { new Derived().testReadonlyElem(); } catch(e) { cnt++; } + try { Derived.prototype.testPrimitiveReceiver.call(null); } catch(e) { cnt++; } + try { Derived.prototype.testPrimitiveReceiverElem.call(null); } catch(e) { cnt++; } + try { new Derived().testAccessorShadow(); } catch(e) { cnt++; } + try { new Derived().testAccessorShadowElem(); } catch(e) { cnt++; } + try { new Derived().testReadonlyShadow(); } catch(e) { cnt++; } + try { new Derived().testReadonlyShadowElem(); } catch(e) { cnt++; } + + assertEq(cnt, 8); +} diff --git a/js/src/jit-test/tests/class/superSetProperty.js b/js/src/jit-test/tests/class/superSetProperty.js new file mode 100644 index 0000000000..6e136cb58b --- /dev/null +++ b/js/src/jit-test/tests/class/superSetProperty.js @@ -0,0 +1,67 @@ + +class Base +{ + set setter(val) { + this.set_val = val; + this.set_this = this; + } +} +Base.prototype.prop = "Base"; + +class Derived extends Base +{ + set setter(val) { super.setter = val; } + setelem(pname, val) { super[pname] = val; } +} + +// Test SETPROP_SUPER invoke setters correctly +function testSetterChain() { + let d = new Derived(); + + for (let i = 0; i < 10; ++i) + { + d.setter = i; + assertEq(d.set_val, i); + assertEq(d.set_this, d); + } +} +function testSetterChainElem() { + let d = new Derived(); + + for (let i = 0; i < 10; ++i) + { + d.setelem("setter", i); + assertEq(d.set_val, i); + assertEq(d.set_this, d); + } +} + +// Test that SETPROP_SUPER modifies |this| and not home object +function testSuperSetProp() { + let d = new Derived(); + + for (let i = 0; i < 10; ++i) + { + d.prop = i; + assertEq(d.prop, i); + assertEq(d.hasOwnProperty("prop"), true); + assertEq(Derived.prototype.prop, "Base"); + } +} +function testSuperSetPropElem() { + let d = new Derived(); + + for (let i = 0; i < 10; ++i) + { + d.setelem("prop", i); + assertEq(d.prop, i); + assertEq(d.hasOwnProperty("prop"), true); + assertEq(Derived.prototype.prop, "Base"); + } +} + +testSetterChain(); +testSetterChainElem(); + +testSuperSetProp(); +testSuperSetPropElem(); diff --git a/js/src/jit-test/tests/class/throwOnCallConstructor.js b/js/src/jit-test/tests/class/throwOnCallConstructor.js new file mode 100644 index 0000000000..2bde725702 --- /dev/null +++ b/js/src/jit-test/tests/class/throwOnCallConstructor.js @@ -0,0 +1,77 @@ +// Count constructor calls +var cnt = 0; +class Base { constructor() { ++cnt; } } + +// Force |JSFunction->hasScript()| +new Base(); +assertEq(cnt, 1); + +// Calling a ClassConstructor must throw +(function() { + function f() { Base(); } + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Spread-calling a ClassConstructor must throw +(function() { + function f() { Base(...[]); } + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Function.prototype.call must throw on ClassConstructor +(function() { + function f() { Base.call(null); } + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Function.prototype.apply must throw on ClassConstructor +(function() { + function f() { Base.apply(null, []); } + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Getter must throw if it is a ClassConstructor +(function() { + var o = {}; + Object.defineProperty(o, "prop", { get: Base }); + function f() { o.prop }; + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Setter must throw if it is a ClassConstructor +(function() { + var o = {}; + Object.defineProperty(o, "prop", { set: Base }); + function f() { o.prop = 1 }; + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Proxy apply must throw if it is a ClassConstructor +(function() { + var o = new Proxy(function() { }, { apply: Base }); + function f() { o() }; + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); + +// Proxy get must throw if it is a ClassConstructor +(function() { + var o = new Proxy({}, { get: Base }); + function f() { o.x } + try { f() } catch (e) {} + try { f() } catch (e) {} + assertEq(cnt, 1); +})(); |