]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSFunction.cpp
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / runtime / JSFunction.cpp
1 /*
2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6 * Copyright (C) 2007 Maks Orlovich
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25 #include "config.h"
26 #include "JSFunction.h"
27
28 #include "CodeBlock.h"
29 #include "CommonIdentifiers.h"
30 #include "CallFrame.h"
31 #include "FunctionPrototype.h"
32 #include "JSGlobalObject.h"
33 #include "Interpreter.h"
34 #include "ObjectPrototype.h"
35 #include "Parser.h"
36 #include "PropertyNameArray.h"
37 #include "ScopeChainMark.h"
38
39 using namespace WTF;
40 using namespace Unicode;
41
42 namespace JSC {
43
44 ASSERT_CLASS_FITS_IN_CELL(JSFunction);
45
46 const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 };
47
48 bool JSFunction::isHostFunctionNonInline() const
49 {
50 return isHostFunction();
51 }
52
53 JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure)
54 : Base(structure)
55 , m_executable(adoptRef(new VPtrHackExecutable()))
56 {
57 }
58
59 JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeExecutable* thunk, NativeFunction func)
60 : Base(&exec->globalData(), structure, name)
61 #if ENABLE(JIT)
62 , m_executable(thunk)
63 #endif
64 {
65 #if ENABLE(JIT)
66 setNativeFunction(func);
67 putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
68 #else
69 UNUSED_PARAM(thunk);
70 UNUSED_PARAM(length);
71 UNUSED_PARAM(func);
72 ASSERT_NOT_REACHED();
73 #endif
74 }
75
76 JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func)
77 : Base(&exec->globalData(), structure, name)
78 #if ENABLE(JIT)
79 , m_executable(exec->globalData().jitStubs->ctiNativeCallThunk())
80 #endif
81 {
82 #if ENABLE(JIT)
83 setNativeFunction(func);
84 putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
85 #else
86 UNUSED_PARAM(length);
87 UNUSED_PARAM(func);
88 ASSERT_NOT_REACHED();
89 #endif
90 }
91
92 JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode)
93 : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), executable->name())
94 , m_executable(executable)
95 {
96 setScopeChain(scopeChainNode);
97 }
98
99 JSFunction::~JSFunction()
100 {
101 ASSERT(vptr() == JSGlobalData::jsFunctionVPtr);
102
103 // JIT code for other functions may have had calls linked directly to the code for this function; these links
104 // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
105 // this memory is freed and may be reused (potentially for another, different JSFunction).
106 if (!isHostFunction()) {
107 #if ENABLE(JIT_OPTIMIZE_CALL)
108 ASSERT(m_executable);
109 if (jsExecutable()->isGenerated())
110 jsExecutable()->generatedBytecode().unlinkCallers();
111 #endif
112 scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too?
113 }
114 }
115
116 void JSFunction::markChildren(MarkStack& markStack)
117 {
118 Base::markChildren(markStack);
119 if (!isHostFunction()) {
120 jsExecutable()->markAggregate(markStack);
121 scopeChain().markAggregate(markStack);
122 }
123 }
124
125 CallType JSFunction::getCallData(CallData& callData)
126 {
127 if (isHostFunction()) {
128 callData.native.function = nativeFunction();
129 return CallTypeHost;
130 }
131 callData.js.functionExecutable = jsExecutable();
132 callData.js.scopeChain = scopeChain().node();
133 return CallTypeJS;
134 }
135
136 JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args)
137 {
138 ASSERT(!isHostFunction());
139 return exec->interpreter()->execute(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot());
140 }
141
142 JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
143 {
144 JSFunction* thisObj = asFunction(slotBase);
145 ASSERT(!thisObj->isHostFunction());
146 return exec->interpreter()->retrieveArguments(exec, thisObj);
147 }
148
149 JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&)
150 {
151 JSFunction* thisObj = asFunction(slotBase);
152 ASSERT(!thisObj->isHostFunction());
153 return exec->interpreter()->retrieveCaller(exec, thisObj);
154 }
155
156 JSValue JSFunction::lengthGetter(ExecState* exec, JSValue slotBase, const Identifier&)
157 {
158 JSFunction* thisObj = asFunction(slotBase);
159 ASSERT(!thisObj->isHostFunction());
160 return jsNumber(exec, thisObj->jsExecutable()->parameterCount());
161 }
162
163 bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
164 {
165 if (isHostFunction())
166 return Base::getOwnPropertySlot(exec, propertyName, slot);
167
168 if (propertyName == exec->propertyNames().prototype) {
169 JSValue* location = getDirectLocation(propertyName);
170
171 if (!location) {
172 JSObject* prototype = new (exec) JSObject(scopeChain().globalObject()->emptyObjectStructure());
173 prototype->putDirect(exec->propertyNames().constructor, this, DontEnum);
174 putDirect(exec->propertyNames().prototype, prototype, DontDelete);
175 location = getDirectLocation(propertyName);
176 }
177
178 slot.setValueSlot(this, location, offsetForLocation(location));
179 }
180
181 if (propertyName == exec->propertyNames().arguments) {
182 slot.setCacheableCustom(this, argumentsGetter);
183 return true;
184 }
185
186 if (propertyName == exec->propertyNames().length) {
187 slot.setCacheableCustom(this, lengthGetter);
188 return true;
189 }
190
191 if (propertyName == exec->propertyNames().caller) {
192 slot.setCacheableCustom(this, callerGetter);
193 return true;
194 }
195
196 return Base::getOwnPropertySlot(exec, propertyName, slot);
197 }
198
199 bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
200 {
201 if (isHostFunction())
202 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
203
204 if (propertyName == exec->propertyNames().prototype) {
205 PropertySlot slot;
206 getOwnPropertySlot(exec, propertyName, slot);
207 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
208 }
209
210 if (propertyName == exec->propertyNames().arguments) {
211 descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
212 return true;
213 }
214
215 if (propertyName == exec->propertyNames().length) {
216 descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
217 return true;
218 }
219
220 if (propertyName == exec->propertyNames().caller) {
221 descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
222 return true;
223 }
224
225 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
226 }
227
228 void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
229 {
230 if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
231 propertyNames.add(exec->propertyNames().arguments);
232 propertyNames.add(exec->propertyNames().callee);
233 propertyNames.add(exec->propertyNames().caller);
234 propertyNames.add(exec->propertyNames().length);
235 }
236 Base::getOwnPropertyNames(exec, propertyNames, mode);
237 }
238
239 void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
240 {
241 if (isHostFunction()) {
242 Base::put(exec, propertyName, value, slot);
243 return;
244 }
245 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
246 return;
247 Base::put(exec, propertyName, value, slot);
248 }
249
250 bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)
251 {
252 if (isHostFunction())
253 return Base::deleteProperty(exec, propertyName);
254 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
255 return false;
256 return Base::deleteProperty(exec, propertyName);
257 }
258
259 // ECMA 13.2.2 [[Construct]]
260 ConstructType JSFunction::getConstructData(ConstructData& constructData)
261 {
262 if (isHostFunction())
263 return ConstructTypeNone;
264 constructData.js.functionExecutable = jsExecutable();
265 constructData.js.scopeChain = scopeChain().node();
266 return ConstructTypeJS;
267 }
268
269 JSObject* JSFunction::construct(ExecState* exec, const ArgList& args)
270 {
271 ASSERT(!isHostFunction());
272 Structure* structure;
273 JSValue prototype = get(exec, exec->propertyNames().prototype);
274 if (prototype.isObject())
275 structure = asObject(prototype)->inheritorID();
276 else
277 structure = exec->lexicalGlobalObject()->emptyObjectStructure();
278 JSObject* thisObj = new (exec) JSObject(structure);
279
280 JSValue result = exec->interpreter()->execute(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot());
281 if (exec->hadException() || !result.isObject())
282 return thisObj;
283 return asObject(result);
284 }
285
286 } // namespace JSC