COMMIT_MESSAGE (1/3)

 1Implement ES5 Function.prototype.bind function
 2https://bugs.webkit.org/show_bug.cgi?id=26382
 3

JavaScriptCore/Android.mk

@@LOCAL_SRC_FILES := \
103103 runtime/JSAPIValueWrapper.cpp \
104104 runtime/JSActivation.cpp \
105105 runtime/JSArray.cpp \
 106 runtime/JSBoundFunction.cpp \
106107 runtime/JSByteArray.cpp \
107108 runtime/JSCell.cpp \
108109 runtime/JSFunction.cpp \

JavaScriptCore/GNUmakefile.am

@@javascriptcore_sources += \
447447 JavaScriptCore/runtime/JSArray.h \
448448 JavaScriptCore/runtime/JSAPIValueWrapper.cpp \
449449 JavaScriptCore/runtime/JSAPIValueWrapper.h \
 450 JavaScriptCore/runtime/JSBoundFunction.cpp \
 451 JavaScriptCore/runtime/JSBoundFunction.h \
450452 JavaScriptCore/runtime/JSCell.cpp \
451453 JavaScriptCore/runtime/JSCell.h \
452454 JavaScriptCore/runtime/JSFunction.cpp \

JavaScriptCore/JavaScriptCore.gypi

224224 'runtime/JSActivation.h',
225225 'runtime/JSArray.cpp',
226226 'runtime/JSArray.h',
 227 'runtime/JSBoundFunction.cpp',
 228 'runtime/JSBoundFunction.h',
227229 'runtime/JSByteArray.cpp',
228230 'runtime/JSByteArray.h',
229231 'runtime/JSCell.cpp',

JavaScriptCore/JavaScriptCore.pro

@@SOURCES += \
150150 runtime/JSByteArray.cpp \
151151 runtime/JSCell.cpp \
152152 runtime/JSFunction.cpp \
 153 runtime/JSBoundFunction.cpp \
153154 runtime/JSGlobalData.cpp \
154155 runtime/JSGlobalObject.cpp \
155156 runtime/JSGlobalObjectFunctions.cpp \

JavaScriptCore/runtime/CommonIdentifiers.h

3333 macro(__lookupSetter__) \
3434 macro(apply) \
3535 macro(arguments) \
 36 macro(bind) \
3637 macro(call) \
3738 macro(callee) \
3839 macro(caller) \

JavaScriptCore/runtime/FunctionPrototype.cpp

2323
2424#include "Arguments.h"
2525#include "JSArray.h"
 26#include "JSBoundFunction.h"
2627#include "JSFunction.h"
2728#include "JSString.h"
2829#include "JSStringBuilder.h"

@@ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype);
3738static JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&);
3839static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSValue, const ArgList&);
3940static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&);
 41static JSValue JSC_HOST_CALL functionProtoFuncBind(ExecState*, JSObject*, JSValue, const ArgList&);
4042
4143FunctionPrototype::FunctionPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure)
4244 : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier)

@@void FunctionPrototype::addFunctionProperties(ExecState* exec, Structure* protot
5153 putDirectFunctionWithoutTransition(exec, *applyFunction, DontEnum);
5254 *callFunction = new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().call, functionProtoFuncCall);
5355 putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum);
 56 putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().bind, functionProtoFuncBind), DontEnum);
5457}
5558
5659static JSValue JSC_HOST_CALL callFunctionPrototype(ExecState*, JSObject*, JSValue, const ArgList&)

@@JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSVa
9598 }
9699 }
97100
 101 if (thisValue.inherits(&JSBoundFunction::info))
 102 return jsString(exec, "function () {\n [bounded function]\n}");
 103
98104 if (thisValue.inherits(&InternalFunction::info)) {
99105 InternalFunction* function = asInternalFunction(thisValue);
100106 return jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}");

@@JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec, JSObject*, JSValue
143149 return call(exec, thisValue, callType, callData, args.at(0), callArgs);
144150}
145151
 152JSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
 153{
 154 CallData callData;
 155 CallType callType = thisValue.getCallData(callData);
 156 if (callType == CallTypeNone || args.size() < 1)
 157 return throwError(exec, TypeError);
 158
 159 ArgList boundArgs;
 160 args.getSlice(1, boundArgs);
 161 return new (exec) JSBoundFunction(exec, thisValue, args.at(0), boundArgs);
 162}
 163
