[ES6] Support subclassing Function.
https://bugs.webkit.org/show_bug.cgi?id=153081

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This patch enables subclassing the Function object. It also fixes an existing
bug that prevented users from subclassing functions that have a function in
the superclass's prototype property.

* bytecompiler/NodesCodegen.cpp:
(JSC::ClassExprNode::emitBytecode):
* runtime/FunctionConstructor.cpp:
(JSC::constructWithFunctionConstructor):
(JSC::constructFunction):
(JSC::constructFunctionSkippingEvalEnabledCheck):
* runtime/FunctionConstructor.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::create):
* runtime/JSFunction.h:
(JSC::JSFunction::createImpl):
* runtime/JSFunctionInlines.h:
(JSC::JSFunction::createWithInvalidatedReallocationWatchpoint):
(JSC::JSFunction::JSFunction): Deleted.
* tests/stress/class-subclassing-function.js: Added.

LayoutTests:

Rebasline tests with the new clearer error message.

* js/class-syntax-extends-expected.txt:
* js/script-tests/class-syntax-extends.js:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@195070 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 3d99b05..e1c84d1 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2016-01-14  Keith Miller  <keith_miller@apple.com>
+
+        [ES6] Support subclassing Function.
+        https://bugs.webkit.org/show_bug.cgi?id=153081
+
+        Reviewed by Geoffrey Garen.
+
+        Rebasline tests with the new clearer error message.
+
+        * js/class-syntax-extends-expected.txt:
+        * js/script-tests/class-syntax-extends.js:
+
 2016-01-14  Zalan Bujtas  <zalan@apple.com>
 
         ASSERTION FAILED: !newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout() in WebCore::FrameView::scheduleRelayoutOfSubtree
diff --git a/LayoutTests/js/class-syntax-extends-expected.txt b/LayoutTests/js/class-syntax-extends-expected.txt
index d1b2ada..c47f5fc 100644
--- a/LayoutTests/js/class-syntax-extends-expected.txt
+++ b/LayoutTests/js/class-syntax-extends-expected.txt
@@ -26,9 +26,9 @@
 PASS x = class extends 3 { constructor() { } }; x.__proto__:::TypeError: The superclass is not an object.
 PASS x = class extends "abc" { constructor() { } }; x.__proto__:::TypeError: The superclass is not an object.
 PASS baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype
-PASS x = class extends baseWithBadPrototype { constructor() { } }:::TypeError: The superclass's prototype is not an object.
+PASS x = class extends baseWithBadPrototype { constructor() { } }:::TypeError: The value of the superclass's prototype property is not an object.
 PASS baseWithBadPrototype.prototype = "abc"
-PASS x = class extends baseWithBadPrototype { constructor() { } }:::TypeError: The superclass's prototype is not an object.
+PASS x = class extends baseWithBadPrototype { constructor() { } }:::TypeError: The value of the superclass's prototype property is not an object.
 PASS baseWithBadPrototype.prototype = null; x = class extends baseWithBadPrototype { constructor() { } }
 PASS x = 1; c = class extends ++x { constructor() { } };:::SyntaxError: Unexpected token '++'
 PASS x = 1; c = class extends x++ { constructor() { } };:::SyntaxError: Unexpected token '++'. Expected opening '{' at the start of a class body.
@@ -48,8 +48,8 @@
 PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends false||null||namespace.A { constructor() { } }:::SyntaxError: Unexpected token '||'. Expected opening '{' at the start of a class body.
 PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (x++, namespace.A) { constructor() { } };
 PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (namespace.A, x++) { constructor() { } };:::TypeError: The superclass is not an object.
-PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A { constructor() { } }:::TypeError: The superclass's prototype is not an object.
-PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A() { constructor() { } }:::TypeError: The superclass's prototype is not an object.
+PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A { constructor() { } }:::TypeError: The value of the superclass's prototype property is not an object.
+PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A() { constructor() { } }:::TypeError: The value of the superclass's prototype property is not an object.
 PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; try { namespace.B = class extends (x++, namespace.A) { constructor() { } } } catch (e) { } x:::2
 PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; try { namespace.B = class extends (namespace.A, x++) { constructor() { } } } catch (e) { } x:::2
 PASS Object.getPrototypeOf((class { constructor () { } }).prototype):::Object.prototype
