summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/class
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/class
parentInitial commit. (diff)
downloadfirefox-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')
-rw-r--r--js/src/jit-test/tests/class/bug1169746.js10
-rw-r--r--js/src/jit-test/tests/class/bug1357506.js8
-rw-r--r--js/src/jit-test/tests/class/bug1359622.js4
-rw-r--r--js/src/jit-test/tests/class/bug1473272-default-constructors.js24
-rw-r--r--js/src/jit-test/tests/class/bug1488385.js13
-rw-r--r--js/src/jit-test/tests/class/bug1567579.js4
-rw-r--r--js/src/jit-test/tests/class/bug1616535.js3
-rw-r--r--js/src/jit-test/tests/class/bug1628719.js28
-rw-r--r--js/src/jit-test/tests/class/checkreturn-optimized-out.js23
-rw-r--r--js/src/jit-test/tests/class/classconstructor.js27
-rw-r--r--js/src/jit-test/tests/class/compProp.js15
-rw-r--r--js/src/jit-test/tests/class/default-constructor-position.js68
-rw-r--r--js/src/jit-test/tests/class/methDefn.js15
-rw-r--r--js/src/jit-test/tests/class/regress-merge-descriptors-simple.js37
-rw-r--r--js/src/jit-test/tests/class/regress-merge-descriptors.js92
-rw-r--r--js/src/jit-test/tests/class/relazify-constructor.js22
-rw-r--r--js/src/jit-test/tests/class/super-in-nested-eval.js34
-rw-r--r--js/src/jit-test/tests/class/super-this-env.js34
-rw-r--r--js/src/jit-test/tests/class/superElemMegamorphic.js33
-rw-r--r--js/src/jit-test/tests/class/superProp.js62
-rw-r--r--js/src/jit-test/tests/class/superPropMegamorphic.js42
-rw-r--r--js/src/jit-test/tests/class/superPropProxy.js23
-rw-r--r--js/src/jit-test/tests/class/superSetPropThrow.js64
-rw-r--r--js/src/jit-test/tests/class/superSetProperty.js67
-rw-r--r--js/src/jit-test/tests/class/throwOnCallConstructor.js77
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);
+})();