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