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