diff --git a/LayoutTests/js/script-tests/class-syntax-extends.js b/LayoutTests/js/script-tests/class-syntax-extends.js
index 2d649ac..38e5e5c 100644
--- a/LayoutTests/js/script-tests/class-syntax-extends.js
+++ b/LayoutTests/js/script-tests/class-syntax-extends.js
@@ -81,9 +81,9 @@
 shouldThrow('x = class extends 3 { constructor() { } }; x.__proto__', '"TypeError: The superclass is not an object."');
 shouldThrow('x = class extends "abc" { constructor() { } }; x.__proto__', '"TypeError: The superclass is not an object."');
 shouldNotThrow('baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype');
-shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The superclass\'s prototype is not an object."');
+shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The value of the superclass\'s prototype property is not an object."');
 shouldNotThrow('baseWithBadPrototype.prototype = "abc"');
-shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The superclass\'s prototype is not an object."');
+shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The value of the superclass\'s prototype property is not an object."');
 shouldNotThrow('baseWithBadPrototype.prototype = null; x = class extends baseWithBadPrototype { constructor() { } }');
 
 shouldThrow('x = 1; c = class extends ++x { constructor() { } };');
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index cd5d37a..3fb0c6d 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,30 @@
+2016-01-14  Keith Miller  <keith_miller@apple.com>
+
+        [ES6] Support subclassing Function.
+        https://bugs.webkit.org/show_bug.cgi?id=153081
+
+        Reviewed by Geoffrey Garen.
+
+        This patch enables subclassing the Function object. It also fixes an existing
+        bug that prevented users from subclassing functions that have a function in
+        the superclass's prototype property.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ClassExprNode::emitBytecode):
+        * runtime/FunctionConstructor.cpp:
+        (JSC::constructWithFunctionConstructor):
+        (JSC::constructFunction):
+        (JSC::constructFunctionSkippingEvalEnabledCheck):
+        * runtime/FunctionConstructor.h:
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::create):
+        * runtime/JSFunction.h:
+        (JSC::JSFunction::createImpl):
+        * runtime/JSFunctionInlines.h:
+        (JSC::JSFunction::createWithInvalidatedReallocationWatchpoint):
+        (JSC::JSFunction::JSFunction): Deleted.
+        * tests/stress/class-subclassing-function.js: Added.
+
 2016-01-13  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [CMake] Do not use LLVM static libraries for FTL JIT
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index cc00be6..3c4f20b 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -3228,7 +3228,8 @@
 
         RefPtr<Label> protoParentIsObjectOrNullLabel = generator.newLabel();
         generator.emitJumpIfTrue(generator.emitUnaryOp(op_is_object_or_null, tempRegister.get(), protoParent.get()), protoParentIsObjectOrNullLabel.get());
-        generator.emitThrowTypeError(ASCIILiteral("The superclass's prototype is not an object."));
+        generator.emitJumpIfTrue(generator.emitUnaryOp(op_is_function, tempRegister.get(), protoParent.get()), protoParentIsObjectOrNullLabel.get());
+        generator.emitThrowTypeError(ASCIILiteral("The value of the superclass's prototype property is not an object."));
         generator.emitLabel(protoParentIsObjectOrNullLabel.get());
 
         generator.emitDirectPutById(constructor.get(), generator.propertyNames().underscoreProto, superclass.get(), PropertyNode::Unknown);
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
index 6c39a0d..cda30b9 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -56,7 +56,7 @@
 static EncodedJSValue JSC_HOST_CALL constructWithFunctionConstructor(ExecState* exec)
 {
     ArgList args(exec);
-    return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args));
+    return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Function, exec->newTarget()));
 }
 
 ConstructType FunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -79,17 +79,17 @@
 }
 
 // ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position, FunctionConstructionMode functionConstructionMode)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
 {
     if (!globalObject->evalEnabled())
         return exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
-    return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position, -1, functionConstructionMode);
+    return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position, -1, functionConstructionMode, newTarget);
 }
 
 JSObject* constructFunctionSkippingEvalEnabledCheck(
     ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, 
     const Identifier& functionName, const String& sourceURL, 
-    const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode)
+    const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
 {
     // How we stringify functions is sometimes important for web compatibility.
     // See https://bugs.webkit.org/show_bug.cgi?id=24350.
@@ -124,13 +124,14 @@
         return exec->vm().throwException(exec, exception);
     }
 
