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