1 /* 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Eric Seidel <eric (at) 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 COMPUTER, 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 COMPUTER, 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 "APIShims.h" 28 #include "APICast.h" 29 #include "Error.h" 30 #include "ExceptionHelpers.h" 31 #include "JSCallbackFunction.h" 32 #include "JSClassRef.h" 33 #include "JSFunction.h" 34 #include "JSGlobalObject.h" 35 #include "JSLock.h" 36 #include "JSObjectRef.h" 37 #include "JSString.h" 38 #include "JSStringRef.h" 39 #include "OpaqueJSString.h" 40 #include "PropertyNameArray.h" 41 #include <wtf/Vector.h> 42 43 namespace JSC { 44 45 template <class Base> 46 inline JSCallbackObject<Base>* JSCallbackObject<Base>::asCallbackObject(JSValue value) 47 { 48 ASSERT(asObject(value)->inherits(&s_info)); 49 return static_cast<JSCallbackObject*>(asObject(value)); 50 } 51 52 template <class Base> 53 JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, void* data) 54 : Base(globalObject, structure) 55 , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) 56 { 57 ASSERT(Base::inherits(&s_info)); 58 init(exec); 59 } 60 61 // Global object constructor. 62 // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. 63 template <class Base> 64 JSCallbackObject<Base>::JSCallbackObject(JSGlobalData& globalData, JSClassRef jsClass, Structure* structure) 65 : Base(globalData, structure) 66 , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) 67 { 68 ASSERT(Base::inherits(&s_info)); 69 ASSERT(Base::isGlobalObject()); 70 init(static_cast<JSGlobalObject*>(this)->globalExec()); 71 } 72 73 template <class Base> 74 void JSCallbackObject<Base>::init(ExecState* exec) 75 { 76 ASSERT(exec); 77 78 Vector<JSObjectInitializeCallback, 16> initRoutines; 79 JSClassRef jsClass = classRef(); 80 do { 81 if (JSObjectInitializeCallback initialize = jsClass->initialize) 82 initRoutines.append(initialize); 83 } while ((jsClass = jsClass->parentClass)); 84 85 // initialize from base to derived 86 for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { 87 APICallbackShim callbackShim(exec); 88 JSObjectInitializeCallback initialize = initRoutines[i]; 89 initialize(toRef(exec), toRef(this)); 90 } 91 92 bool needsFinalizer = false; 93 for (JSClassRef jsClassPtr = classRef(); jsClassPtr && !needsFinalizer; jsClassPtr = jsClassPtr->parentClass) 94 needsFinalizer = jsClassPtr->finalize; 95 if (needsFinalizer) { 96 HandleSlot slot = exec->globalData().allocateGlobalHandle(); 97 HandleHeap::heapFor(slot)->makeWeak(slot, m_callbackObjectData.get(), classRef()); 98 HandleHeap::heapFor(slot)->writeBarrier(slot, this); 99 *slot = this; 100 } 101 } 102 103 template <class Base> 104 UString JSCallbackObject<Base>::className() const 105 { 106 UString thisClassName = classRef()->className(); 107 if (!thisClassName.isEmpty()) 108 return thisClassName; 109 110 return Base::className(); 111 } 112 113 template <class Base> 114 bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 115 { 116 JSContextRef ctx = toRef(exec); 117 JSObjectRef thisRef = toRef(this); 118 RefPtr<OpaqueJSString> propertyNameRef; 119 120 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 121 // optional optimization to bypass getProperty in cases when we only need to know if the property exists 122 if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { 123 if (!propertyNameRef) 124 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 125 APICallbackShim callbackShim(exec); 126 if (hasProperty(ctx, thisRef, propertyNameRef.get())) { 127 slot.setCustom(this, callbackGetter); 128 return true; 129 } 130 } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { 131 if (!propertyNameRef) 132 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 133 JSValueRef exception = 0; 134 JSValueRef value; 135 { 136 APICallbackShim callbackShim(exec); 137 value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); 138 } 139 if (exception) { 140 throwError(exec, toJS(exec, exception)); 141 slot.setValue(jsUndefined()); 142 return true; 143 } 144 if (value) { 145 slot.setValue(toJS(exec, value)); 146 return true; 147 } 148 } 149 150 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 151 if (staticValues->contains(propertyName.impl())) { 152 slot.setCustom(this, staticValueGetter); 153 return true; 154 } 155 } 156 157 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 158 if (staticFunctions->contains(propertyName.impl())) { 159 slot.setCustom(this, staticFunctionGetter); 160 return true; 161 } 162 } 163 } 164 165 return Base::getOwnPropertySlot(exec, propertyName, slot); 166 } 167 168 template <class Base> 169 bool JSCallbackObject<Base>::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) 170 { 171 PropertySlot slot; 172 if (getOwnPropertySlot(exec, propertyName, slot)) { 173 // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing. 174 JSValue value = slot.getValue(exec, propertyName); 175 if (!exec->hadException()) 176 descriptor.setValue(value); 177 // We don't know whether the property is configurable, but assume it is. 178 descriptor.setConfigurable(true); 179 // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't. 180 descriptor.setEnumerable(false); 181 return true; 182 } 183 184 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); 185 } 186 187 template <class Base> 188 void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) 189 { 190 JSContextRef ctx = toRef(exec); 191 JSObjectRef thisRef = toRef(this); 192 RefPtr<OpaqueJSString> propertyNameRef; 193 JSValueRef valueRef = toRef(exec, value); 194 195 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 196 if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { 197 if (!propertyNameRef) 198 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 199 JSValueRef exception = 0; 200 bool result; 201 { 202 APICallbackShim callbackShim(exec); 203 result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); 204 } 205 if (exception) 206 throwError(exec, toJS(exec, exception)); 207 if (result || exception) 208 return; 209 } 210 211 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 212 if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { 213 if (entry->attributes & kJSPropertyAttributeReadOnly) 214 return; 215 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { 216 if (!propertyNameRef) 217 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 218 JSValueRef exception = 0; 219 bool result; 220 { 221 APICallbackShim callbackShim(exec); 222 result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); 223 } 224 if (exception) 225 throwError(exec, toJS(exec, exception)); 226 if (result || exception) 227 return; 228 } else 229 throwError(exec, createReferenceError(exec, "Attempt to set a property that is not settable.")); 230 } 231 } 232 233 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 234 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { 235 if (entry->attributes & kJSPropertyAttributeReadOnly) 236 return; 237 JSCallbackObject<Base>::putDirect(exec->globalData(), propertyName, value); // put as override property 238 return; 239 } 240 } 241 } 242 243 return Base::put(exec, propertyName, value, slot); 244 } 245 246 template <class Base> 247 bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, const Identifier& propertyName) 248 { 249 JSContextRef ctx = toRef(exec); 250 JSObjectRef thisRef = toRef(this); 251 RefPtr<OpaqueJSString> propertyNameRef; 252 253 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 254 if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { 255 if (!propertyNameRef) 256 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 257 JSValueRef exception = 0; 258 bool result; 259 { 260 APICallbackShim callbackShim(exec); 261 result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); 262 } 263 if (exception) 264 throwError(exec, toJS(exec, exception)); 265 if (result || exception) 266 return true; 267 } 268 269 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 270 if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { 271 if (entry->attributes & kJSPropertyAttributeDontDelete) 272 return false; 273 return true; 274 } 275 } 276 277 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 278 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { 279 if (entry->attributes & kJSPropertyAttributeDontDelete) 280 return false; 281 return true; 282 } 283 } 284 } 285 286 return Base::deleteProperty(exec, propertyName); 287 } 288 289 template <class Base> 290 bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, unsigned propertyName) 291 { 292 return deleteProperty(exec, Identifier::from(exec, propertyName)); 293 } 294 295 template <class Base> 296 ConstructType JSCallbackObject<Base>::getConstructData(ConstructData& constructData) 297 { 298 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 299 if (jsClass->callAsConstructor) { 300 constructData.native.function = construct; 301 return ConstructTypeHost; 302 } 303 } 304 return ConstructTypeNone; 305 } 306 307 template <class Base> 308 EncodedJSValue JSCallbackObject<Base>::construct(ExecState* exec) 309 { 310 JSObject* constructor = exec->callee(); 311 JSContextRef execRef = toRef(exec); 312 JSObjectRef constructorRef = toRef(constructor); 313 314 for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { 315 if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { 316 int argumentCount = static_cast<int>(exec->argumentCount()); 317 Vector<JSValueRef, 16> arguments(argumentCount); 318 for (int i = 0; i < argumentCount; i++) 319 arguments[i] = toRef(exec, exec->argument(i)); 320 JSValueRef exception = 0; 321 JSObject* result; 322 { 323 APICallbackShim callbackShim(exec); 324 result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); 325 } 326 if (exception) 327 throwError(exec, toJS(exec, exception)); 328 return JSValue::encode(result); 329 } 330 } 331 332 ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here 333 return JSValue::encode(JSValue()); 334 } 335 336 template <class Base> 337 bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue value, JSValue) 338 { 339 JSContextRef execRef = toRef(exec); 340 JSObjectRef thisRef = toRef(this); 341 342 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 343 if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) { 344 JSValueRef valueRef = toRef(exec, value); 345 JSValueRef exception = 0; 346 bool result; 347 { 348 APICallbackShim callbackShim(exec); 349 result = hasInstance(execRef, thisRef, valueRef, &exception); 350 } 351 if (exception) 352 throwError(exec, toJS(exec, exception)); 353 return result; 354 } 355 } 356 return false; 357 } 358 359 template <class Base> 360 CallType JSCallbackObject<Base>::getCallData(CallData& callData) 361 { 362 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 363 if (jsClass->callAsFunction) { 364 callData.native.function = call; 365 return CallTypeHost; 366 } 367 } 368 return CallTypeNone; 369 } 370 371 template <class Base> 372 EncodedJSValue JSCallbackObject<Base>::call(ExecState* exec) 373 { 374 JSContextRef execRef = toRef(exec); 375 JSObjectRef functionRef = toRef(exec->callee()); 376 JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); 377 378 for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) { 379 if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { 380 int argumentCount = static_cast<int>(exec->argumentCount()); 381 Vector<JSValueRef, 16> arguments(argumentCount); 382 for (int i = 0; i < argumentCount; i++) 383 arguments[i] = toRef(exec, exec->argument(i)); 384 JSValueRef exception = 0; 385 JSValue result; 386 { 387 APICallbackShim callbackShim(exec); 388 result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); 389 } 390 if (exception) 391 throwError(exec, toJS(exec, exception)); 392 return JSValue::encode(result); 393 } 394 } 395 396 ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here 397 return JSValue::encode(JSValue()); 398 } 399 400 template <class Base> 401 void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 402 { 403 JSContextRef execRef = toRef(exec); 404 JSObjectRef thisRef = toRef(this); 405 406 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { 407 if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { 408 APICallbackShim callbackShim(exec); 409 getPropertyNames(execRef, thisRef, toRef(&propertyNames)); 410 } 411 412 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { 413 typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; 414 iterator end = staticValues->end(); 415 for (iterator it = staticValues->begin(); it != end; ++it) { 416 StringImpl* name = it->first.get(); 417 StaticValueEntry* entry = it->second; 418 if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) 419 propertyNames.add(Identifier(exec, name)); 420 } 421 } 422 423 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 424 typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; 425 iterator end = staticFunctions->end(); 426 for (iterator it = staticFunctions->begin(); it != end; ++it) { 427 StringImpl* name = it->first.get(); 428 StaticFunctionEntry* entry = it->second; 429 if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) 430 propertyNames.add(Identifier(exec, name)); 431 } 432 } 433 } 434 435 Base::getOwnPropertyNames(exec, propertyNames, mode); 436 } 437 438 template <class Base> 439 double JSCallbackObject<Base>::toNumber(ExecState* exec) const 440 { 441 // We need this check to guard against the case where this object is rhs of 442 // a binary expression where lhs threw an exception in its conversion to 443 // primitive 444 if (exec->hadException()) 445 return NaN; 446 JSContextRef ctx = toRef(exec); 447 JSObjectRef thisRef = toRef(this); 448 449 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) 450 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { 451 JSValueRef exception = 0; 452 JSValueRef value; 453 { 454 APICallbackShim callbackShim(exec); 455 value = convertToType(ctx, thisRef, kJSTypeNumber, &exception); 456 } 457 if (exception) { 458 throwError(exec, toJS(exec, exception)); 459 return 0; 460 } 461 462 double dValue; 463 if (value) 464 return toJS(exec, value).getNumber(dValue) ? dValue : NaN; 465 } 466 467 return Base::toNumber(exec); 468 } 469 470 template <class Base> 471 UString JSCallbackObject<Base>::toString(ExecState* exec) const 472 { 473 JSContextRef ctx = toRef(exec); 474 JSObjectRef thisRef = toRef(this); 475 476 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) 477 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { 478 JSValueRef exception = 0; 479 JSValueRef value; 480 { 481 APICallbackShim callbackShim(exec); 482 value = convertToType(ctx, thisRef, kJSTypeString, &exception); 483 } 484 if (exception) { 485 throwError(exec, toJS(exec, exception)); 486 return ""; 487 } 488 if (value) 489 return toJS(exec, value).getString(exec); 490 } 491 492 return Base::toString(exec); 493 } 494 495 template <class Base> 496 void JSCallbackObject<Base>::setPrivate(void* data) 497 { 498 m_callbackObjectData->privateData = data; 499 } 500 501 template <class Base> 502 void* JSCallbackObject<Base>::getPrivate() 503 { 504 return m_callbackObjectData->privateData; 505 } 506 507 template <class Base> 508 bool JSCallbackObject<Base>::inherits(JSClassRef c) const 509 { 510 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) 511 if (jsClass == c) 512 return true; 513 514 return false; 515 } 516 517 template <class Base> 518 JSValue JSCallbackObject<Base>::staticValueGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 519 { 520 JSCallbackObject* thisObj = asCallbackObject(slotBase); 521 522 JSObjectRef thisRef = toRef(thisObj); 523 RefPtr<OpaqueJSString> propertyNameRef; 524 525 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) 526 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) 527 if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) 528 if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { 529 if (!propertyNameRef) 530 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 531 JSValueRef exception = 0; 532 JSValueRef value; 533 { 534 APICallbackShim callbackShim(exec); 535 value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); 536 } 537 if (exception) { 538 throwError(exec, toJS(exec, exception)); 539 return jsUndefined(); 540 } 541 if (value) 542 return toJS(exec, value); 543 } 544 545 return throwError(exec, createReferenceError(exec, "Static value property defined with NULL getProperty callback.")); 546 } 547 548 template <class Base> 549 JSValue JSCallbackObject<Base>::staticFunctionGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 550 { 551 JSCallbackObject* thisObj = asCallbackObject(slotBase); 552 553 // Check for cached or override property. 554 PropertySlot slot2(thisObj); 555 if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2)) 556 return slot2.getValue(exec, propertyName); 557 558 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { 559 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { 560 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { 561 if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { 562 563 JSObject* o = new (exec) JSCallbackFunction(exec, asGlobalObject(thisObj->getAnonymousValue(0)), callAsFunction, propertyName); 564 thisObj->putDirect(exec->globalData(), propertyName, o, entry->attributes); 565 return o; 566 } 567 } 568 } 569 } 570 571 return throwError(exec, createReferenceError(exec, "Static function property defined with NULL callAsFunction callback.")); 572 } 573 574 template <class Base> 575 JSValue JSCallbackObject<Base>::callbackGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 576 { 577 JSCallbackObject* thisObj = asCallbackObject(slotBase); 578 579 JSObjectRef thisRef = toRef(thisObj); 580 RefPtr<OpaqueJSString> propertyNameRef; 581 582 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) 583 if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { 584 if (!propertyNameRef) 585 propertyNameRef = OpaqueJSString::create(propertyName.ustring()); 586 JSValueRef exception = 0; 587 JSValueRef value; 588 { 589 APICallbackShim callbackShim(exec); 590 value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); 591 } 592 if (exception) { 593 throwError(exec, toJS(exec, exception)); 594 return jsUndefined(); 595 } 596 if (value) 597 return toJS(exec, value); 598 } 599 600 return throwError(exec, createReferenceError(exec, "hasProperty callback returned true for a property that doesn't exist.")); 601 } 602 603 } // namespace JSC 604