ES6 classes: When a class extends B, super() invokes B.prototype.constructor() instead of B()
https://bugs.webkit.org/show_bug.cgi?id=149001
Reviewed by Saam Barati.
Source/JavaScriptCore:
This patch matches the `super()` call in the constructor to the latest spec.
Before this patch, when calling `super()`, it loads `callee.[[HomeObject]].__proto__.constructor`
as a super constructor. But after this patch, it loads `callee.__proto__` as a super constructor.
This behavior corresponds to the section 12.3.5.2[1].
[1]: http://www.ecma-international.org/ecma-262/6.0/#sec-getsuperconstructor
* bytecompiler/NodesCodegen.cpp:
(JSC::SuperNode::emitBytecode):
* tests/stress/super-call-does-not-look-up-constructor.js: Added.
(shouldBe):
(B):
(C):
(B.prototype):
LayoutTests:
An error message becomes changed.
* js/class-syntax-call-expected.txt:
* js/class-syntax-extends-expected.txt:
* js/class-syntax-super-expected.txt:
* js/script-tests/class-syntax-call.js:
* js/script-tests/class-syntax-extends.js:
* js/script-tests/class-syntax-super.js:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@190847 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 11bad1e..a42eefe 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,19 @@
+2015-10-11 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ ES6 classes: When a class extends B, super() invokes B.prototype.constructor() instead of B()
+ https://bugs.webkit.org/show_bug.cgi?id=149001
+
+ Reviewed by Saam Barati.
+
+ An error message becomes changed.
+
+ * js/class-syntax-call-expected.txt:
+ * js/class-syntax-extends-expected.txt:
+ * js/class-syntax-super-expected.txt:
+ * js/script-tests/class-syntax-call.js:
+ * js/script-tests/class-syntax-extends.js:
+ * js/script-tests/class-syntax-super.js:
+
2015-10-10 Antti Koivisto <antti@apple.com>
Rewrite HTMLDetailsElement using HTMLSlotElement
diff --git a/LayoutTests/js/class-syntax-call-expected.txt b/LayoutTests/js/class-syntax-call-expected.txt
index 78704f3..4a8850a 100644
--- a/LayoutTests/js/class-syntax-call-expected.txt
+++ b/LayoutTests/js/class-syntax-call-expected.txt
@@ -9,7 +9,7 @@
PASS B():::"TypeError: Cannot call a class constructor"
PASS new (class { constructor() {} })()
PASS (class { constructor() {} })():::"TypeError: Cannot call a class constructor"
-PASS new (class extends null { constructor() { super() } })():::"TypeError: undefined is not an object (evaluating 'super()')"
+PASS new (class extends null { constructor() { super() } })():::"TypeError: function is not a constructor (evaluating 'super()')"
PASS (class extends null { constructor() { super() } })():::"TypeError: Cannot call a class constructor"
PASS successfullyParsed is true
diff --git a/LayoutTests/js/class-syntax-extends-expected.txt b/LayoutTests/js/class-syntax-extends-expected.txt
index 690ca39..d1b2ada 100644
--- a/LayoutTests/js/class-syntax-extends-expected.txt
+++ b/LayoutTests/js/class-syntax-extends-expected.txt
@@ -58,7 +58,7 @@
PASS x = undefined; new (class extends x { constructor () { super(); } }):::TypeError: The superclass is not an object.
PASS class x {}; new (class extends null { constructor () { return new x; } }) instanceof x
PASS new (class extends null { constructor () { this; } }):::ReferenceError: Cannot access uninitialized variable.
-PASS new (class extends null { constructor () { super(); } }):::TypeError: undefined is not an object (evaluating 'super()')
+PASS new (class extends null { constructor () { super(); } }):::TypeError: function is not a constructor (evaluating 'super()')
PASS x = {}; new (class extends null { constructor () { return x } }):::x
PASS y = 12; new (class extends null { constructor () { return y; } }):::TypeError: Cannot return a non-object type in the constructor of a derived class.
PASS class x {}; new (class extends null { constructor () { return new x; } }) instanceof x
diff --git a/LayoutTests/js/class-syntax-super-expected.txt b/LayoutTests/js/class-syntax-super-expected.txt
index 76b5b0b..f28c9ba 100644
--- a/LayoutTests/js/class-syntax-super-expected.txt
+++ b/LayoutTests/js/class-syntax-super-expected.txt
@@ -29,12 +29,12 @@
PASS new (class extends Base { constructor() { } }):::ReferenceError: Cannot access uninitialized variable.
PASS new (class extends Base { constructor() { return 1; } }):::TypeError: Cannot return a non-object type in the constructor of a derived class.
PASS new (class extends null { constructor() { return undefined } }):::ReferenceError: Cannot access uninitialized variable.
-PASS new (class extends null { constructor() { super(); return undefined } }):::TypeError: undefined is not an object (evaluating 'super()')
+PASS new (class extends null { constructor() { super(); return undefined } }):::TypeError: function is not a constructor (evaluating 'super()')
PASS x = { }; new (class extends null { constructor() { return x } });:::x
PASS x instanceof Object
PASS new (class extends null { constructor() { } }):::ReferenceError: Cannot access uninitialized variable.
PASS new (class extends null { constructor() { return 1; } }):::TypeError: Cannot return a non-object type in the constructor of a derived class.
-PASS new (class extends null { constructor() { super() } }):::TypeError: undefined is not an object (evaluating 'super()')
+PASS new (class extends null { constructor() { super() } }):::TypeError: function is not a constructor (evaluating 'super()')
PASS new (class { constructor() { super() } }):::SyntaxError: Cannot call super() in a base class constructor.
PASS function x() { super(); }:::SyntaxError: Cannot call super() outside of a class constructor.
PASS new (class extends Object { constructor() { function x() { super() } } }):::SyntaxError: Cannot call super() outside of a class constructor.
diff --git a/LayoutTests/js/script-tests/class-syntax-call.js b/LayoutTests/js/script-tests/class-syntax-call.js
index 87c4acb..668b008 100644
--- a/LayoutTests/js/script-tests/class-syntax-call.js
+++ b/LayoutTests/js/script-tests/class-syntax-call.js
@@ -37,7 +37,7 @@
shouldThrow('B()', '"TypeError: Cannot call a class constructor"');
shouldNotThrow('new (class { constructor() {} })()');
shouldThrow('(class { constructor() {} })()', '"TypeError: Cannot call a class constructor"');
-shouldThrow('new (class extends null { constructor() { super() } })()', '"TypeError: undefined is not an object (evaluating \'super()\')"');
+shouldThrow('new (class extends null { constructor() { super() } })()', '"TypeError: function is not a constructor (evaluating \'super()\')"');
shouldThrow('(class extends null { constructor() { super() } })()', '"TypeError: Cannot call a class constructor"');
var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/class-syntax-extends.js b/LayoutTests/js/script-tests/class-syntax-extends.js
index fb10830..2d649ac 100644
--- a/LayoutTests/js/script-tests/class-syntax-extends.js
+++ b/LayoutTests/js/script-tests/class-syntax-extends.js
@@ -116,7 +116,7 @@
shouldThrow('x = undefined; new (class extends x { constructor () { super(); } })', '"TypeError: The superclass is not an object."');
shouldBeTrue ('class x {}; new (class extends null { constructor () { return new x; } }) instanceof x');
shouldThrow('new (class extends null { constructor () { this; } })', '"ReferenceError: Cannot access uninitialized variable."');
-shouldThrow('new (class extends null { constructor () { super(); } })', '"TypeError: undefined is not an object (evaluating \'super()\')"');
+shouldThrow('new (class extends null { constructor () { super(); } })', '"TypeError: function is not a constructor (evaluating \'super()\')"');
shouldBe('x = {}; new (class extends null { constructor () { return x } })', 'x');
shouldThrow('y = 12; new (class extends null { constructor () { return y; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."');
shouldBeTrue ('class x {}; new (class extends null { constructor () { return new x; } }) instanceof x');
diff --git a/LayoutTests/js/script-tests/class-syntax-super.js b/LayoutTests/js/script-tests/class-syntax-super.js
index 2256c50..08823f6 100644
--- a/LayoutTests/js/script-tests/class-syntax-super.js
+++ b/LayoutTests/js/script-tests/class-syntax-super.js
@@ -103,12 +103,12 @@
shouldThrow('new (class extends Base { constructor() { } })', '"ReferenceError: Cannot access uninitialized variable."');
shouldThrow('new (class extends Base { constructor() { return 1; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."');
shouldThrow('new (class extends null { constructor() { return undefined } })');
-shouldThrow('new (class extends null { constructor() { super(); return undefined } })', '"TypeError: undefined is not an object (evaluating \'super()\')"');
+shouldThrow('new (class extends null { constructor() { super(); return undefined } })', '"TypeError: function is not a constructor (evaluating \'super()\')"');
shouldBe('x = { }; new (class extends null { constructor() { return x } });', 'x');
shouldBeTrue('x instanceof Object');
shouldThrow('new (class extends null { constructor() { } })', '"ReferenceError: Cannot access uninitialized variable."');
shouldThrow('new (class extends null { constructor() { return 1; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."');
-shouldThrow('new (class extends null { constructor() { super() } })', '"TypeError: undefined is not an object (evaluating \'super()\')"');
+shouldThrow('new (class extends null { constructor() { super() } })', '"TypeError: function is not a constructor (evaluating \'super()\')"');
shouldThrow('new (class { constructor() { super() } })', '"SyntaxError: Cannot call super() in a base class constructor."');
shouldThrow('function x() { super(); }', '"SyntaxError: Cannot call super() outside of a class constructor."');
shouldThrow('new (class extends Object { constructor() { function x() { super() } } })', '"SyntaxError: Cannot call super() outside of a class constructor."');
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 8b732f3..c1569f6 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,25 @@
+2015-10-11 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ ES6 classes: When a class extends B, super() invokes B.prototype.constructor() instead of B()
+ https://bugs.webkit.org/show_bug.cgi?id=149001
+
+ Reviewed by Saam Barati.
+
+ This patch matches the `super()` call in the constructor to the latest spec.
+ Before this patch, when calling `super()`, it loads `callee.[[HomeObject]].__proto__.constructor`
+ as a super constructor. But after this patch, it loads `callee.__proto__` as a super constructor.
+ This behavior corresponds to the section 12.3.5.2[1].
+
+ [1]: http://www.ecma-international.org/ecma-262/6.0/#sec-getsuperconstructor
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::SuperNode::emitBytecode):
+ * tests/stress/super-call-does-not-look-up-constructor.js: Added.
+ (shouldBe):
+ (B):
+ (C):
+ (B.prototype):
+
2015-10-10 Andreas Kling <akling@apple.com>
Reduce pointless malloc traffic in CodeBlock construction.
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index a3e5f56..5abc004 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -167,9 +167,7 @@
RegisterID callee;
callee.setIndex(JSStack::Callee);
- RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName);
- RefPtr<RegisterID> protoParent = generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto);
- return generator.emitGetById(generator.finalDestination(dst), protoParent.get(), generator.propertyNames().constructor);
+ return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
}
static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
diff --git a/Source/JavaScriptCore/tests/stress/super-call-does-not-look-up-constructor.js b/Source/JavaScriptCore/tests/stress/super-call-does-not-look-up-constructor.js
new file mode 100644
index 0000000..1a14249
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/super-call-does-not-look-up-constructor.js
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+var called = null;
+class B {
+ constructor() {
+ called = 'B';
+ }
+}
+
+class C extends B {
+}
+B.prototype.constructor = function F() {
+ called = 'F';
+};
+
+new C();
+shouldBe(called, 'B');