summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/class
diff options
context:
space:
mode:
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.js16
-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/bug1645835.js18
-rw-r--r--js/src/jit-test/tests/class/bug1709328.js18
-rw-r--r--js/src/jit-test/tests/class/bug1715318.js18
-rw-r--r--js/src/jit-test/tests/class/bug1720032-1.js29
-rw-r--r--js/src/jit-test/tests/class/bug1720032-2.js27
-rw-r--r--js/src/jit-test/tests/class/bug1720032-3.js27
-rw-r--r--js/src/jit-test/tests/class/bug1727281.js4
-rw-r--r--js/src/jit-test/tests/class/checkreturn-catch-return-finally-super-arrow.js22
-rw-r--r--js/src/jit-test/tests/class/checkreturn-catch-return-finally-super.js20
-rw-r--r--js/src/jit-test/tests/class/checkreturn-catch-return.js21
-rw-r--r--js/src/jit-test/tests/class/checkreturn-catch-super-arrow.js21
-rw-r--r--js/src/jit-test/tests/class/checkreturn-catch-super.js19
-rw-r--r--js/src/jit-test/tests/class/checkreturn-finally-super-arrow.js20
-rw-r--r--js/src/jit-test/tests/class/checkreturn-finally-super.js18
-rw-r--r--js/src/jit-test/tests/class/checkreturn-for-condition.js68
-rw-r--r--js/src/jit-test/tests/class/checkreturn-for-of-arrow.js29
-rw-r--r--js/src/jit-test/tests/class/checkreturn-for-of.js27
-rw-r--r--js/src/jit-test/tests/class/checkreturn-for.js68
-rw-r--r--js/src/jit-test/tests/class/checkreturn-optimized-out.js23
-rw-r--r--js/src/jit-test/tests/class/checkreturn-source-location.js19
-rw-r--r--js/src/jit-test/tests/class/checkreturn-while.js68
-rw-r--r--js/src/jit-test/tests/class/class-static-01.js172
-rw-r--r--js/src/jit-test/tests/class/class-static-02.js10
-rw-r--r--js/src/jit-test/tests/class/class-static-03.js15
-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-base-is-null-get-elem.js12
-rw-r--r--js/src/jit-test/tests/class/super-base-is-null-get-prop.js12
-rw-r--r--js/src/jit-test/tests/class/super-base-is-null-set-elem.js12
-rw-r--r--js/src/jit-test/tests/class/super-base-is-null-set-prop.js12
-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/this-check-after-scalar-replacement-in-derived-class-constructor.js29
-rw-r--r--js/src/jit-test/tests/class/throwOnCallConstructor.js77
53 files changed, 1672 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..2e6f54ef38
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1357506.js
@@ -0,0 +1,16 @@
+// 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";
+ }
+}
+
+function f() {
+ 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/bug1645835.js b/js/src/jit-test/tests/class/bug1645835.js
new file mode 100644
index 0000000000..3a66d94eec
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1645835.js
@@ -0,0 +1,18 @@
+function Base() {
+ // Creates MNewObject, which is recoverable. An instruction which has the
+ // |RecoveredOnBailout| flag set mustn't have any live uses.
+ return {};
+}
+
+class C extends Base {
+ constructor() {
+ // |super()| assigns to |this|. The |this| slot mustn't be optimised away
+ // in case the debugger tries to read that slot.
+ super();
+ }
+}
+
+for (var i = 0; i < 100; i++) {
+ // The returned object is not used, so it can be optimised away.
+ new C();
+}
diff --git a/js/src/jit-test/tests/class/bug1709328.js b/js/src/jit-test/tests/class/bug1709328.js
new file mode 100644
index 0000000000..9ad856a5e4
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1709328.js
@@ -0,0 +1,18 @@
+class A0 { constructor() { this.dummy = true; } }
+class A1 { constructor() { this.dummy = true; } }
+class A2 { constructor() { this.dummy = true; } }
+class A3 { constructor() { this.dummy = true; } }
+class A4 { constructor() { this.dummy = true; } }
+class A5 { constructor() { this.dummy = true; } }
+class A6 { constructor() { this.dummy = true; } }
+class A7 { constructor() { this.dummy = true; } }
+class A8 { constructor() { this.dummy = true; } }
+class A9 { constructor() { this.dummy = true; } }
+
+var constructors = [A1, A2, A3, A4, A5, A6, A7, A8, A9];
+for (var i = 0; i < 1000; i++) {
+ for (var construct of constructors) {
+ var h = new construct();
+ assertEq(Reflect.get(h, "nonexistent", "dummy"), undefined);
+ }
+}
diff --git a/js/src/jit-test/tests/class/bug1715318.js b/js/src/jit-test/tests/class/bug1715318.js
new file mode 100644
index 0000000000..6513cfeb8a
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1715318.js
@@ -0,0 +1,18 @@
+// |jit-test| --no-threads; --fast-warmup
+function f() {
+ // A non-constructor with a null .prototype.
+ let arrow = _ => null;
+ arrow.prototype = null;
+
+ // Warm up.
+ for (var i = 0; i < 100; i++) {}
+
+ try {
+ class C1 extends arrow {}
+ throw "Fail";
+ } catch (e) {
+ assertEq(e instanceof TypeError, true);
+ }
+}
+f();
+f();
diff --git a/js/src/jit-test/tests/class/bug1720032-1.js b/js/src/jit-test/tests/class/bug1720032-1.js
new file mode 100644
index 0000000000..c2ab722638
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1720032-1.js
@@ -0,0 +1,29 @@
+// |jit-test| skip-if: getBuildConfiguration()['osx'] && getBuildConfiguration()['arm64']
+load(libdir + "asserts.js");
+function main() {
+ class Base {}
+
+ class Derived extends Base {
+ constructor() {
+ super();
+
+ let v = 0xffff;
+
+ try {
+ // Ensure this statement doesn't get DCE'ed.
+ v &= 0xff;
+
+ // Returning a primitive value throws.
+ return 0;
+ } catch {}
+
+ assertEq(v, 255);
+ }
+ }
+
+ for (let i = 0; i < 15; i++) {
+ assertThrowsInstanceOf(() => new Derived(), TypeError);
+ }
+}
+main();
+main();
diff --git a/js/src/jit-test/tests/class/bug1720032-2.js b/js/src/jit-test/tests/class/bug1720032-2.js
new file mode 100644
index 0000000000..7ca7a8df06
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1720032-2.js
@@ -0,0 +1,27 @@
+function main() {
+ class Base {}
+
+ class Derived extends Base {
+ constructor() {
+ let v = 0xffff;
+
+ try {
+ // Ensure this statement doesn't get DCE'ed.
+ v &= 0xff;
+
+ // Accessing |this| throws when |super()| wasn't yet called.
+ this;
+ } catch {}
+
+ assertEq(v, 255);
+
+ super();
+ }
+ }
+
+ for (let i = 0; i < 15; i++) {
+ new Derived();
+ }
+}
+main();
+main();
diff --git a/js/src/jit-test/tests/class/bug1720032-3.js b/js/src/jit-test/tests/class/bug1720032-3.js
new file mode 100644
index 0000000000..e087e8e0f8
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1720032-3.js
@@ -0,0 +1,27 @@
+function main() {
+ class Base {}
+
+ class Derived extends Base {
+ constructor() {
+ super();
+
+ let v = 0xffff;
+
+ try {
+ // Ensure this statement doesn't get DCE'ed.
+ v &= 0xff;
+
+ // Calling |super()| twice throws an error.
+ super();
+ } catch {}
+
+ assertEq(v, 255);
+ }
+ }
+
+ for (let i = 0; i < 15; i++) {
+ new Derived();
+ }
+}
+main();
+main();
diff --git a/js/src/jit-test/tests/class/bug1727281.js b/js/src/jit-test/tests/class/bug1727281.js
new file mode 100644
index 0000000000..e17bec8612
--- /dev/null
+++ b/js/src/jit-test/tests/class/bug1727281.js
@@ -0,0 +1,4 @@
+// No assertion.
+var a = {
+ 0: class { #$() {} }
+};
diff --git a/js/src/jit-test/tests/class/checkreturn-catch-return-finally-super-arrow.js b/js/src/jit-test/tests/class/checkreturn-catch-return-finally-super-arrow.js
new file mode 100644
index 0000000000..4a9d22955a
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-catch-return-finally-super-arrow.js
@@ -0,0 +1,22 @@
+class C extends class {} {
+ constructor() {
+ var f = () => super();
+
+ try {
+ throw null;
+ } catch {
+ return;
+ } finally {
+ f();
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-catch-return-finally-super.js b/js/src/jit-test/tests/class/checkreturn-catch-return-finally-super.js
new file mode 100644
index 0000000000..534d8e3046
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-catch-return-finally-super.js
@@ -0,0 +1,20 @@
+class C extends class {} {
+ constructor() {
+ try {
+ throw null;
+ } catch {
+ return;
+ } finally {
+ super();
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-catch-return.js b/js/src/jit-test/tests/class/checkreturn-catch-return.js
new file mode 100644
index 0000000000..9794dc23b1
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-catch-return.js
@@ -0,0 +1,21 @@
+load(libdir + "asserts.js");
+
+class C extends class {} {
+ constructor() {
+ super();
+
+ try {
+ return 0;
+ } catch {
+ return;
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-catch-super-arrow.js b/js/src/jit-test/tests/class/checkreturn-catch-super-arrow.js
new file mode 100644
index 0000000000..0645c51e23
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-catch-super-arrow.js
@@ -0,0 +1,21 @@
+load(libdir + "asserts.js");
+
+class C extends class {} {
+ constructor() {
+ var f = () => super();
+
+ try {
+ return 0;
+ } catch {
+ f();
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-catch-super.js b/js/src/jit-test/tests/class/checkreturn-catch-super.js
new file mode 100644
index 0000000000..e06270a527
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-catch-super.js
@@ -0,0 +1,19 @@
+load(libdir + "asserts.js");
+
+class C extends class {} {
+ constructor() {
+ try {
+ return 0;
+ } catch {
+ super();
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-finally-super-arrow.js b/js/src/jit-test/tests/class/checkreturn-finally-super-arrow.js
new file mode 100644
index 0000000000..91d43a3507
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-finally-super-arrow.js
@@ -0,0 +1,20 @@
+class C extends class {} {
+ constructor() {
+ var f = () => super();
+
+ try {
+ return;
+ } finally {
+ f();
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-finally-super.js b/js/src/jit-test/tests/class/checkreturn-finally-super.js
new file mode 100644
index 0000000000..805b9af50f
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-finally-super.js
@@ -0,0 +1,18 @@
+class C extends class {} {
+ constructor() {
+ try {
+ return;
+ } finally {
+ super();
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-for-condition.js b/js/src/jit-test/tests/class/checkreturn-for-condition.js
new file mode 100644
index 0000000000..e654056a15
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-for-condition.js
@@ -0,0 +1,68 @@
+load(libdir + "asserts.js");
+
+function testReturn() {
+ class C extends class {} {
+ constructor(n) {
+ for (let i = 0; i < n; ++i) {
+ return;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(1), ReferenceError);
+ }
+}
+testReturn();
+
+function testReturnSuper() {
+ class C extends class {} {
+ constructor(n) {
+ super();
+ for (let i = 0; i < n; ++i) {
+ return;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C(1);
+ }
+}
+testReturnSuper();
+
+function testReturnPrimitive() {
+ class C extends class {} {
+ constructor(n) {
+ for (let i = 0; i < n; ++i) {
+ return 0;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(1), TypeError);
+ }
+}
+testReturnPrimitive();
+
+function testReturnPrimitiveSuper() {
+ class C extends class {} {
+ constructor(n) {
+ super();
+ for (let i = 0; i < n; ++i) {
+ return 0;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(1), TypeError);
+ }
+}
+testReturnPrimitiveSuper();
diff --git a/js/src/jit-test/tests/class/checkreturn-for-of-arrow.js b/js/src/jit-test/tests/class/checkreturn-for-of-arrow.js
new file mode 100644
index 0000000000..4358bb1778
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-for-of-arrow.js
@@ -0,0 +1,29 @@
+var iter = {
+ [Symbol.iterator]() { return this; },
+ next() { return {done: false}; },
+ return() {
+ // Calls |super()|.
+ this.f();
+
+ return {done: true};
+ },
+};
+
+class C extends class {} {
+ constructor() {
+ iter.f = () => super();
+
+ for (var k of iter) {
+ return;
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-for-of.js b/js/src/jit-test/tests/class/checkreturn-for-of.js
new file mode 100644
index 0000000000..2c06fd4ea0
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-for-of.js
@@ -0,0 +1,27 @@
+load(libdir + "asserts.js");
+
+var error = {};
+
+var iter = {
+ [Symbol.iterator]() { return this; },
+ next() { return {done: false}; },
+ return() { throw error; },
+};
+
+class C extends class {} {
+ constructor() {
+ super();
+
+ for (var k of iter) {
+ return 0;
+ }
+ }
+}
+
+function test() {
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsValue(() => new C(), error);
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/class/checkreturn-for.js b/js/src/jit-test/tests/class/checkreturn-for.js
new file mode 100644
index 0000000000..c1efd30540
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-for.js
@@ -0,0 +1,68 @@
+load(libdir + "asserts.js");
+
+function testReturn() {
+ class C extends class {} {
+ constructor() {
+ for (;;) {
+ return;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), ReferenceError);
+ }
+}
+testReturn();
+
+function testReturnSuper() {
+ class C extends class {} {
+ constructor() {
+ super();
+ for (;;) {
+ return;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+testReturnSuper();
+
+function testReturnPrimitive() {
+ class C extends class {} {
+ constructor() {
+ for (;;) {
+ return 0;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+testReturnPrimitive();
+
+function testReturnPrimitiveSuper() {
+ class C extends class {} {
+ constructor() {
+ super();
+ for (;;) {
+ return 0;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+testReturnPrimitiveSuper();
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/checkreturn-source-location.js b/js/src/jit-test/tests/class/checkreturn-source-location.js
new file mode 100644
index 0000000000..3bdc83c36d
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-source-location.js
@@ -0,0 +1,19 @@
+// Test source location for missing-super-call check at the end of a derived class constructor.
+class A {};
+class B extends A {
+ constructor(x) {
+ if (x === null) {
+ throw "fail";
+ }
+ }
+};
+let ex;
+try {
+ new B();
+} catch (e) {
+ ex = e;
+}
+assertEq(ex instanceof ReferenceError, true);
+// The closing '}' of B's constructor.
+assertEq(ex.lineNumber, 8);
+assertEq(ex.columnNumber, 5);
diff --git a/js/src/jit-test/tests/class/checkreturn-while.js b/js/src/jit-test/tests/class/checkreturn-while.js
new file mode 100644
index 0000000000..426e7effdc
--- /dev/null
+++ b/js/src/jit-test/tests/class/checkreturn-while.js
@@ -0,0 +1,68 @@
+load(libdir + "asserts.js");
+
+function testReturn() {
+ class C extends class {} {
+ constructor() {
+ while (true) {
+ return;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), ReferenceError);
+ }
+}
+testReturn();
+
+function testReturnSuper() {
+ class C extends class {} {
+ constructor() {
+ super();
+ while (true) {
+ return;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ // No error.
+ new C();
+ }
+}
+testReturnSuper();
+
+function testReturnPrimitive() {
+ class C extends class {} {
+ constructor() {
+ while (true) {
+ return 0;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+testReturnPrimitive();
+
+function testReturnPrimitiveSuper() {
+ class C extends class {} {
+ constructor() {
+ super();
+ while (true) {
+ return 0;
+ }
+ assertEq(true, false, "unreachable");
+ }
+ }
+
+ for (var i = 0; i < 100; ++i) {
+ assertThrowsInstanceOf(() => new C(), TypeError);
+ }
+}
+testReturnPrimitiveSuper();
diff --git a/js/src/jit-test/tests/class/class-static-01.js b/js/src/jit-test/tests/class/class-static-01.js
new file mode 100644
index 0000000000..ee41def1fb
--- /dev/null
+++ b/js/src/jit-test/tests/class/class-static-01.js
@@ -0,0 +1,172 @@
+// |jit-test|
+load(libdir + "asserts.js");
+
+// Parse
+class A {
+ static { }
+};
+
+// Run
+var ran = false;
+class B {
+ static {
+ ran = true;
+ }
+};
+
+assertEq(ran, true);
+
+// Can access static assigned before.
+var res;
+class C {
+ static x = 10;
+ static {
+ res = this.x;
+ }
+};
+
+assertEq(res, 10);
+
+// Multiple static blocks
+class D {
+ static { }
+ static { }
+};
+
+class D1 {
+ static { } static { }
+};
+
+// Blocks run in order.
+class E {
+ static {
+ res = 10;
+ }
+ static {
+ assertEq(res, 10);
+ res = 14;
+ }
+}
+
+assertEq(res, 14);
+
+
+// Can use static to access private state.
+let accessor;
+class F {
+ #x = 10
+ static {
+ accessor = (o) => o.#x;
+ }
+}
+
+let f = new F;
+assertEq(accessor(f), 10);
+
+class G {
+ static {
+ this.a = 10;
+ }
+}
+assertEq(G.a, 10);
+
+// Can use the super-keyword to access a static method in super class.
+class H {
+ static a() { return 101; }
+}
+
+class I extends H {
+ static {
+ res = super.a();
+ }
+}
+
+assertEq(res, 101);
+
+// Can add a property to a class from within a static
+class J {
+ static {
+ this.x = 12;
+ }
+}
+
+assertEq(J.x, 12);
+
+
+function assertThrowsSyntaxError(str) {
+ assertThrowsInstanceOf(() => eval(str), SyntaxError); // Direct Eval
+ assertThrowsInstanceOf(() => (1, eval)(str), SyntaxError); // Indirect Eval
+ assertThrowsInstanceOf(() => Function(str), SyntaxError); // Function
+}
+
+assertThrowsSyntaxError(`
+class X {
+ static {
+ arguments;
+ }
+}
+`)
+
+
+assertThrowsSyntaxError(`
+class X extends class {} {
+ static {
+ super(); // can't call super in a static block
+ }
+}
+`)
+
+assertThrowsSyntaxError(`
+class X {
+ static {
+ return 10; // Can't return in a static block
+ }
+}
+`)
+
+assertThrowsSyntaxError(`
+class X {
+ static {
+ await 10; // Can't await in a static block
+ }
+}
+`)
+
+// Can't await inside a static block, even if we're inside an async function.
+//
+// The error message here is not good `SyntaxError: await is a reserved identifier`,
+// but can be fixed later. s
+assertThrowsSyntaxError(`
+async function f() {
+ class X {
+ static {
+ await 10; // Can't await in a static block
+ }
+ }
+}
+`)
+
+
+assertThrowsSyntaxError(`
+class X {
+ static {
+ yield 10; // Can't yield in a static block
+ }
+}
+`)
+
+
+assertThrowsSyntaxError(`
+function* gen() {
+ class X {
+ static {
+ yield 10; // Can't yield in a static block, even inside a generator
+ }
+ }
+}
+`)
+
+// Incomplete should throw a sensible error.
+assertThrowsSyntaxError(`
+class A { static { this.x
+`) \ No newline at end of file
diff --git a/js/src/jit-test/tests/class/class-static-02.js b/js/src/jit-test/tests/class/class-static-02.js
new file mode 100644
index 0000000000..e096ec86d1
--- /dev/null
+++ b/js/src/jit-test/tests/class/class-static-02.js
@@ -0,0 +1,10 @@
+// |jit-test|
+
+Reflect.parse(`class A {
+ static { print('hi'); }
+}`)
+
+Reflect.parse(`class A {
+ static x = 10;
+ static { this.x++ }
+}`); \ No newline at end of file
diff --git a/js/src/jit-test/tests/class/class-static-03.js b/js/src/jit-test/tests/class/class-static-03.js
new file mode 100644
index 0000000000..816e63d923
--- /dev/null
+++ b/js/src/jit-test/tests/class/class-static-03.js
@@ -0,0 +1,15 @@
+// |jit-test|
+
+var g = newGlobal({ newCompartment: true });
+var dbg = new Debugger;
+var gw = dbg.addDebuggee(g);
+
+dbg.onDebuggerStatement = function (frame) {
+ var e = frame.eval("this.y = 13");
+ return undefined;
+};
+
+g.eval("class A { static x = 10; static { debugger; } }; a = A;");
+assertEq(g.a.x, 10);
+assertEq(g.a.y, 13);
+
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..abe2eeb7ab
--- /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 = `
+ /* GeneralParser::synthesizeConstructor */ class A {
+ }
+
+ /* GeneralParser::synthesizeConstructor (derived) */ 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-base-is-null-get-elem.js b/js/src/jit-test/tests/class/super-base-is-null-get-elem.js
new file mode 100644
index 0000000000..3bb052af54
--- /dev/null
+++ b/js/src/jit-test/tests/class/super-base-is-null-get-elem.js
@@ -0,0 +1,12 @@
+class NullProto {
+ static m(key) {
+ try {
+ return super[key];
+ } catch {}
+ }
+}
+Object.setPrototypeOf(NullProto, null);
+
+for (var i = 0; i < 100; ++i) {
+ NullProto.m(i);
+}
diff --git a/js/src/jit-test/tests/class/super-base-is-null-get-prop.js b/js/src/jit-test/tests/class/super-base-is-null-get-prop.js
new file mode 100644
index 0000000000..eff5a290ee
--- /dev/null
+++ b/js/src/jit-test/tests/class/super-base-is-null-get-prop.js
@@ -0,0 +1,12 @@
+class NullProto {
+ static m() {
+ try {
+ return super.p;
+ } catch {}
+ }
+}
+Object.setPrototypeOf(NullProto, null);
+
+for (var i = 0; i < 100; ++i) {
+ NullProto.m();
+}
diff --git a/js/src/jit-test/tests/class/super-base-is-null-set-elem.js b/js/src/jit-test/tests/class/super-base-is-null-set-elem.js
new file mode 100644
index 0000000000..226760f9db
--- /dev/null
+++ b/js/src/jit-test/tests/class/super-base-is-null-set-elem.js
@@ -0,0 +1,12 @@
+class NullProto {
+ static m(key) {
+ try {
+ super[key] = 0;
+ } catch {}
+ }
+}
+Object.setPrototypeOf(NullProto, null);
+
+for (var i = 0; i < 100; ++i) {
+ NullProto.m(i);
+}
diff --git a/js/src/jit-test/tests/class/super-base-is-null-set-prop.js b/js/src/jit-test/tests/class/super-base-is-null-set-prop.js
new file mode 100644
index 0000000000..a3b734eef2
--- /dev/null
+++ b/js/src/jit-test/tests/class/super-base-is-null-set-prop.js
@@ -0,0 +1,12 @@
+class NullProto {
+ static m() {
+ try {
+ super.p = 0;
+ } catch {}
+ }
+}
+Object.setPrototypeOf(NullProto, null);
+
+for (var i = 0; i < 100; ++i) {
+ NullProto.m();
+}
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..8786de4ba7
--- /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 = "var q; if (d-- > 0) { eval(s) } else { eval(callsuper); }";
+ eval(s);
+ }
+}
+
+const MAX_DEPTH = 250;
+
+// 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/this-check-after-scalar-replacement-in-derived-class-constructor.js b/js/src/jit-test/tests/class/this-check-after-scalar-replacement-in-derived-class-constructor.js
new file mode 100644
index 0000000000..257e723f05
--- /dev/null
+++ b/js/src/jit-test/tests/class/this-check-after-scalar-replacement-in-derived-class-constructor.js
@@ -0,0 +1,29 @@
+// Create a derived class with a default class constructor.
+class C extends class {} {}
+
+// The default constructor of a derived class is small enough to be inlinable.
+assertEq(isSmallFunction(C), true);
+
+// Bound functions have a configurable "prototype" property.
+const BF = function(){}.bind();
+
+function testBoundFunction() {
+ for (let i = 0; i <= 1000; ++i) {
+ let newTarget = i < 1000 ? C : BF;
+ Reflect.construct(C, [], newTarget);
+ }
+}
+
+for (let i = 0; i < 2; ++i) testBoundFunction();
+
+// Proxy have a configurable "prototype" property.
+const P = new Proxy(function(){}, {});
+
+function testProxy() {
+ for (let i = 0; i <= 1000; ++i) {
+ let newTarget = i < 1000 ? C : P;
+ Reflect.construct(C, [], newTarget);
+ }
+}
+
+for (let i = 0; i < 2; ++i) testProxy();
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);
+})();