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