|
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 "ExceptionHelpers.h" |
|
32 #include "FunctionPrototype.h" |
|
33 #include "JSGlobalObject.h" |
|
34 #include "JSNotAnObject.h" |
|
35 #include "Interpreter.h" |
|
36 #include "ObjectPrototype.h" |
|
37 #include "Parser.h" |
|
38 #include "PropertyNameArray.h" |
|
39 #include "ScopeChainMark.h" |
|
40 |
|
41 using namespace WTF; |
|
42 using namespace Unicode; |
|
43 |
|
44 namespace JSC { |
|
45 #if ENABLE(JIT) |
|
46 EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) |
|
47 { |
|
48 CodeBlock* codeBlock = exec->callerFrame()->codeBlock(); |
|
49 unsigned vPCIndex = codeBlock->bytecodeOffset(exec, exec->returnPC()); |
|
50 return throwVMError(exec, createNotAConstructorError(exec, exec->callee(), vPCIndex, codeBlock)); |
|
51 } |
|
52 #endif |
|
53 |
|
54 ASSERT_CLASS_FITS_IN_CELL(JSFunction); |
|
55 |
|
56 const ClassInfo JSFunction::info = { "Function", 0, 0, 0 }; |
|
57 |
|
58 bool JSFunction::isHostFunctionNonInline() const |
|
59 { |
|
60 return isHostFunction(); |
|
61 } |
|
62 |
|
63 JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure) |
|
64 : Base(structure) |
|
65 , m_executable(adoptRef(new VPtrHackExecutable())) |
|
66 , m_scopeChain(NoScopeChain()) |
|
67 { |
|
68 } |
|
69 |
|
70 #if ENABLE(JIT) |
|
71 JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, PassRefPtr<NativeExecutable> thunk) |
|
72 : Base(globalObject, structure) |
|
73 , m_executable(thunk) |
|
74 , m_scopeChain(globalObject->globalScopeChain()) |
|
75 { |
|
76 putDirect(exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); |
|
77 putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); |
|
78 } |
|
79 #endif |
|
80 |
|
81 JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) |
|
82 : Base(globalObject, structure) |
|
83 #if ENABLE(JIT) |
|
84 , m_executable(exec->globalData().getHostFunction(func)) |
|
85 #endif |
|
86 , m_scopeChain(globalObject->globalScopeChain()) |
|
87 { |
|
88 putDirect(exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); |
|
89 #if ENABLE(JIT) |
|
90 putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); |
|
91 #else |
|
92 UNUSED_PARAM(length); |
|
93 UNUSED_PARAM(func); |
|
94 ASSERT_NOT_REACHED(); |
|
95 #endif |
|
96 } |
|
97 |
|
98 JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode) |
|
99 : Base(scopeChainNode->globalObject, scopeChainNode->globalObject->functionStructure()) |
|
100 , m_executable(executable) |
|
101 , m_scopeChain(scopeChainNode) |
|
102 { |
|
103 const Identifier& name = static_cast<FunctionExecutable*>(m_executable.get())->name(); |
|
104 putDirect(exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum); |
|
105 } |
|
106 |
|
107 JSFunction::~JSFunction() |
|
108 { |
|
109 ASSERT(vptr() == JSGlobalData::jsFunctionVPtr); |
|
110 |
|
111 // JIT code for other functions may have had calls linked directly to the code for this function; these links |
|
112 // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once |
|
113 // this memory is freed and may be reused (potentially for another, different JSFunction). |
|
114 if (!isHostFunction()) { |
|
115 #if ENABLE(JIT_OPTIMIZE_CALL) |
|
116 ASSERT(m_executable); |
|
117 if (jsExecutable()->isGeneratedForCall()) |
|
118 jsExecutable()->generatedBytecodeForCall().unlinkCallers(); |
|
119 if (jsExecutable()->isGeneratedForConstruct()) |
|
120 jsExecutable()->generatedBytecodeForConstruct().unlinkCallers(); |
|
121 #endif |
|
122 } |
|
123 } |
|
124 |
|
125 const UString& JSFunction::name(ExecState* exec) |
|
126 { |
|
127 return asString(getDirect(exec->globalData().propertyNames->name))->tryGetValue(); |
|
128 } |
|
129 |
|
130 const UString JSFunction::displayName(ExecState* exec) |
|
131 { |
|
132 JSValue displayName = getDirect(exec->globalData().propertyNames->displayName); |
|
133 |
|
134 if (displayName && isJSString(&exec->globalData(), displayName)) |
|
135 return asString(displayName)->tryGetValue(); |
|
136 |
|
137 return UString::null(); |
|
138 } |
|
139 |
|
140 const UString JSFunction::calculatedDisplayName(ExecState* exec) |
|
141 { |
|
142 const UString explicitName = displayName(exec); |
|
143 |
|
144 if (!explicitName.isEmpty()) |
|
145 return explicitName; |
|
146 |
|
147 return name(exec); |
|
148 } |
|
149 |
|
150 void JSFunction::markChildren(MarkStack& markStack) |
|
151 { |
|
152 Base::markChildren(markStack); |
|
153 if (!isHostFunction()) { |
|
154 jsExecutable()->markAggregate(markStack); |
|
155 scope().markAggregate(markStack); |
|
156 } |
|
157 } |
|
158 |
|
159 CallType JSFunction::getCallData(CallData& callData) |
|
160 { |
|
161 #if ENABLE(JIT) |
|
162 if (isHostFunction()) { |
|
163 callData.native.function = nativeFunction(); |
|
164 return CallTypeHost; |
|
165 } |
|
166 #endif |
|
167 callData.js.functionExecutable = jsExecutable(); |
|
168 callData.js.scopeChain = scope().node(); |
|
169 return CallTypeJS; |
|
170 } |
|
171 |
|
172 JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&) |
|
173 { |
|
174 JSFunction* thisObj = asFunction(slotBase); |
|
175 ASSERT(!thisObj->isHostFunction()); |
|
176 return exec->interpreter()->retrieveArguments(exec, thisObj); |
|
177 } |
|
178 |
|
179 JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&) |
|
180 { |
|
181 JSFunction* thisObj = asFunction(slotBase); |
|
182 ASSERT(!thisObj->isHostFunction()); |
|
183 return exec->interpreter()->retrieveCaller(exec, thisObj); |
|
184 } |
|
185 |
|
186 JSValue JSFunction::lengthGetter(ExecState* exec, JSValue slotBase, const Identifier&) |
|
187 { |
|
188 JSFunction* thisObj = asFunction(slotBase); |
|
189 ASSERT(!thisObj->isHostFunction()); |
|
190 return jsNumber(exec, thisObj->jsExecutable()->parameterCount()); |
|
191 } |
|
192 |
|
193 bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
|
194 { |
|
195 if (isHostFunction()) |
|
196 return Base::getOwnPropertySlot(exec, propertyName, slot); |
|
197 |
|
198 if (propertyName == exec->propertyNames().prototype) { |
|
199 JSValue* location = getDirectLocation(propertyName); |
|
200 |
|
201 if (!location) { |
|
202 JSObject* prototype = new (exec) JSObject(scope().globalObject()->emptyObjectStructure()); |
|
203 prototype->putDirect(exec->propertyNames().constructor, this, DontEnum); |
|
204 putDirect(exec->propertyNames().prototype, prototype, DontDelete); |
|
205 location = getDirectLocation(propertyName); |
|
206 } |
|
207 |
|
208 slot.setValueSlot(this, location, offsetForLocation(location)); |
|
209 } |
|
210 |
|
211 if (propertyName == exec->propertyNames().arguments) { |
|
212 slot.setCacheableCustom(this, argumentsGetter); |
|
213 return true; |
|
214 } |
|
215 |
|
216 if (propertyName == exec->propertyNames().length) { |
|
217 slot.setCacheableCustom(this, lengthGetter); |
|
218 return true; |
|
219 } |
|
220 |
|
221 if (propertyName == exec->propertyNames().caller) { |
|
222 slot.setCacheableCustom(this, callerGetter); |
|
223 return true; |
|
224 } |
|
225 |
|
226 return Base::getOwnPropertySlot(exec, propertyName, slot); |
|
227 } |
|
228 |
|
229 bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) |
|
230 { |
|
231 if (isHostFunction()) |
|
232 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); |
|
233 |
|
234 if (propertyName == exec->propertyNames().prototype) { |
|
235 PropertySlot slot; |
|
236 getOwnPropertySlot(exec, propertyName, slot); |
|
237 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); |
|
238 } |
|
239 |
|
240 if (propertyName == exec->propertyNames().arguments) { |
|
241 descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete); |
|
242 return true; |
|
243 } |
|
244 |
|
245 if (propertyName == exec->propertyNames().length) { |
|
246 descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete); |
|
247 return true; |
|
248 } |
|
249 |
|
250 if (propertyName == exec->propertyNames().caller) { |
|
251 descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete); |
|
252 return true; |
|
253 } |
|
254 |
|
255 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); |
|
256 } |
|
257 |
|
258 void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) |
|
259 { |
|
260 if (!isHostFunction() && (mode == IncludeDontEnumProperties)) { |
|
261 propertyNames.add(exec->propertyNames().arguments); |
|
262 propertyNames.add(exec->propertyNames().callee); |
|
263 propertyNames.add(exec->propertyNames().caller); |
|
264 propertyNames.add(exec->propertyNames().length); |
|
265 } |
|
266 Base::getOwnPropertyNames(exec, propertyNames, mode); |
|
267 } |
|
268 |
|
269 void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
|
270 { |
|
271 if (isHostFunction()) { |
|
272 Base::put(exec, propertyName, value, slot); |
|
273 return; |
|
274 } |
|
275 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) |
|
276 return; |
|
277 Base::put(exec, propertyName, value, slot); |
|
278 } |
|
279 |
|
280 bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName) |
|
281 { |
|
282 if (isHostFunction()) |
|
283 return Base::deleteProperty(exec, propertyName); |
|
284 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) |
|
285 return false; |
|
286 return Base::deleteProperty(exec, propertyName); |
|
287 } |
|
288 |
|
289 // ECMA 13.2.2 [[Construct]] |
|
290 ConstructType JSFunction::getConstructData(ConstructData& constructData) |
|
291 { |
|
292 if (isHostFunction()) |
|
293 return ConstructTypeNone; |
|
294 constructData.js.functionExecutable = jsExecutable(); |
|
295 constructData.js.scopeChain = scope().node(); |
|
296 return ConstructTypeJS; |
|
297 } |
|
298 |
|
299 } // namespace JSC |