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