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