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