1/* 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "APICast.h" 28#include "Error.h" 29#include "ExceptionHelpers.h" 30#include "JSCallbackFunction.h" 31#include "JSClassRef.h" 32#include "JSFunction.h" 33#include "JSGlobalObject.h" 34#include "JSLock.h" 35#include "JSObjectRef.h" 36#include "JSString.h" 37#include "JSStringRef.h" 38#include "OpaqueJSString.h" 39#include "PropertyNameArray.h" 40#include <wtf/Vector.h> 41 42namespace JSC { 43 44template <class Parent> 45inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(JSValue value) 46{ 47 ASSERT(asObject(value)->inherits(info())); 48 return jsCast<JSCallbackObject*>(asObject(value)); 49} 50 51template <class Parent> 52inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(EncodedJSValue value) 53{ 54 ASSERT(asObject(JSValue::decode(value))->inherits(info())); 55 return jsCast<JSCallbackObject*>(asObject(JSValue::decode(value))); 56} 57 58template <class Parent> 59JSCallbackObject<Parent>::JSCallbackObject(ExecState* exec, Structure* structure, JSClassRef jsClass, void* data) 60 : Parent(exec->vm(), structure) 61 , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) 62{ 63} 64 65// Global object constructor. 66// FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. 67template <class Parent> 68JSCallbackObject<Parent>::JSCallbackObject(VM& vm, JSClassRef jsClass, Structure* structure) 69 : Parent(vm, structure) 70 , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) 71{ 72} 73 74template <class Parent> 75void JSCallbackObject<Parent>::finishCreation(ExecState* exec) 76{ 77 Base::finishCreation(exec->vm()); 78 ASSERT(Parent::inherits(info())); 79 init(exec); 80} 81 82// This is just for Global object, so we can assume that Base::finishCreation is JSGlobalObject::finishCreation. 83template <class Parent> 84void JSCallbackObject<Parent>::finishCreation(VM& vm) 85{ 86 ASSERT(Parent::inherits(info())); 87 ASSERT(Parent::isGlobalObject()); 88 Base::finishCreation(vm); 89 init(jsCast<JSGlobalObject*>(this)->globalExec()); 90} 91 92template <class Parent> 93void JSCallbackObject<Parent>::init(ExecState* exec) 94{ 95 ASSERT(exec); 96 97 Vector<JSObjectInitializeCallback, 16> initRoutines; 98 JSClassRef jsClass = classRef(); 99 do { 100 if (JSObjectInitializeCallback initialize = jsClass->initialize) 101 initRoutines.append(initialize); 102 } while ((jsClass = jsClass->parentClass)); 103 104 // initialize from base to derived 105 for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { 106 JSLock::DropAllLocks dropAllLocks(exec); 107 JSObjectInitializeCallback initialize = initRoutines[i]; 108 initialize(toRef(exec), toRef(this)); 109 } 110 111 for (JSClassRef jsClassPtr = classRef(); jsClassPtr; jsClassPtr = jsClassPtr->parentClass) { 112 if (jsClassPtr->finalize) { 113 WeakSet::allocate(this, m_callbackObjectData.get(), classRef()); 114 break; 115 } 116 } 117} 118 119template <class Parent> 120String JSCallbackObject<Parent>::className(const JSObject* object) 121{ 122 const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object); 123 String thisClassName = thisObject->classRef()->className(); 124 if (!thisClassName.isEmpty()) 125 return thisClassName; 126 127 return Parent::className(object); 128} 129 130template <class Parent> 131bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) 132{ 133 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); 134 JSContextRef ctx = toRef(exec); 135 JSObjectRef thisRef = toRef(thisObject); 136 RefPtr<OpaqueJSString> propertyNameRef; 137 138 if (StringImpl* name = propertyName.uid()) { 139 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 140 // optional optimization to bypass getProperty in cases when we only need to know if the property exists 141 if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { 142 if (!propertyNameRef) 143 propertyNameRef = OpaqueJSString::create(name); 144 JSLock::DropAllLocks dropAllLocks(exec); 145 if (hasProperty(ctx, thisRef, propertyNameRef.get())) { 146 slot.setCustom(thisObject, ReadOnly | DontEnum, callbackGetter); 147 return true; 148 } 149 } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { 150 if (!propertyNameRef) 151 propertyNameRef = OpaqueJSString::create(name); 152 JSValueRef exception = 0; 153 JSValueRef value; 154 { 155 JSLock::DropAllLocks dropAllLocks(exec); 156 value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); 157 } 158 if (exception) { 159 exec->vm().throwException(exec, toJS(exec, exception)); 160 slot.setValue(thisObject, ReadOnly | DontEnum, jsUndefined()); 161 return true; 162 } 163 if (value) { 164 slot.setValue(thisObject, ReadOnly | DontEnum, toJS(exec, value)); 165 return true; 166 } 167 } 168 169 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 170 if (staticValues->contains(name)) { 171 JSValue value = thisObject->getStaticValue(exec, propertyName); 172 if (value) { 173 slot.setValue(thisObject, ReadOnly | DontEnum, value); 174 return true; 175 } 176 } 177 } 178 179 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 180 if (staticFunctions->contains(name)) { 181 slot.setCustom(thisObject, ReadOnly | DontEnum, staticFunctionGetter); 182 return true; 183 } 184 } 185 } 186 } 187 188 return Parent::getOwnPropertySlot(thisObject, exec, propertyName, slot); 189} 190 191template <class Parent> 192bool JSCallbackObject<Parent>::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot) 193{ 194 return object->methodTable()->getOwnPropertySlot(object, exec, Identifier::from(exec, propertyName), slot); 195} 196 197template <class Parent> 198JSValue JSCallbackObject<Parent>::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint) 199{ 200 const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object); 201 JSContextRef ctx = toRef(exec); 202 JSObjectRef thisRef = toRef(thisObject); 203 ::JSType jsHint = hint == PreferString ? kJSTypeString : kJSTypeNumber; 204 205 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 206 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { 207 JSValueRef exception = 0; 208 JSValueRef result = convertToType(ctx, thisRef, jsHint, &exception); 209 if (exception) { 210 exec->vm().throwException(exec, toJS(exec, exception)); 211 return jsUndefined(); 212 } 213 if (result) 214 return toJS(exec, result); 215 } 216 } 217 218 return Parent::defaultValue(object, exec, hint); 219} 220 221template <class Parent> 222void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 223{ 224 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); 225 JSContextRef ctx = toRef(exec); 226 JSObjectRef thisRef = toRef(thisObject); 227 RefPtr<OpaqueJSString> propertyNameRef; 228 JSValueRef valueRef = toRef(exec, value); 229 230 if (StringImpl* name = propertyName.uid()) { 231 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 232 if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { 233 if (!propertyNameRef) 234 propertyNameRef = OpaqueJSString::create(name); 235 JSValueRef exception = 0; 236 bool result; 237 { 238 JSLock::DropAllLocks dropAllLocks(exec); 239 result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); 240 } 241 if (exception) 242 exec->vm().throwException(exec, toJS(exec, exception)); 243 if (result || exception) 244 return; 245 } 246 247 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 248 if (StaticValueEntry* entry = staticValues->get(name)) { 249 if (entry->attributes & kJSPropertyAttributeReadOnly) 250 return; 251 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { 252 JSValueRef exception = 0; 253 bool result; 254 { 255 JSLock::DropAllLocks dropAllLocks(exec); 256 result = setProperty(ctx, thisRef, entry->propertyNameRef.get(), valueRef, &exception); 257 } 258 if (exception) 259 exec->vm().throwException(exec, toJS(exec, exception)); 260 if (result || exception) 261 return; 262 } 263 } 264 } 265 266 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 267 if (StaticFunctionEntry* entry = staticFunctions->get(name)) { 268 if (entry->attributes & kJSPropertyAttributeReadOnly) 269 return; 270 thisObject->JSCallbackObject<Parent>::putDirect(exec->vm(), propertyName, value); // put as override property 271 return; 272 } 273 } 274 } 275 } 276 277 return Parent::put(thisObject, exec, propertyName, value, slot); 278} 279 280template <class Parent> 281void JSCallbackObject<Parent>::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyIndex, JSValue value, bool shouldThrow) 282{ 283 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); 284 JSContextRef ctx = toRef(exec); 285 JSObjectRef thisRef = toRef(thisObject); 286 RefPtr<OpaqueJSString> propertyNameRef; 287 JSValueRef valueRef = toRef(exec, value); 288 Identifier propertyName = Identifier::from(exec, propertyIndex); 289 290 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 291 if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { 292 if (!propertyNameRef) 293 propertyNameRef = OpaqueJSString::create(propertyName.impl()); 294 JSValueRef exception = 0; 295 bool result; 296 { 297 JSLock::DropAllLocks dropAllLocks(exec); 298 result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); 299 } 300 if (exception) 301 exec->vm().throwException(exec, toJS(exec, exception)); 302 if (result || exception) 303 return; 304 } 305 306 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 307 if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { 308 if (entry->attributes & kJSPropertyAttributeReadOnly) 309 return; 310 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { 311 JSValueRef exception = 0; 312 bool result; 313 { 314 JSLock::DropAllLocks dropAllLocks(exec); 315 result = setProperty(ctx, thisRef, entry->propertyNameRef.get(), valueRef, &exception); 316 } 317 if (exception) 318 exec->vm().throwException(exec, toJS(exec, exception)); 319 if (result || exception) 320 return; 321 } 322 } 323 } 324 325 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 326 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { 327 if (entry->attributes & kJSPropertyAttributeReadOnly) 328 return; 329 break; 330 } 331 } 332 } 333 334 return Parent::putByIndex(thisObject, exec, propertyIndex, value, shouldThrow); 335} 336 337template <class Parent> 338bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) 339{ 340 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); 341 JSContextRef ctx = toRef(exec); 342 JSObjectRef thisRef = toRef(thisObject); 343 RefPtr<OpaqueJSString> propertyNameRef; 344 345 if (StringImpl* name = propertyName.uid()) { 346 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 347 if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { 348 if (!propertyNameRef) 349 propertyNameRef = OpaqueJSString::create(name); 350 JSValueRef exception = 0; 351 bool result; 352 { 353 JSLock::DropAllLocks dropAllLocks(exec); 354 result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); 355 } 356 if (exception) 357 exec->vm().throwException(exec, toJS(exec, exception)); 358 if (result || exception) 359 return true; 360 } 361 362 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 363 if (StaticValueEntry* entry = staticValues->get(name)) { 364 if (entry->attributes & kJSPropertyAttributeDontDelete) 365 return false; 366 return true; 367 } 368 } 369 370 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 371 if (StaticFunctionEntry* entry = staticFunctions->get(name)) { 372 if (entry->attributes & kJSPropertyAttributeDontDelete) 373 return false; 374 return true; 375 } 376 } 377 } 378 } 379 380 return Parent::deleteProperty(thisObject, exec, propertyName); 381} 382 383template <class Parent> 384bool JSCallbackObject<Parent>::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) 385{ 386 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); 387 return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, propertyName)); 388} 389 390template <class Parent> 391ConstructType JSCallbackObject<Parent>::getConstructData(JSCell* cell, ConstructData& constructData) 392{ 393 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); 394 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 395 if (jsClass->callAsConstructor) { 396 constructData.native.function = construct; 397 return ConstructTypeHost; 398 } 399 } 400 return ConstructTypeNone; 401} 402 403template <class Parent> 404EncodedJSValue JSCallbackObject<Parent>::construct(ExecState* exec) 405{ 406 JSObject* constructor = exec->callee(); 407 JSContextRef execRef = toRef(exec); 408 JSObjectRef constructorRef = toRef(constructor); 409 410 for (JSClassRef jsClass = jsCast<JSCallbackObject<Parent>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { 411 if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { 412 size_t argumentCount = exec->argumentCount(); 413 Vector<JSValueRef, 16> arguments; 414 arguments.reserveInitialCapacity(argumentCount); 415 for (size_t i = 0; i < argumentCount; ++i) 416 arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); 417 JSValueRef exception = 0; 418 JSObject* result; 419 { 420 JSLock::DropAllLocks dropAllLocks(exec); 421 result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); 422 } 423 if (exception) 424 exec->vm().throwException(exec, toJS(exec, exception)); 425 return JSValue::encode(result); 426 } 427 } 428 429 RELEASE_ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here 430 return JSValue::encode(JSValue()); 431} 432 433template <class Parent> 434bool JSCallbackObject<Parent>::customHasInstance(JSObject* object, ExecState* exec, JSValue value) 435{ 436 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); 437 JSContextRef execRef = toRef(exec); 438 JSObjectRef thisRef = toRef(thisObject); 439 440 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 441 if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) { 442 JSValueRef valueRef = toRef(exec, value); 443 JSValueRef exception = 0; 444 bool result; 445 { 446 JSLock::DropAllLocks dropAllLocks(exec); 447 result = hasInstance(execRef, thisRef, valueRef, &exception); 448 } 449 if (exception) 450 exec->vm().throwException(exec, toJS(exec, exception)); 451 return result; 452 } 453 } 454 return false; 455} 456 457template <class Parent> 458CallType JSCallbackObject<Parent>::getCallData(JSCell* cell, CallData& callData) 459{ 460 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); 461 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 462 if (jsClass->callAsFunction) { 463 callData.native.function = call; 464 return CallTypeHost; 465 } 466 } 467 return CallTypeNone; 468} 469 470template <class Parent> 471EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec) 472{ 473 JSContextRef execRef = toRef(exec); 474 JSObjectRef functionRef = toRef(exec->callee()); 475 JSObjectRef thisObjRef = toRef(jsCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode))); 476 477 for (JSClassRef jsClass = jsCast<JSCallbackObject<Parent>*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) { 478 if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { 479 size_t argumentCount = exec->argumentCount(); 480 Vector<JSValueRef, 16> arguments; 481 arguments.reserveInitialCapacity(argumentCount); 482 for (size_t i = 0; i < argumentCount; ++i) 483 arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); 484 JSValueRef exception = 0; 485 JSValue result; 486 { 487 JSLock::DropAllLocks dropAllLocks(exec); 488 result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); 489 } 490 if (exception) 491 exec->vm().throwException(exec, toJS(exec, exception)); 492 return JSValue::encode(result); 493 } 494 } 495 496 RELEASE_ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here 497 return JSValue::encode(JSValue()); 498} 499 500template <class Parent> 501void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 502{ 503 JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); 504 JSContextRef execRef = toRef(exec); 505 JSObjectRef thisRef = toRef(thisObject); 506 507 for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { 508 if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { 509 JSLock::DropAllLocks dropAllLocks(exec); 510 getPropertyNames(execRef, thisRef, toRef(&propertyNames)); 511 } 512 513 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 514 typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; 515 iterator end = staticValues->end(); 516 for (iterator it = staticValues->begin(); it != end; ++it) { 517 StringImpl* name = it->key.get(); 518 StaticValueEntry* entry = it->value.get(); 519 if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) 520 propertyNames.add(Identifier(exec, name)); 521 } 522 } 523 524 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 525 typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; 526 iterator end = staticFunctions->end(); 527 for (iterator it = staticFunctions->begin(); it != end; ++it) { 528 StringImpl* name = it->key.get(); 529 StaticFunctionEntry* entry = it->value.get(); 530 if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) 531 propertyNames.add(Identifier(exec, name)); 532 } 533 } 534 } 535 536 Parent::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); 537} 538 539template <class Parent> 540void JSCallbackObject<Parent>::setPrivate(void* data) 541{ 542 m_callbackObjectData->privateData = data; 543} 544 545template <class Parent> 546void* JSCallbackObject<Parent>::getPrivate() 547{ 548 return m_callbackObjectData->privateData; 549} 550 551template <class Parent> 552bool JSCallbackObject<Parent>::inherits(JSClassRef c) const 553{ 554 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 555 if (jsClass == c) 556 return true; 557 } 558 return false; 559} 560 561template <class Parent> 562JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName propertyName) 563{ 564 JSObjectRef thisRef = toRef(this); 565 566 if (StringImpl* name = propertyName.uid()) { 567 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 568 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 569 if (StaticValueEntry* entry = staticValues->get(name)) { 570 if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { 571 JSValueRef exception = 0; 572 JSValueRef value; 573 { 574 JSLock::DropAllLocks dropAllLocks(exec); 575 value = getProperty(toRef(exec), thisRef, entry->propertyNameRef.get(), &exception); 576 } 577 if (exception) { 578 exec->vm().throwException(exec, toJS(exec, exception)); 579 return jsUndefined(); 580 } 581 if (value) 582 return toJS(exec, value); 583 } 584 } 585 } 586 } 587 } 588 589 return JSValue(); 590} 591 592template <class Parent> 593EncodedJSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, JSObject* slotParent, EncodedJSValue, PropertyName propertyName) 594{ 595 JSCallbackObject* thisObj = asCallbackObject(slotParent); 596 597 // Check for cached or override property. 598 PropertySlot slot2(thisObj); 599 if (Parent::getOwnPropertySlot(thisObj, exec, propertyName, slot2)) 600 return JSValue::encode(slot2.getValue(exec, propertyName)); 601 602 if (StringImpl* name = propertyName.uid()) { 603 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { 604 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 605 if (StaticFunctionEntry* entry = staticFunctions->get(name)) { 606 if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { 607 VM& vm = exec->vm(); 608 JSObject* o = JSCallbackFunction::create(vm, thisObj->globalObject(), callAsFunction, name); 609 thisObj->putDirect(vm, propertyName, o, entry->attributes); 610 return JSValue::encode(o); 611 } 612 } 613 } 614 } 615 } 616 617 return JSValue::encode(exec->vm().throwException(exec, createReferenceError(exec, ASCIILiteral("Static function property defined with NULL callAsFunction callback.")))); 618} 619 620template <class Parent> 621EncodedJSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, JSObject* slotParent, EncodedJSValue, PropertyName propertyName) 622{ 623 JSCallbackObject* thisObj = asCallbackObject(slotParent); 624 625 JSObjectRef thisRef = toRef(thisObj); 626 RefPtr<OpaqueJSString> propertyNameRef; 627 628 if (StringImpl* name = propertyName.uid()) { 629 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { 630 if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { 631 if (!propertyNameRef) 632 propertyNameRef = OpaqueJSString::create(name); 633 JSValueRef exception = 0; 634 JSValueRef value; 635 { 636 JSLock::DropAllLocks dropAllLocks(exec); 637 value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); 638 } 639 if (exception) { 640 exec->vm().throwException(exec, toJS(exec, exception)); 641 return JSValue::encode(jsUndefined()); 642 } 643 if (value) 644 return JSValue::encode(toJS(exec, value)); 645 } 646 } 647 } 648 649 return JSValue::encode(exec->vm().throwException(exec, createReferenceError(exec, ASCIILiteral("hasProperty callback returned true for a property that doesn't exist.")))); 650} 651 652} // namespace JSC 653