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 "GetterSetter.h" 34#include "JSArray.h" 35#include "JSGlobalObject.h" 36#include "JSNotAnObject.h" 37#include "Interpreter.h" 38#include "ObjectConstructor.h" 39#include "ObjectPrototype.h" 40#include "Operations.h" 41#include "Parser.h" 42#include "PropertyNameArray.h" 43 44using namespace WTF; 45using namespace Unicode; 46 47namespace JSC { 48EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) 49{ 50 return throwVMError(exec, createNotAConstructorError(exec, exec->callee())); 51} 52 53const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) }; 54 55bool JSFunction::isHostFunctionNonInline() const 56{ 57 return isHostFunction(); 58} 59 60JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor) 61{ 62 NativeExecutable* executable; 63#if !ENABLE(JIT) 64 UNUSED_PARAM(intrinsic); 65#else 66 if (intrinsic != NoIntrinsic && exec->vm().canUseJIT()) { 67 ASSERT(nativeConstructor == callHostFunctionAsConstructor); 68 executable = exec->vm().getHostFunction(nativeFunction, intrinsic); 69 } else 70#endif 71 executable = exec->vm().getHostFunction(nativeFunction, nativeConstructor); 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; 77} 78 79void JSFunction::destroy(JSCell* cell) 80{ 81 static_cast<JSFunction*>(cell)->JSFunction::~JSFunction(); 82} 83 84JSFunction::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) 98{ 99} 100 101void JSFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const String& name) 102{ 103 Base::finishCreation(exec->vm()); 104 ASSERT(inherits(&s_info)); 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); 108} 109 110ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity) 111{ 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; 118} 119 120String JSFunction::name(ExecState* exec) 121{ 122 return get(exec, exec->vm().propertyNames->name).toWTFString(exec); 123} 124 125String JSFunction::displayName(ExecState* exec) 126{ 127 JSValue displayName = getDirect(exec->vm(), exec->vm().propertyNames->displayName); 128 129 if (displayName && isJSString(displayName)) 130 return asString(displayName)->tryGetValue(); 131 132 return String(); 133} 134 135const String JSFunction::calculatedDisplayName(ExecState* exec) 136{ 137 const String explicitName = displayName(exec); 138 139 if (!explicitName.isEmpty()) 140 return explicitName; 141 142 const String actualName = name(exec); 143 if (!actualName.isEmpty() || isHostFunction()) 144 return actualName; 145 146 return jsExecutable()->inferredName().string(); 147} 148 149const SourceCode* JSFunction::sourceCode() const 150{ 151 if (isHostFunction()) 152 return 0; 153 return &jsExecutable()->source(); 154} 155 156void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor) 157{ 158 JSFunction* thisObject = jsCast<JSFunction*>(cell); 159 ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); 160 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 161 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 162 Base::visitChildren(thisObject, visitor); 163 164 visitor.append(&thisObject->m_scope); 165 visitor.append(&thisObject->m_executable); 166 thisObject->m_allocationProfile.visitAggregate(visitor); 167} 168 169CallType JSFunction::getCallData(JSCell* cell, CallData& callData) 170{ 171 JSFunction* thisObject = jsCast<JSFunction*>(cell); 172 if (thisObject->isHostFunction()) { 173 callData.native.function = thisObject->nativeFunction(); 174 return CallTypeHost; 175 } 176 callData.js.functionExecutable = thisObject->jsExecutable(); 177 callData.js.scope = thisObject->scope(); 178 return CallTypeJS; 179} 180 181JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, PropertyName) 182{ 183 JSFunction* thisObj = jsCast<JSFunction*>(slotBase); 184 ASSERT(!thisObj->isHostFunction()); 185 return exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObj); 186} 187 188JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, PropertyName) 189{ 190 JSFunction* thisObj = jsCast<JSFunction*>(slotBase); 191 ASSERT(!thisObj->isHostFunction()); 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; 200 return throwTypeError(exec, ASCIILiteral("Function.caller used to retrieve strict caller")); 201} 202 203JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, PropertyName) 204{ 205 JSFunction* thisObj = jsCast<JSFunction*>(slotBase); 206 ASSERT(!thisObj->isHostFunction()); 207 return jsNumber(thisObj->jsExecutable()->parameterCount()); 208} 209 210JSValue JSFunction::nameGetter(ExecState*, JSValue slotBase, PropertyName) 211{ 212 JSFunction* thisObj = jsCast<JSFunction*>(slotBase); 213 ASSERT(!thisObj->isHostFunction()); 214 return thisObj->jsExecutable()->nameValue(); 215} 216 217bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) 218{ 219 JSFunction* thisObject = jsCast<JSFunction*>(cell); 220 if (thisObject->isHostFunction()) 221 return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); 222 223 if (propertyName == exec->propertyNames().prototype) { 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)); 232 } 233 234 slot.setValue(thisObject, thisObject->getDirect(offset), offset); 235 } 236 237 if (propertyName == exec->propertyNames().arguments) { 238 if (thisObject->jsExecutable()->isStrictMode()) { 239 bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); 240 if (!result) { 241 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); 242 result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); 243 ASSERT(result); 244 } 245 return result; 246 } 247 slot.setCacheableCustom(thisObject, argumentsGetter); 248 return true; 249 } 250 251 if (propertyName == exec->propertyNames().length) { 252 slot.setCacheableCustom(thisObject, lengthGetter); 253 return true; 254 } 255 256 if (propertyName == exec->propertyNames().name) { 257 slot.setCacheableCustom(thisObject, nameGetter); 258 return true; 259 } 260 261 if (propertyName == exec->propertyNames().caller) { 262 if (thisObject->jsExecutable()->isStrictMode()) { 263 bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); 264 if (!result) { 265 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); 266 result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); 267 ASSERT(result); 268 } 269 return result; 270 } 271 slot.setCacheableCustom(thisObject, callerGetter); 272 return true; 273 } 274 275 return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); 276} 277 278bool JSFunction::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) 279{ 280 JSFunction* thisObject = jsCast<JSFunction*>(object); 281 if (thisObject->isHostFunction()) 282 return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); 283 284 if (propertyName == exec->propertyNames().prototype) { 285 PropertySlot slot; 286 thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); 287 return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); 288 } 289 290 if (propertyName == exec->propertyNames().arguments) { 291 if (thisObject->jsExecutable()->isStrictMode()) { 292 bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); 293 if (!result) { 294 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); 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); 301 return true; 302 } 303 304 if (propertyName == exec->propertyNames().length) { 305 descriptor.setDescriptor(jsNumber(thisObject->jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete); 306 return true; 307 } 308 309 if (propertyName == exec->propertyNames().name) { 310 descriptor.setDescriptor(thisObject->jsExecutable()->nameValue(), ReadOnly | DontEnum | DontDelete); 311 return true; 312 } 313 314 if (propertyName == exec->propertyNames().caller) { 315 if (thisObject->jsExecutable()->isStrictMode()) { 316 bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); 317 if (!result) { 318 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); 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); 325 return true; 326 } 327 328 return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); 329} 330 331void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 332{ 333 JSFunction* thisObject = jsCast<JSFunction*>(object); 334 if (!thisObject->isHostFunction() && (mode == IncludeDontEnumProperties)) { 335 // Make sure prototype has been reified. 336 PropertySlot slot; 337 thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, exec->propertyNames().prototype, slot); 338 339 propertyNames.add(exec->propertyNames().arguments); 340 propertyNames.add(exec->propertyNames().caller); 341 propertyNames.add(exec->propertyNames().length); 342 propertyNames.add(exec->propertyNames().name); 343 } 344 Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); 345} 346 347void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 348{ 349 JSFunction* thisObject = jsCast<JSFunction*>(cell); 350 if (thisObject->isHostFunction()) { 351 Base::put(thisObject, exec, propertyName, value, slot); 352 return; 353 } 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; 358 thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); 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; 365 } 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; 372 } 373 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().name || propertyName == exec->propertyNames().caller) { 374 if (slot.isStrictMode()) 375 throwTypeError(exec, StrictModeReadonlyPropertyWriteError); 376 return; 377 } 378 Base::put(thisObject, exec, propertyName, value, slot); 379} 380 381bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) 382{ 383 JSFunction* thisObject = jsCast<JSFunction*>(cell); 384 // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty. 385 if (!thisObject->isHostFunction() && !exec->vm().isInDefineOwnProperty() 386 && (propertyName == exec->propertyNames().arguments 387 || propertyName == exec->propertyNames().length 388 || propertyName == exec->propertyNames().name 389 || propertyName == exec->propertyNames().prototype 390 || propertyName == exec->propertyNames().caller)) 391 return false; 392 return Base::deleteProperty(thisObject, exec, propertyName); 393} 394 395bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException) 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); 406 thisObject->m_allocationProfile.clear(); 407 thisObject->m_allocationProfileWatchpoint.notifyWrite(); 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)) 415 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); 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)) 422 thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); 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())); 428 else if (propertyName == exec->propertyNames().name) 429 valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), thisObject->jsExecutable()->nameValue()); 430 else 431 return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); 432 433 if (descriptor.configurablePresent() && descriptor.configurable()) { 434 if (throwException) 435 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); 436 return false; 437 } 438 if (descriptor.enumerablePresent() && descriptor.enumerable()) { 439 if (throwException) 440 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property."))); 441 return false; 442 } 443 if (descriptor.isAccessorDescriptor()) { 444 if (throwException) 445 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property."))); 446 return false; 447 } 448 if (descriptor.writablePresent() && descriptor.writable()) { 449 if (throwException) 450 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property."))); 451 return false; 452 } 453 if (!valueCheck) { 454 if (throwException) 455 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property."))); 456 return false; 457 } 458 return true; 459} 460 461// ECMA 13.2.2 [[Construct]] 462ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData) 463{ 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(); 470 constructData.js.scope = thisObject->scope(); 471 return ConstructTypeJS; 472} 473 474String getCalculatedDisplayName(CallFrame* callFrame, JSObject* object) 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); 480 return ""; 481} 482 483} // namespace JSC 484