]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
f9bf01c6 | 4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. |
9dae56ea A |
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" | |
14957cd0 | 31 | #include "ExceptionHelpers.h" |
9dae56ea | 32 | #include "FunctionPrototype.h" |
6fe7ccc8 A |
33 | #include "GetterSetter.h" |
34 | #include "JSArray.h" | |
9dae56ea | 35 | #include "JSGlobalObject.h" |
14957cd0 | 36 | #include "JSNotAnObject.h" |
9dae56ea | 37 | #include "Interpreter.h" |
93a37866 | 38 | #include "ObjectConstructor.h" |
9dae56ea | 39 | #include "ObjectPrototype.h" |
93a37866 | 40 | #include "Operations.h" |
9dae56ea A |
41 | #include "Parser.h" |
42 | #include "PropertyNameArray.h" | |
9dae56ea A |
43 | |
44 | using namespace WTF; | |
45 | using namespace Unicode; | |
46 | ||
47 | namespace JSC { | |
14957cd0 A |
48 | EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) |
49 | { | |
50 | return throwVMError(exec, createNotAConstructorError(exec, exec->callee())); | |
51 | } | |
9dae56ea | 52 | |
6fe7ccc8 | 53 | const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) }; |
9dae56ea | 54 | |
f9bf01c6 A |
55 | bool JSFunction::isHostFunctionNonInline() const |
56 | { | |
57 | return isHostFunction(); | |
58 | } | |
59 | ||
93a37866 | 60 | JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) |
f9bf01c6 | 61 | { |
6fe7ccc8 A |
62 | NativeExecutable* executable; |
63 | #if !ENABLE(JIT) | |
64 | UNUSED_PARAM(intrinsic); | |
65 | #else | |
93a37866 | 66 | if (intrinsic != NoIntrinsic && exec->vm().canUseJIT()) { |
6fe7ccc8 | 67 | ASSERT(nativeConstructor == callHostFunctionAsConstructor); |
93a37866 | 68 | executable = exec->vm().getHostFunction(nativeFunction, intrinsic); |
6fe7ccc8 A |
69 | } else |
70 | #endif | |
93a37866 | 71 | executable = exec->vm().getHostFunction(nativeFunction, nativeConstructor); |
6fe7ccc8 A |
72 | |
73 | JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure()); | |
74 | // Can't do this during initialization because getHostFunction might do a GC allocation. | |
75 | function->finishCreation(exec, executable, length, name); | |
76 | return function; | |
f9bf01c6 A |
77 | } |
78 | ||
93a37866 | 79 | void JSFunction::destroy(JSCell* cell) |
ba379fdc | 80 | { |
93a37866 | 81 | static_cast<JSFunction*>(cell)->JSFunction::~JSFunction(); |
ba379fdc A |
82 | } |
83 | ||
93a37866 A |
84 | JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) |
85 | : Base(exec->vm(), structure) | |
86 | , m_executable() | |
87 | , m_scope(exec->vm(), this, globalObject) | |
88 | // We initialize blind so that changes to the prototype after function creation but before | |
89 | // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the | |
90 | // watchpoint will start watching and any changes will both force deoptimization and disable | |
91 | // future attempts to optimize. This is necessary because we are guaranteed that the | |
92 | // allocation profile is changed exactly once prior to optimizations kicking in. We could be | |
93 | // smarter and count the number of times the prototype is clobbered and only optimize if it | |
94 | // was clobbered exactly once, but that seems like overkill. In almost all cases it will be | |
95 | // clobbered once, and if it's clobbered more than once, that will probably only occur | |
96 | // before we started optimizing, anyway. | |
97 | , m_allocationProfileWatchpoint(InitializedBlind) | |
9dae56ea A |
98 | { |
99 | } | |
100 | ||
93a37866 | 101 | void JSFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const String& name) |
9dae56ea | 102 | { |
93a37866 | 103 | Base::finishCreation(exec->vm()); |
6fe7ccc8 | 104 | ASSERT(inherits(&s_info)); |
93a37866 A |
105 | m_executable.set(exec->vm(), this, executable); |
106 | putDirect(exec->vm(), exec->vm().propertyNames->name, jsString(exec, name), DontDelete | ReadOnly | DontEnum); | |
107 | putDirect(exec->vm(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum); | |
14957cd0 | 108 | } |
f9bf01c6 | 109 | |
93a37866 | 110 | ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity) |
14957cd0 | 111 | { |
93a37866 A |
112 | VM& vm = exec->vm(); |
113 | JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype)); | |
114 | if (!prototype) | |
115 | prototype = globalObject()->objectPrototype(); | |
116 | m_allocationProfile.initialize(globalObject()->vm(), this, prototype, inlineCapacity); | |
117 | return &m_allocationProfile; | |
9dae56ea A |
118 | } |
119 | ||
93a37866 | 120 | String JSFunction::name(ExecState* exec) |
9dae56ea | 121 | { |
93a37866 | 122 | return get(exec, exec->vm().propertyNames->name).toWTFString(exec); |
14957cd0 A |
123 | } |
124 | ||
93a37866 | 125 | String JSFunction::displayName(ExecState* exec) |
14957cd0 | 126 | { |
93a37866 | 127 | JSValue displayName = getDirect(exec->vm(), exec->vm().propertyNames->displayName); |
14957cd0 | 128 | |
6fe7ccc8 | 129 | if (displayName && isJSString(displayName)) |
14957cd0 A |
130 | return asString(displayName)->tryGetValue(); |
131 | ||
93a37866 | 132 | return String(); |
14957cd0 A |
133 | } |
134 | ||
93a37866 | 135 | const String JSFunction::calculatedDisplayName(ExecState* exec) |
14957cd0 | 136 | { |
93a37866 | 137 | const String explicitName = displayName(exec); |
14957cd0 A |
138 | |
139 | if (!explicitName.isEmpty()) | |
140 | return explicitName; | |
141 | ||
93a37866 | 142 | const String actualName = name(exec); |
6fe7ccc8 A |
143 | if (!actualName.isEmpty() || isHostFunction()) |
144 | return actualName; | |
145 | ||
93a37866 | 146 | return jsExecutable()->inferredName().string(); |
6fe7ccc8 A |
147 | } |
148 | ||
149 | const SourceCode* JSFunction::sourceCode() const | |
150 | { | |
151 | if (isHostFunction()) | |
152 | return 0; | |
153 | return &jsExecutable()->source(); | |
14957cd0 A |
154 | } |
155 | ||
6fe7ccc8 | 156 | void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) |
14957cd0 | 157 | { |
6fe7ccc8 A |
158 | JSFunction* thisObject = jsCast<JSFunction*>(cell); |
159 | ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); | |
14957cd0 | 160 | COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); |
6fe7ccc8 A |
161 | ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); |
162 | Base::visitChildren(thisObject, visitor); | |
14957cd0 | 163 | |
93a37866 A |
164 | visitor.append(&thisObject->m_scope); |
165 | visitor.append(&thisObject->m_executable); | |
166 | thisObject->m_allocationProfile.visitAggregate(visitor); | |
9dae56ea A |
167 | } |
168 | ||
6fe7ccc8 | 169 | CallType JSFunction::getCallData(JSCell* cell, CallData& callData) |
9dae56ea | 170 | { |
6fe7ccc8 A |
171 | JSFunction* thisObject = jsCast<JSFunction*>(cell); |
172 | if (thisObject->isHostFunction()) { | |
173 | callData.native.function = thisObject->nativeFunction(); | |
ba379fdc A |
174 | return CallTypeHost; |
175 | } | |
6fe7ccc8 | 176 | callData.js.functionExecutable = thisObject->jsExecutable(); |
93a37866 | 177 | callData.js.scope = thisObject->scope(); |
9dae56ea A |
178 | return CallTypeJS; |
179 | } | |
180 | ||
93a37866 | 181 | JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 182 | { |
6fe7ccc8 | 183 | JSFunction* thisObj = jsCast<JSFunction*>(slotBase); |
ba379fdc | 184 | ASSERT(!thisObj->isHostFunction()); |
6fe7ccc8 | 185 | return exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObj); |
9dae56ea A |
186 | } |
187 | ||
93a37866 | 188 | JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, PropertyName) |
9dae56ea | 189 | { |
6fe7ccc8 | 190 | JSFunction* thisObj = jsCast<JSFunction*>(slotBase); |
ba379fdc | 191 | ASSERT(!thisObj->isHostFunction()); |
6fe7ccc8 A |
192 | JSValue caller = exec->interpreter()->retrieveCallerFromVMCode(exec, thisObj); |
193 | ||
194 | // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller. | |
195 | if (!caller.isObject() || !asObject(caller)->inherits(&JSFunction::s_info)) | |
196 | return caller; | |
197 | JSFunction* function = jsCast<JSFunction*>(caller); | |
198 | if (function->isHostFunction() || !function->jsExecutable()->isStrictMode()) | |
199 | return caller; | |
93a37866 | 200 | return throwTypeError(exec, ASCIILiteral("Function.caller used to retrieve strict caller")); |
9dae56ea A |
201 | } |
202 | ||
93a37866 | 203 | JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, PropertyName) |
9dae56ea | 204 | { |
6fe7ccc8 | 205 | JSFunction* thisObj = jsCast<JSFunction*>(slotBase); |
ba379fdc | 206 | ASSERT(!thisObj->isHostFunction()); |
14957cd0 A |
207 | return jsNumber(thisObj->jsExecutable()->parameterCount()); |
208 | } | |
209 | ||
93a37866 A |
210 | JSValue JSFunction::nameGetter(ExecState*, JSValue slotBase, PropertyName) |
211 | { | |
212 | JSFunction* thisObj = jsCast<JSFunction*>(slotBase); | |
213 | ASSERT(!thisObj->isHostFunction()); | |
214 | return thisObj->jsExecutable()->nameValue(); | |
215 | } | |
216 | ||
217 | bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) | |
14957cd0 | 218 | { |
6fe7ccc8 A |
219 | JSFunction* thisObject = jsCast<JSFunction*>(cell); |
220 | if (thisObject->isHostFunction()) | |
221 | return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); | |
ba379fdc | 222 | |
9dae56ea | 223 | if (propertyName == exec->propertyNames().prototype) { |
93a37866 A |
224 | VM& vm = exec->vm(); |
225 | PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName); | |
226 | if (!isValidOffset(offset)) { | |
227 | JSObject* prototype = constructEmptyObject(exec); | |
228 | prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum); | |
229 | thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum); | |
230 | offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype); | |
231 | ASSERT(isValidOffset(offset)); | |
6fe7ccc8 | 232 | } |
9dae56ea | 233 | |
93a37866 | 234 | slot.setValue(thisObject, thisObject->getDirect(offset), offset); |
9dae56ea A |
235 | } |
236 | ||
237 | if (propertyName == exec->propertyNames().arguments) { | |
6fe7ccc8 A |
238 | if (thisObject->jsExecutable()->isStrictMode()) { |
239 | bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); | |
240 | if (!result) { | |
93a37866 | 241 | thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); |
6fe7ccc8 A |
242 | result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
243 | ASSERT(result); | |
244 | } | |
245 | return result; | |
14957cd0 | 246 | } |
6fe7ccc8 | 247 | slot.setCacheableCustom(thisObject, argumentsGetter); |
9dae56ea A |
248 | return true; |
249 | } | |
250 | ||
251 | if (propertyName == exec->propertyNames().length) { | |
6fe7ccc8 | 252 | slot.setCacheableCustom(thisObject, lengthGetter); |
9dae56ea A |
253 | return true; |
254 | } | |
255 | ||
93a37866 A |
256 | if (propertyName == exec->propertyNames().name) { |
257 | slot.setCacheableCustom(thisObject, nameGetter); | |
258 | return true; | |
259 | } | |
260 | ||
9dae56ea | 261 | if (propertyName == exec->propertyNames().caller) { |
6fe7ccc8 A |
262 | if (thisObject->jsExecutable()->isStrictMode()) { |
263 | bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); | |
264 | if (!result) { | |
93a37866 | 265 | thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); |
6fe7ccc8 A |
266 | result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
267 | ASSERT(result); | |
268 | } | |
269 | return result; | |
14957cd0 | 270 | } |
6fe7ccc8 | 271 | slot.setCacheableCustom(thisObject, callerGetter); |
9dae56ea A |
272 | return true; |
273 | } | |
274 | ||
6fe7ccc8 | 275 | return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
9dae56ea A |
276 | } |
277 | ||
93a37866 | 278 | bool JSFunction::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) |
14957cd0 | 279 | { |
6fe7ccc8 A |
280 | JSFunction* thisObject = jsCast<JSFunction*>(object); |
281 | if (thisObject->isHostFunction()) | |
282 | return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); | |
14957cd0 A |
283 | |
284 | if (propertyName == exec->propertyNames().prototype) { | |
285 | PropertySlot slot; | |
6fe7ccc8 A |
286 | thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); |
287 | return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); | |
14957cd0 A |
288 | } |
289 | ||
290 | if (propertyName == exec->propertyNames().arguments) { | |
6fe7ccc8 A |
291 | if (thisObject->jsExecutable()->isStrictMode()) { |
292 | bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); | |
293 | if (!result) { | |
93a37866 | 294 | thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); |
6fe7ccc8 A |
295 | result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); |
296 | ASSERT(result); | |
297 | } | |
298 | return result; | |
299 | } | |
300 | descriptor.setDescriptor(exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete); | |
14957cd0 A |
301 | return true; |
302 | } | |
303 | ||
304 | if (propertyName == exec->propertyNames().length) { | |
6fe7ccc8 | 305 | descriptor.setDescriptor(jsNumber(thisObject->jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete); |
14957cd0 A |
306 | return true; |
307 | } | |
308 | ||
93a37866 A |
309 | if (propertyName == exec->propertyNames().name) { |
310 | descriptor.setDescriptor(thisObject->jsExecutable()->nameValue(), ReadOnly | DontEnum | DontDelete); | |
311 | return true; | |
312 | } | |
313 | ||
14957cd0 | 314 | if (propertyName == exec->propertyNames().caller) { |
6fe7ccc8 A |
315 | if (thisObject->jsExecutable()->isStrictMode()) { |
316 | bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); | |
317 | if (!result) { | |
93a37866 | 318 | thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); |
6fe7ccc8 A |
319 | result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); |
320 | ASSERT(result); | |
321 | } | |
322 | return result; | |
323 | } | |
324 | descriptor.setDescriptor(exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject), ReadOnly | DontEnum | DontDelete); | |
14957cd0 | 325 | return true; |
f9bf01c6 A |
326 | } |
327 | ||
6fe7ccc8 | 328 | return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); |
14957cd0 A |
329 | } |
330 | ||
93a37866 | 331 | void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) |
f9bf01c6 | 332 | { |
6fe7ccc8 A |
333 | JSFunction* thisObject = jsCast<JSFunction*>(object); |
334 | if (!thisObject->isHostFunction() && (mode == IncludeDontEnumProperties)) { | |
14957cd0 A |
335 | // Make sure prototype has been reified. |
336 | PropertySlot slot; | |
6fe7ccc8 | 337 | thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, exec->propertyNames().prototype, slot); |
14957cd0 | 338 | |
f9bf01c6 | 339 | propertyNames.add(exec->propertyNames().arguments); |
f9bf01c6 A |
340 | propertyNames.add(exec->propertyNames().caller); |
341 | propertyNames.add(exec->propertyNames().length); | |
93a37866 | 342 | propertyNames.add(exec->propertyNames().name); |
f9bf01c6 | 343 | } |
93a37866 | 344 | Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); |
f9bf01c6 A |
345 | } |
346 | ||
93a37866 | 347 | void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) |
9dae56ea | 348 | { |
6fe7ccc8 A |
349 | JSFunction* thisObject = jsCast<JSFunction*>(cell); |
350 | if (thisObject->isHostFunction()) { | |
351 | Base::put(thisObject, exec, propertyName, value, slot); | |
ba379fdc A |
352 | return; |
353 | } | |
14957cd0 A |
354 | if (propertyName == exec->propertyNames().prototype) { |
355 | // Make sure prototype has been reified, such that it can only be overwritten | |
356 | // following the rules set out in ECMA-262 8.12.9. | |
357 | PropertySlot slot; | |
6fe7ccc8 | 358 | thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); |
93a37866 A |
359 | thisObject->m_allocationProfile.clear(); |
360 | thisObject->m_allocationProfileWatchpoint.notifyWrite(); | |
361 | // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile. | |
362 | PutPropertySlot dontCache; | |
363 | Base::put(thisObject, exec, propertyName, value, dontCache); | |
364 | return; | |
14957cd0 | 365 | } |
6fe7ccc8 A |
366 | if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) { |
367 | // This will trigger the property to be reified, if this is not already the case! | |
368 | bool okay = thisObject->hasProperty(exec, propertyName); | |
369 | ASSERT_UNUSED(okay, okay); | |
370 | Base::put(thisObject, exec, propertyName, value, slot); | |
371 | return; | |
14957cd0 | 372 | } |
93a37866 | 373 | if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().name || propertyName == exec->propertyNames().caller) { |
6fe7ccc8 A |
374 | if (slot.isStrictMode()) |
375 | throwTypeError(exec, StrictModeReadonlyPropertyWriteError); | |
9dae56ea | 376 | return; |
6fe7ccc8 A |
377 | } |
378 | Base::put(thisObject, exec, propertyName, value, slot); | |
9dae56ea A |
379 | } |
380 | ||
93a37866 | 381 | bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) |
9dae56ea | 382 | { |
6fe7ccc8 A |
383 | JSFunction* thisObject = jsCast<JSFunction*>(cell); |
384 | // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty. | |
93a37866 | 385 | if (!thisObject->isHostFunction() && !exec->vm().isInDefineOwnProperty() |
6fe7ccc8 A |
386 | && (propertyName == exec->propertyNames().arguments |
387 | || propertyName == exec->propertyNames().length | |
93a37866 | 388 | || propertyName == exec->propertyNames().name |
6fe7ccc8 A |
389 | || propertyName == exec->propertyNames().prototype |
390 | || propertyName == exec->propertyNames().caller)) | |
391 | return false; | |
392 | return Base::deleteProperty(thisObject, exec, propertyName); | |
393 | } | |
394 | ||
93a37866 | 395 | bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException) |
6fe7ccc8 A |
396 | { |
397 | JSFunction* thisObject = jsCast<JSFunction*>(object); | |
398 | if (thisObject->isHostFunction()) | |
399 | return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); | |
400 | ||
401 | if (propertyName == exec->propertyNames().prototype) { | |
402 | // Make sure prototype has been reified, such that it can only be overwritten | |
403 | // following the rules set out in ECMA-262 8.12.9. | |
404 | PropertySlot slot; | |
405 | thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); | |
93a37866 A |
406 | thisObject->m_allocationProfile.clear(); |
407 | thisObject->m_allocationProfileWatchpoint.notifyWrite(); | |
6fe7ccc8 A |
408 | return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); |
409 | } | |
410 | ||
411 | bool valueCheck; | |
412 | if (propertyName == exec->propertyNames().arguments) { | |
413 | if (thisObject->jsExecutable()->isStrictMode()) { | |
414 | if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor)) | |
93a37866 | 415 | thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); |
6fe7ccc8 A |
416 | return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); |
417 | } | |
418 | valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject)); | |
419 | } else if (propertyName == exec->propertyNames().caller) { | |
420 | if (thisObject->jsExecutable()->isStrictMode()) { | |
421 | if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor)) | |
93a37866 | 422 | thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); |
6fe7ccc8 A |
423 | return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); |
424 | } | |
425 | valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject)); | |
426 | } else if (propertyName == exec->propertyNames().length) | |
427 | valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount())); | |
93a37866 A |
428 | else if (propertyName == exec->propertyNames().name) |
429 | valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), thisObject->jsExecutable()->nameValue()); | |
6fe7ccc8 A |
430 | else |
431 | return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); | |
432 | ||
433 | if (descriptor.configurablePresent() && descriptor.configurable()) { | |
434 | if (throwException) | |
93a37866 | 435 | throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); |
6fe7ccc8 A |
436 | return false; |
437 | } | |
438 | if (descriptor.enumerablePresent() && descriptor.enumerable()) { | |
439 | if (throwException) | |
93a37866 | 440 | throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property."))); |
6fe7ccc8 A |
441 | return false; |
442 | } | |
443 | if (descriptor.isAccessorDescriptor()) { | |
444 | if (throwException) | |
93a37866 | 445 | throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property."))); |
6fe7ccc8 A |
446 | return false; |
447 | } | |
448 | if (descriptor.writablePresent() && descriptor.writable()) { | |
449 | if (throwException) | |
93a37866 | 450 | throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property."))); |
9dae56ea | 451 | return false; |
6fe7ccc8 A |
452 | } |
453 | if (!valueCheck) { | |
454 | if (throwException) | |
93a37866 | 455 | throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property."))); |
6fe7ccc8 A |
456 | return false; |
457 | } | |
458 | return true; | |
9dae56ea A |
459 | } |
460 | ||
461 | // ECMA 13.2.2 [[Construct]] | |
6fe7ccc8 | 462 | ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData) |
9dae56ea | 463 | { |
6fe7ccc8 A |
464 | JSFunction* thisObject = jsCast<JSFunction*>(cell); |
465 | if (thisObject->isHostFunction()) { | |
466 | constructData.native.function = thisObject->nativeConstructor(); | |
467 | return ConstructTypeHost; | |
468 | } | |
469 | constructData.js.functionExecutable = thisObject->jsExecutable(); | |
93a37866 | 470 | constructData.js.scope = thisObject->scope(); |
9dae56ea A |
471 | return ConstructTypeJS; |
472 | } | |
6fe7ccc8 | 473 | |
93a37866 | 474 | String getCalculatedDisplayName(CallFrame* callFrame, JSObject* object) |
6fe7ccc8 A |
475 | { |
476 | if (JSFunction* function = jsDynamicCast<JSFunction*>(object)) | |
477 | return function->calculatedDisplayName(callFrame); | |
478 | if (InternalFunction* function = jsDynamicCast<InternalFunction*>(object)) | |
479 | return function->calculatedDisplayName(callFrame); | |
93a37866 | 480 | return ""; |
6fe7ccc8 | 481 | } |
9dae56ea | 482 | |
9dae56ea | 483 | } // namespace JSC |