-    return JSFunction::create(exec->vm(), function, globalObject);
+
+    return JSFunction::create(exec->vm(), function, globalObject, InternalFunction::createSubclassStructure(exec, newTarget, globalObject->functionStructure()));
 }
 
 // ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, FunctionConstructionMode functionConstructionMode)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
 {
-    return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition(), functionConstructionMode);
+    return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition(), functionConstructionMode, newTarget);
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h
index d11fb2a..63bc408 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.h
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h
@@ -61,12 +61,13 @@
     Generator,
 };
 
-JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&, FunctionConstructionMode = FunctionConstructionMode::Function);
-JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, FunctionConstructionMode = FunctionConstructionMode::Function);
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&, FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
 
 JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(
     ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, 
-    const String&, const WTF::TextPosition&, int overrideLineNumber = -1, FunctionConstructionMode = FunctionConstructionMode::Function);
+    const String&, const WTF::TextPosition&, int overrideLineNumber = -1,
+    FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
 
 } // namespace JSC
 
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 5cff8bc..5687161 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -63,7 +63,12 @@
 
 JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
 {
-    JSFunction* result = createImpl(vm, executable, scope);
+    return create(vm, executable, scope, scope->globalObject()->functionStructure());
+}
+
+JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+{
+    JSFunction* result = createImpl(vm, executable, scope, structure);
     executable->singletonFunction()->notifyWrite(vm, result, "Allocating a function");
     return result;
 }
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index 7878348..63fed33 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -73,6 +73,7 @@
     static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
 
     static JSFunction* create(VM&, FunctionExecutable*, JSScope*);
+    static JSFunction* create(VM&, FunctionExecutable*, JSScope*, Structure*);
 #if ENABLE(WEBASSEMBLY)
     static JSFunction* create(VM&, WebAssemblyExecutable*, JSScope*);
 #endif
@@ -151,7 +152,6 @@
 
 protected:
     JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
-    JSFunction(VM&, FunctionExecutable*, JSScope*);
     JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
 
 #if ENABLE(WEBASSEMBLY)
@@ -179,9 +179,9 @@
     static NativeExecutable* lookUpOrCreateNativeExecutable(VM&, NativeFunction, Intrinsic, NativeFunction nativeConstructor, const String& name);
 
 private:
-    static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope)
+    static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
     {
-        JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope);
+        JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope, structure);
         ASSERT(function->structure()->globalObject());
         function->finishCreation(vm);
         return function;
diff --git a/Source/JavaScriptCore/runtime/JSFunctionInlines.h b/Source/JavaScriptCore/runtime/JSFunctionInlines.h
index a1f7c67..ef43d32 100644
--- a/Source/JavaScriptCore/runtime/JSFunctionInlines.h
+++ b/Source/JavaScriptCore/runtime/JSFunctionInlines.h
@@ -35,16 +35,9 @@
     VM& vm, FunctionExecutable* executable, JSScope* scope)
 {
     ASSERT(executable->singletonFunction()->hasBeenInvalidated());
-    return createImpl(vm, executable, scope);
+    return createImpl(vm, executable, scope, scope->globalObject()->functionStructure());
 }
 
-inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope)
-    : Base(vm, scope, scope->globalObject()->functionStructure())
-    , m_executable(vm, this, executable)
-    , m_rareData()
-{
-}
-    
 inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
     : Base(vm, scope, structure)
     , m_executable(vm, this, executable)
diff --git a/Source/JavaScriptCore/tests/stress/class-subclassing-function.js b/Source/JavaScriptCore/tests/stress/class-subclassing-function.js
new file mode 100644
index 0000000..7b8ea99
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/class-subclassing-function.js
@@ -0,0 +1,33 @@
+F = class extends Function { }
+
+function test(i) {
+
+    let f = new F("x", "return x + " + i + ";");
+    let C = new F("x", "this.x = x; this.i = " + i);
+
+    if (!(f instanceof Function && f instanceof F))
+        throw "bad chain";
+
+    if (f(1) !== i+1)
+        throw "function was not called correctly";
+
+    let o = new C("hello");
+    if (o.x !== "hello" || o.i !== i)
+        throw "function as constructor was not correct";
+
+    let g = new F("x", "y", "return this.foo + x + y");
+    if (g.call({foo:1}, 1, 1) !== 3)
+        throw "function was not .callable";
+
+    let g2 = g.bind({foo:1}, 1);
+    if (g2 instanceof F)
+        throw "the binding of a subclass should not inherit from the original function";
+
+    if (g2(1) !== 3)
+        throw "binding didn't work";
+
+}
+noInline(test);
+
+for (i = 0; i < 10000; i++)
+    test(i);