146164} // namespace JSC

JavaScriptCore/runtime/JSBoundFunction.cpp

 1#include "config.h"
 2#include "JSBoundFunction.h"
 3
 4#include "Error.h"
 5#include "JSGlobalObject.h"
 6
 7namespace JSC {
 8
 9ASSERT_CLASS_FITS_IN_CELL(JSBoundFunction);
 10
 11const ClassInfo JSBoundFunction::info = { "Function", &InternalFunction::info, 0, 0 };
 12
 13JSBoundFunction::JSBoundFunction(ExecState* exec, JSValue targetFunction, JSValue boundThis, const ArgList& args)
 14 : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject()->boundFunctionStructure(), Identifier(exec, "boundFunction"))
 15 , m_targetFunction(targetFunction)
 16 , m_boundThis(boundThis)
 17 , d(args.size() ? new BoundArgsData(args) : 0)
 18{
 19 const unsigned targetLength = targetFunction.get(exec, exec->propertyNames().length).toUInt32(exec);
 20 int length = targetLength - args.size();
 21 if (length < 0)
 22 length = 0;
 23 putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
 24
 25 // FIXME: DefineOwnProperty for "caller" and "arguments" using ThrowTypeError as get/set.
 26}
 27
 28bool JSBoundFunction::hasInstance(ExecState* exec, JSValue value, JSValue proto)
 29{
 30 JSObject* target = asObject(m_targetFunction);
 31 if (!target->structure()->typeInfo().implementsHasInstance())
 32 return throwError(exec, TypeError);
 33
 34 return target->hasInstance(exec, value, target->get(exec, exec->propertyNames().prototype));
 35}
 36
 37static JSObject* constructBoundFunction(ExecState* exec, JSObject* function, const ArgList& args)
 38{
 39 JSBoundFunction* boundFunc = asBoundFunction(function);
 40
 41 JSObject* target = asObject(boundFunc->targetFunction());
 42 ConstructData constructData;
 43 ConstructType constructType = target->getConstructData(constructData);
 44 if (constructType == ConstructTypeNone)
 45 return throwError(exec, TypeError);
 46
 47 JSValue* boundArgs = boundFunc->boundArgs();
 48 size_t boundArgCount = boundFunc->boundArgCount();
 49
 50 if (args.isEmpty())
 51 return construct(exec, target, constructType, constructData, ArgList(boundArgs, boundArgCount));
 52
 53 MarkedArgumentBuffer finalArgs;
 54 for (int i = 0; i < boundArgCount; i++)
 55 finalArgs.append(boundArgs[i]);
 56 for (int i = 0; i < args.size(); i++)
 57 finalArgs.append(args.at(i));
 58
 59 return construct(exec, target, constructType, constructData, finalArgs);
 60}
 61
 62ConstructType JSBoundFunction::getConstructData(ConstructData& constructData)
 63{
 64 constructData.native.function = constructBoundFunction;
 65 return ConstructTypeHost;
 66}
 67
 68static JSValue JSC_HOST_CALL callBoundFunction(ExecState* exec, JSObject* function, JSValue, const ArgList& args)
 69{
 70 JSBoundFunction* boundFunc = asBoundFunction(function);
 71
 72 JSObject* target = asObject(boundFunc->targetFunction());
 73 CallData callData;
 74 CallType callType = target->getCallData(callData);
 75
 76 // We already checked this in functionProtoFuncBind().
 77 ASSERT(callType != CallTypeNone);
 78
 79 JSValue* boundArgs = boundFunc->boundArgs();
 80 size_t boundArgCount = boundFunc->boundArgCount();
 81
 82 if (args.isEmpty())
 83 return call(exec, target, callType, callData, boundFunc->boundThis(), ArgList(boundArgs, boundArgCount));
 84
 85 MarkedArgumentBuffer finalArgs;
 86 for (int i = 0; i < boundArgCount; i++)
 87 finalArgs.append(boundArgs[i]);
 88 for (int i = 0; i < args.size(); i++)
 89 finalArgs.append(args.at(i));
 90
 91 return call(exec, target, callType, callData, boundFunc->boundThis(), finalArgs);
 92}
 93
 94CallType JSBoundFunction::getCallData(CallData& callData)
 95{
 96 callData.native.function = callBoundFunction;
 97 return CallTypeHost;
 98}
 99
 100void JSBoundFunction::markChildren(MarkStack& markStack)
 101{
 102 JSObject::markChildren(markStack);
 103 markStack.append(m_targetFunction);
 104 markStack.append(m_boundThis);
 105 if (d)
 106 markStack.appendValues(d->args, d->argCount, MayContainNullValues);
 107}
 108
 109} // namespace JSC

