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');