]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 A |
1 | /* |
2 | * Copyright (C) 2011 Apple Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #include "config.h" | |
27 | #include "JSBoundFunction.h" | |
28 | ||
29 | #include "GetterSetter.h" | |
30 | #include "JSGlobalObject.h" | |
31 | ||
32 | namespace JSC { | |
33 | ||
34 | ASSERT_CLASS_FITS_IN_CELL(JSBoundFunction); | |
35 | ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSBoundFunction); | |
36 | ||
37 | const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) }; | |
38 | ||
39 | EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec) | |
40 | { | |
41 | JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee()); | |
42 | ||
43 | ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true! | |
44 | JSArray* boundArgs = asArray(boundFunction->boundArgs()); | |
45 | ||
46 | MarkedArgumentBuffer args; | |
47 | for (unsigned i = 0; i < boundArgs->length(); ++i) | |
48 | args.append(boundArgs->getIndex(i)); | |
49 | for (unsigned i = 0; i < exec->argumentCount(); ++i) | |
50 | args.append(exec->argument(i)); | |
51 | ||
52 | JSObject* targetFunction = boundFunction->targetFunction(); | |
53 | CallData callData; | |
54 | CallType callType = getCallData(targetFunction, callData); | |
55 | ASSERT(callType != CallTypeNone); | |
56 | return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args)); | |
57 | } | |
58 | ||
59 | EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState* exec) | |
60 | { | |
61 | JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee()); | |
62 | ||
63 | ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true! | |
64 | JSArray* boundArgs = asArray(boundFunction->boundArgs()); | |
65 | ||
66 | MarkedArgumentBuffer args; | |
67 | for (unsigned i = 0; i < boundArgs->length(); ++i) | |
68 | args.append(boundArgs->getIndex(i)); | |
69 | for (unsigned i = 0; i < exec->argumentCount(); ++i) | |
70 | args.append(exec->argument(i)); | |
71 | ||
72 | JSObject* targetFunction = boundFunction->targetFunction(); | |
73 | ConstructData constructData; | |
74 | ConstructType constructType = getConstructData(targetFunction, constructData); | |
75 | ASSERT(constructType != ConstructTypeNone); | |
76 | return JSValue::encode(construct(exec, targetFunction, constructType, constructData, args)); | |
77 | } | |
78 | ||
79 | JSBoundFunction* JSBoundFunction::create(ExecState* exec, JSGlobalObject* globalObject, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int length, const Identifier& name) | |
80 | { | |
81 | ConstructData constructData; | |
82 | ConstructType constructType = JSC::getConstructData(targetFunction, constructData); | |
83 | bool canConstruct = constructType != ConstructTypeNone; | |
84 | ||
85 | NativeExecutable* executable = exec->globalData().getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor); | |
86 | JSBoundFunction* function = new (NotNull, allocateCell<JSBoundFunction>(*exec->heap())) JSBoundFunction(exec, globalObject, globalObject->boundFunctionStructure(), targetFunction, boundThis, boundArgs); | |
87 | ||
88 | function->finishCreation(exec, executable, length, name); | |
89 | return function; | |
90 | } | |
91 | ||
92 | bool JSBoundFunction::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue) | |
93 | { | |
94 | JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(object); | |
95 | // FIXME: our instanceof implementation will have already (incorrectly) performed | |
96 | // a [[Get]] of .prototype from the bound function object, which is incorrect! | |
97 | // https://bugs.webkit.org/show_bug.cgi?id=68656 | |
98 | JSValue proto = thisObject->m_targetFunction->get(exec, exec->propertyNames().prototype); | |
99 | return thisObject->m_targetFunction->methodTable()->hasInstance(thisObject->m_targetFunction.get(), exec, value, proto); | |
100 | } | |
101 | ||
102 | JSBoundFunction::JSBoundFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs) | |
103 | : Base(exec, globalObject, structure) | |
104 | , m_targetFunction(exec->globalData(), this, targetFunction) | |
105 | , m_boundThis(exec->globalData(), this, boundThis) | |
106 | , m_boundArgs(exec->globalData(), this, boundArgs) | |
107 | { | |
108 | } | |
109 | ||
110 | void JSBoundFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const Identifier& name) | |
111 | { | |
112 | Base::finishCreation(exec, executable, length, name); | |
113 | ASSERT(inherits(&s_info)); | |
114 | ||
115 | putDirectAccessor(exec->globalData(), exec->propertyNames().arguments, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); | |
116 | putDirectAccessor(exec->globalData(), exec->propertyNames().caller, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); | |
117 | } | |
118 | ||
119 | void JSBoundFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) | |
120 | { | |
121 | JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(cell); | |
122 | ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); | |
123 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); | |
124 | ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); | |
125 | Base::visitChildren(thisObject, visitor); | |
126 | ||
127 | visitor.append(&thisObject->m_targetFunction); | |
128 | visitor.append(&thisObject->m_boundThis); | |
129 | visitor.append(&thisObject->m_boundArgs); | |
130 | } | |
131 | ||
132 | } // namespace JSC |