JavaScriptCore/runtime/JSBoundFunction.h

 1#ifndef JSBoundFunction_h
 2#define JSBoundFunction_h
 3
 4#include "InternalFunction.h"
 5#include <wtf/FastAllocBase.h>
 6#include <wtf/OwnPtr.h>
 7
 8namespace JSC {
 9
 10class JSBoundFunction : public InternalFunction {
 11 friend class JIT;
 12
 13public:
 14 explicit JSBoundFunction(ExecState*, JSValue, JSValue, const ArgList&);
 15
 16 JSValue targetFunction() const { return m_targetFunction; }
 17 JSValue boundThis() const { return m_boundThis; }
 18 JSValue* boundArgs() const { return d ? d->args : 0; }
 19 size_t boundArgCount() const { return d ? d->argCount : 0; }
 20
 21 virtual const ClassInfo* classInfo() const { return &info; }
 22 static const ClassInfo info;
 23
 24 static PassRefPtr<Structure> createStructure(JSValue proto)
 25 {
 26 return Structure::create(proto, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
 27 }
 28
 29protected:
 30 static const unsigned StructureFlags = OverridesHasInstance | InternalFunction::StructureFlags;
 31
 32private:
 33 virtual bool hasInstance(ExecState*, JSValue, JSValue proto);
 34
 35 virtual ConstructType getConstructData(ConstructData&);
 36 virtual CallType getCallData(CallData&);
 37
 38 virtual void markChildren(MarkStack&);
 39
 40 struct BoundArgsData : FastAllocBase {
 41 BoundArgsData(const ArgList& args)
 42 : args(new JSValue[args.size()])
 43 , argCount(args.size())
 44 {
 45 for (int i = 0; i < argCount; i++)
 46 this->args[i] = args.at(i);
 47 }
 48
 49 ~BoundArgsData()
 50 {
 51 delete [] args;
 52 }
 53
 54 JSValue* args;
 55 size_t argCount;
 56 };
 57
 58 JSValue m_targetFunction;
 59 JSValue m_boundThis;
 60 OwnPtr<BoundArgsData> d;
 61};
 62
 63JSBoundFunction* asBoundFunction(JSValue);
 64
 65inline JSBoundFunction* asBoundFunction(JSValue value)
 66{
 67 ASSERT(asObject(value)->inherits(&JSBoundFunction::info));
 68 return static_cast<JSBoundFunction*>(asObject(value));
 69}
 70
 71} // namespace JSC
 72
 73#endif // JSBoundFunction_h

JavaScriptCore/runtime/JSGlobalObject.cpp

4747#include "FunctionConstructor.h"
4848#include "FunctionPrototype.h"
4949#include "GlobalEvalFunction.h"
 50#include "JSBoundFunction.h"
5051#include "JSFunction.h"
5152#include "JSGlobalObjectFunctions.h"
5253#include "JSLock.h"

@@void JSGlobalObject::reset(JSValue prototype)
217218
218219 d()->functionStructure = JSFunction::createStructure(d()->functionPrototype);
219220 d()->callbackFunctionStructure = JSCallbackFunction::createStructure(d()->functionPrototype);
 221 d()->boundFunctionStructure = JSBoundFunction::createStructure(d()->functionPrototype);
220222 d()->argumentsStructure = Arguments::createStructure(d()->objectPrototype);
221223 d()->callbackConstructorStructure = JSCallbackConstructor::createStructure(d()->objectPrototype);
222224 d()->callbackObjectStructure = JSCallbackObject<JSObject>::createStructure(d()->objectPrototype);

JavaScriptCore/runtime/JSGlobalObject.h

@@namespace JSC {
136136 RefPtr<Structure> argumentsStructure;
137137 RefPtr<Structure> arrayStructure;
138138 RefPtr<Structure> booleanObjectStructure;
 139 RefPtr<Structure> boundFunctionStructure;
139140 RefPtr<Structure> callbackConstructorStructure;
140141 RefPtr<Structure> callbackFunctionStructure;
141142 RefPtr<Structure> callbackObjectStructure;

@@namespace JSC {
221222 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
222223 Structure* arrayStructure() const { return d()->arrayStructure.get(); }
223224 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
 225 Structure* boundFunctionStructure() const { return d()->boundFunctionStructure.get(); }
224226 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
225227 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
226228 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }

LayoutTests/fast/js/Object-getOwnPropertyNames-expected.txt

@@PASS getSortedOwnPropertyNames(encodeURIComponent) is ['length', 'name']
4343PASS getSortedOwnPropertyNames(Object) is ['create', 'defineProperties', 'defineProperty', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'keys', 'length', 'name', 'prototype']
4444PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
4545PASS getSortedOwnPropertyNames(Function) is ['length', 'name', 'prototype']
46 PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'call', 'constructor', 'length', 'name', 'toString']
 46PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']
4747PASS getSortedOwnPropertyNames(Array) is ['isArray', 'length', 'name', 'prototype']
4848PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'every', 'filter', 'forEach', 'indexOf', 'join', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
4949PASS getSortedOwnPropertyNames(String) is ['fromCharCode', 'length', 'name', 'prototype']

LayoutTests/fast/js/function-bind.html

 1<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
 2<html>
 3<head>
 4<link rel="stylesheet" href="resources/js-test-style.css">
 5<script src="resources/js-test-pre.js"></script>
 6</head>
 7<body>
 8<p id="description"></p>
 9<div id="console"></div>
 10<script src="script-tests/function-bind.js"></script>
 11<script src="resources/js-test-post.js"></script>
 12</body>
 13</html>

LayoutTests/fast/js/script-tests/Object-getOwnPropertyNames.js

@@var expectedPropertyNamesSet = {
5151 "Object": "['create', 'defineProperties', 'defineProperty', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'keys', 'length', 'name', 'prototype']",
5252 "Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']",
5353 "Function": "['length', 'name', 'prototype']",
54  "Function.prototype": "['apply', 'call', 'constructor', 'length', 'name', 'toString']",
 54 "Function.prototype": "['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']",
5555 "Array": "['isArray', 'length', 'name', 'prototype']",
5656 "Array.prototype": "['concat', 'constructor', 'every', 'filter', 'forEach', 'indexOf', 'join', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
5757 "String": "['fromCharCode', 'length', 'name', 'prototype']",

LayoutTests/fast/js/script-tests/function-bind.js

 1description("Test to ensure correct behaviour of Function.prototype.bind");
 2
 3
 4// Simple use to bind 'this'
 5name = "global";
 6var obj = { name: "local" };
 7
 8shouldBe("obj.name", "'local'");
 9
 10var f = function() { return this.name; }
 11obj.f = f;
 12
 13shouldBe("f()", "'global'");
 14shouldBe("obj.f()", "'local'");
 15
 16var g = obj.f;
 17shouldBe("g()", "'global'");
 18
 19var h = f.bind(obj);
 20shouldBe("h()", "'local'");
 21
 22
 23// Simple use to curry the parameters
 24var adder = function (a, b, c, d) { return a + b + c + d; };
 25var addTwoTwo = adder.bind(null, 2, 2);
 26
 27shouldBe("addTwoTwo(3, 4)", "11");
 28
 29
 30// Constructor
 31var Rectangle = function(color, size) { this.color = color; this.size = size; };
 32var BlueRectangle = Rectangle.bind(null, "blue");
 33
 34var rect = new BlueRectangle(10);
 35
 36shouldBe("rect.color", "'blue'");
 37shouldBe("rect.size", "10");
 38shouldBeTrue("rect instanceof Rectangle");
 39shouldBeTrue("rect instanceof BlueRectangle");
 40
 41
 42// Bind over bind
 43var fun1 = function(a, b, c) { return a + b + c; };
 44var fun2 = fun1.bind(null, 1);
 45var fun3 = fun2.bind(null, 2);
 46
 47shouldBe("fun3(3)", "6");
 48
 49
 50successfullyParsed = true;