2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 #include "ExceptionHelpers.h"
30 #include "JSCallbackFunction.h"
31 #include "JSClassRef.h"
32 #include "JSFunction.h"
33 #include "JSGlobalObject.h"
35 #include "JSObjectRef.h"
37 #include "JSStringRef.h"
38 #include "OpaqueJSString.h"
39 #include "PropertyNameArray.h"
40 #include <wtf/Vector.h>
44 template <class Parent
>
45 inline JSCallbackObject
<Parent
>* JSCallbackObject
<Parent
>::asCallbackObject(JSValue value
)
47 ASSERT(asObject(value
)->inherits(info()));
48 return jsCast
<JSCallbackObject
*>(asObject(value
));
51 template <class Parent
>
52 inline JSCallbackObject
<Parent
>* JSCallbackObject
<Parent
>::asCallbackObject(EncodedJSValue value
)
54 ASSERT(asObject(JSValue::decode(value
))->inherits(info()));
55 return jsCast
<JSCallbackObject
*>(asObject(JSValue::decode(value
)));
58 template <class Parent
>
59 JSCallbackObject
<Parent
>::JSCallbackObject(ExecState
* exec
, Structure
* structure
, JSClassRef jsClass
, void* data
)
60 : Parent(exec
->vm(), structure
)
61 , m_callbackObjectData(std::make_unique
<JSCallbackObjectData
>(data
, jsClass
))
65 extern const GlobalObjectMethodTable javaScriptCoreAPIGlobalObjectMethodTable
;
67 // Global object constructor.
68 // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one.
69 template <class Parent
>
70 JSCallbackObject
<Parent
>::JSCallbackObject(VM
& vm
, JSClassRef jsClass
, Structure
* structure
)
71 : Parent(vm
, structure
, &javaScriptCoreAPIGlobalObjectMethodTable
)
72 , m_callbackObjectData(std::make_unique
<JSCallbackObjectData
>(nullptr, jsClass
))
76 template <class Parent
>
77 JSCallbackObject
<Parent
>::~JSCallbackObject()
79 JSObjectRef thisRef
= toRef(static_cast<JSObject
*>(this));
80 for (JSClassRef jsClass
= classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
81 if (JSObjectFinalizeCallback finalize
= jsClass
->finalize
)
86 template <class Parent
>
87 void JSCallbackObject
<Parent
>::finishCreation(ExecState
* exec
)
89 Base::finishCreation(exec
->vm());
90 ASSERT(Parent::inherits(info()));
94 // This is just for Global object, so we can assume that Base::finishCreation is JSGlobalObject::finishCreation.
95 template <class Parent
>
96 void JSCallbackObject
<Parent
>::finishCreation(VM
& vm
)
98 ASSERT(Parent::inherits(info()));
99 ASSERT(Parent::isGlobalObject());
100 Base::finishCreation(vm
);
101 init(jsCast
<JSGlobalObject
*>(this)->globalExec());
104 template <class Parent
>
105 void JSCallbackObject
<Parent
>::init(ExecState
* exec
)
109 Vector
<JSObjectInitializeCallback
, 16> initRoutines
;
110 JSClassRef jsClass
= classRef();
112 if (JSObjectInitializeCallback initialize
= jsClass
->initialize
)
113 initRoutines
.append(initialize
);
114 } while ((jsClass
= jsClass
->parentClass
));
116 // initialize from base to derived
117 for (int i
= static_cast<int>(initRoutines
.size()) - 1; i
>= 0; i
--) {
118 JSLock::DropAllLocks
dropAllLocks(exec
);
119 JSObjectInitializeCallback initialize
= initRoutines
[i
];
120 initialize(toRef(exec
), toRef(this));
124 template <class Parent
>
125 String JSCallbackObject
<Parent
>::className(const JSObject
* object
)
127 const JSCallbackObject
* thisObject
= jsCast
<const JSCallbackObject
*>(object
);
128 String thisClassName
= thisObject
->classRef()->className();
129 if (!thisClassName
.isEmpty())
130 return thisClassName
;
132 return Parent::className(object
);
135 template <class Parent
>
136 bool JSCallbackObject
<Parent
>::getOwnPropertySlot(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
138 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(object
);
139 JSContextRef ctx
= toRef(exec
);
140 JSObjectRef thisRef
= toRef(thisObject
);
141 RefPtr
<OpaqueJSString
> propertyNameRef
;
143 if (StringImpl
* name
= propertyName
.uid()) {
144 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
145 // optional optimization to bypass getProperty in cases when we only need to know if the property exists
146 if (JSObjectHasPropertyCallback hasProperty
= jsClass
->hasProperty
) {
147 if (!propertyNameRef
)
148 propertyNameRef
= OpaqueJSString::create(name
);
149 JSLock::DropAllLocks
dropAllLocks(exec
);
150 if (hasProperty(ctx
, thisRef
, propertyNameRef
.get())) {
151 slot
.setCustom(thisObject
, ReadOnly
| DontEnum
, callbackGetter
);
154 } else if (JSObjectGetPropertyCallback getProperty
= jsClass
->getProperty
) {
155 if (!propertyNameRef
)
156 propertyNameRef
= OpaqueJSString::create(name
);
157 JSValueRef exception
= 0;
160 JSLock::DropAllLocks
dropAllLocks(exec
);
161 value
= getProperty(ctx
, thisRef
, propertyNameRef
.get(), &exception
);
164 exec
->vm().throwException(exec
, toJS(exec
, exception
));
165 slot
.setValue(thisObject
, ReadOnly
| DontEnum
, jsUndefined());
169 slot
.setValue(thisObject
, ReadOnly
| DontEnum
, toJS(exec
, value
));
174 if (OpaqueJSClassStaticValuesTable
* staticValues
= jsClass
->staticValues(exec
)) {
175 if (staticValues
->contains(name
)) {
176 JSValue value
= thisObject
->getStaticValue(exec
, propertyName
);
178 slot
.setValue(thisObject
, ReadOnly
| DontEnum
, value
);
184 if (OpaqueJSClassStaticFunctionsTable
* staticFunctions
= jsClass
->staticFunctions(exec
)) {
185 if (staticFunctions
->contains(name
)) {
186 slot
.setCustom(thisObject
, ReadOnly
| DontEnum
, staticFunctionGetter
);
193 return Parent::getOwnPropertySlot(thisObject
, exec
, propertyName
, slot
);
196 template <class Parent
>
197 bool JSCallbackObject
<Parent
>::getOwnPropertySlotByIndex(JSObject
* object
, ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
199 return object
->methodTable()->getOwnPropertySlot(object
, exec
, Identifier::from(exec
, propertyName
), slot
);
202 template <class Parent
>
203 JSValue JSCallbackObject
<Parent
>::defaultValue(const JSObject
* object
, ExecState
* exec
, PreferredPrimitiveType hint
)
205 const JSCallbackObject
* thisObject
= jsCast
<const JSCallbackObject
*>(object
);
206 JSContextRef ctx
= toRef(exec
);
207 JSObjectRef thisRef
= toRef(thisObject
);
208 ::JSType jsHint
= hint
== PreferString
? kJSTypeString
: kJSTypeNumber
;
210 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
211 if (JSObjectConvertToTypeCallback convertToType
= jsClass
->convertToType
) {
212 JSValueRef exception
= 0;
213 JSValueRef result
= convertToType(ctx
, thisRef
, jsHint
, &exception
);
215 exec
->vm().throwException(exec
, toJS(exec
, exception
));
216 return jsUndefined();
219 return toJS(exec
, result
);
223 return Parent::defaultValue(object
, exec
, hint
);
226 template <class Parent
>
227 void JSCallbackObject
<Parent
>::put(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
229 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(cell
);
230 JSContextRef ctx
= toRef(exec
);
231 JSObjectRef thisRef
= toRef(thisObject
);
232 RefPtr
<OpaqueJSString
> propertyNameRef
;
233 JSValueRef valueRef
= toRef(exec
, value
);
235 if (StringImpl
* name
= propertyName
.uid()) {
236 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
237 if (JSObjectSetPropertyCallback setProperty
= jsClass
->setProperty
) {
238 if (!propertyNameRef
)
239 propertyNameRef
= OpaqueJSString::create(name
);
240 JSValueRef exception
= 0;
243 JSLock::DropAllLocks
dropAllLocks(exec
);
244 result
= setProperty(ctx
, thisRef
, propertyNameRef
.get(), valueRef
, &exception
);
247 exec
->vm().throwException(exec
, toJS(exec
, exception
));
248 if (result
|| exception
)
252 if (OpaqueJSClassStaticValuesTable
* staticValues
= jsClass
->staticValues(exec
)) {
253 if (StaticValueEntry
* entry
= staticValues
->get(name
)) {
254 if (entry
->attributes
& kJSPropertyAttributeReadOnly
)
256 if (JSObjectSetPropertyCallback setProperty
= entry
->setProperty
) {
257 JSValueRef exception
= 0;
260 JSLock::DropAllLocks
dropAllLocks(exec
);
261 result
= setProperty(ctx
, thisRef
, entry
->propertyNameRef
.get(), valueRef
, &exception
);
264 exec
->vm().throwException(exec
, toJS(exec
, exception
));
265 if (result
|| exception
)
271 if (OpaqueJSClassStaticFunctionsTable
* staticFunctions
= jsClass
->staticFunctions(exec
)) {
272 if (StaticFunctionEntry
* entry
= staticFunctions
->get(name
)) {
273 PropertySlot
getSlot(thisObject
);
274 if (Parent::getOwnPropertySlot(thisObject
, exec
, propertyName
, getSlot
))
275 return Parent::put(thisObject
, exec
, propertyName
, value
, slot
);
276 if (entry
->attributes
& kJSPropertyAttributeReadOnly
)
278 thisObject
->JSCallbackObject
<Parent
>::putDirect(exec
->vm(), propertyName
, value
); // put as override property
285 return Parent::put(thisObject
, exec
, propertyName
, value
, slot
);
288 template <class Parent
>
289 void JSCallbackObject
<Parent
>::putByIndex(JSCell
* cell
, ExecState
* exec
, unsigned propertyIndex
, JSValue value
, bool shouldThrow
)
291 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(cell
);
292 JSContextRef ctx
= toRef(exec
);
293 JSObjectRef thisRef
= toRef(thisObject
);
294 RefPtr
<OpaqueJSString
> propertyNameRef
;
295 JSValueRef valueRef
= toRef(exec
, value
);
296 Identifier propertyName
= Identifier::from(exec
, propertyIndex
);
298 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
299 if (JSObjectSetPropertyCallback setProperty
= jsClass
->setProperty
) {
300 if (!propertyNameRef
)
301 propertyNameRef
= OpaqueJSString::create(propertyName
.impl());
302 JSValueRef exception
= 0;
305 JSLock::DropAllLocks
dropAllLocks(exec
);
306 result
= setProperty(ctx
, thisRef
, propertyNameRef
.get(), valueRef
, &exception
);
309 exec
->vm().throwException(exec
, toJS(exec
, exception
));
310 if (result
|| exception
)
314 if (OpaqueJSClassStaticValuesTable
* staticValues
= jsClass
->staticValues(exec
)) {
315 if (StaticValueEntry
* entry
= staticValues
->get(propertyName
.impl())) {
316 if (entry
->attributes
& kJSPropertyAttributeReadOnly
)
318 if (JSObjectSetPropertyCallback setProperty
= entry
->setProperty
) {
319 JSValueRef exception
= 0;
322 JSLock::DropAllLocks
dropAllLocks(exec
);
323 result
= setProperty(ctx
, thisRef
, entry
->propertyNameRef
.get(), valueRef
, &exception
);
326 exec
->vm().throwException(exec
, toJS(exec
, exception
));
327 if (result
|| exception
)
333 if (OpaqueJSClassStaticFunctionsTable
* staticFunctions
= jsClass
->staticFunctions(exec
)) {
334 if (StaticFunctionEntry
* entry
= staticFunctions
->get(propertyName
.impl())) {
335 if (entry
->attributes
& kJSPropertyAttributeReadOnly
)
342 return Parent::putByIndex(thisObject
, exec
, propertyIndex
, value
, shouldThrow
);
345 template <class Parent
>
346 bool JSCallbackObject
<Parent
>::deleteProperty(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
)
348 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(cell
);
349 JSContextRef ctx
= toRef(exec
);
350 JSObjectRef thisRef
= toRef(thisObject
);
351 RefPtr
<OpaqueJSString
> propertyNameRef
;
353 if (StringImpl
* name
= propertyName
.uid()) {
354 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
355 if (JSObjectDeletePropertyCallback deleteProperty
= jsClass
->deleteProperty
) {
356 if (!propertyNameRef
)
357 propertyNameRef
= OpaqueJSString::create(name
);
358 JSValueRef exception
= 0;
361 JSLock::DropAllLocks
dropAllLocks(exec
);
362 result
= deleteProperty(ctx
, thisRef
, propertyNameRef
.get(), &exception
);
365 exec
->vm().throwException(exec
, toJS(exec
, exception
));
366 if (result
|| exception
)
370 if (OpaqueJSClassStaticValuesTable
* staticValues
= jsClass
->staticValues(exec
)) {
371 if (StaticValueEntry
* entry
= staticValues
->get(name
)) {
372 if (entry
->attributes
& kJSPropertyAttributeDontDelete
)
378 if (OpaqueJSClassStaticFunctionsTable
* staticFunctions
= jsClass
->staticFunctions(exec
)) {
379 if (StaticFunctionEntry
* entry
= staticFunctions
->get(name
)) {
380 if (entry
->attributes
& kJSPropertyAttributeDontDelete
)
388 return Parent::deleteProperty(thisObject
, exec
, propertyName
);
391 template <class Parent
>
392 bool JSCallbackObject
<Parent
>::deletePropertyByIndex(JSCell
* cell
, ExecState
* exec
, unsigned propertyName
)
394 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(cell
);
395 return thisObject
->methodTable()->deleteProperty(thisObject
, exec
, Identifier::from(exec
, propertyName
));
398 template <class Parent
>
399 ConstructType JSCallbackObject
<Parent
>::getConstructData(JSCell
* cell
, ConstructData
& constructData
)
401 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(cell
);
402 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
403 if (jsClass
->callAsConstructor
) {
404 constructData
.native
.function
= construct
;
405 return ConstructTypeHost
;
408 return ConstructTypeNone
;
411 template <class Parent
>
412 EncodedJSValue JSCallbackObject
<Parent
>::construct(ExecState
* exec
)
414 JSObject
* constructor
= exec
->callee();
415 JSContextRef execRef
= toRef(exec
);
416 JSObjectRef constructorRef
= toRef(constructor
);
418 for (JSClassRef jsClass
= jsCast
<JSCallbackObject
<Parent
>*>(constructor
)->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
419 if (JSObjectCallAsConstructorCallback callAsConstructor
= jsClass
->callAsConstructor
) {
420 size_t argumentCount
= exec
->argumentCount();
421 Vector
<JSValueRef
, 16> arguments
;
422 arguments
.reserveInitialCapacity(argumentCount
);
423 for (size_t i
= 0; i
< argumentCount
; ++i
)
424 arguments
.uncheckedAppend(toRef(exec
, exec
->uncheckedArgument(i
)));
425 JSValueRef exception
= 0;
428 JSLock::DropAllLocks
dropAllLocks(exec
);
429 result
= toJS(callAsConstructor(execRef
, constructorRef
, argumentCount
, arguments
.data(), &exception
));
432 exec
->vm().throwException(exec
, toJS(exec
, exception
));
433 return JSValue::encode(result
);
437 RELEASE_ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here
438 return JSValue::encode(JSValue());
441 template <class Parent
>
442 bool JSCallbackObject
<Parent
>::customHasInstance(JSObject
* object
, ExecState
* exec
, JSValue value
)
444 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(object
);
445 JSContextRef execRef
= toRef(exec
);
446 JSObjectRef thisRef
= toRef(thisObject
);
448 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
449 if (JSObjectHasInstanceCallback hasInstance
= jsClass
->hasInstance
) {
450 JSValueRef valueRef
= toRef(exec
, value
);
451 JSValueRef exception
= 0;
454 JSLock::DropAllLocks
dropAllLocks(exec
);
455 result
= hasInstance(execRef
, thisRef
, valueRef
, &exception
);
458 exec
->vm().throwException(exec
, toJS(exec
, exception
));
465 template <class Parent
>
466 CallType JSCallbackObject
<Parent
>::getCallData(JSCell
* cell
, CallData
& callData
)
468 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(cell
);
469 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
470 if (jsClass
->callAsFunction
) {
471 callData
.native
.function
= call
;
478 template <class Parent
>
479 EncodedJSValue JSCallbackObject
<Parent
>::call(ExecState
* exec
)
481 JSContextRef execRef
= toRef(exec
);
482 JSObjectRef functionRef
= toRef(exec
->callee());
483 JSObjectRef thisObjRef
= toRef(jsCast
<JSObject
*>(exec
->thisValue().toThis(exec
, NotStrictMode
)));
485 for (JSClassRef jsClass
= jsCast
<JSCallbackObject
<Parent
>*>(toJS(functionRef
))->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
486 if (JSObjectCallAsFunctionCallback callAsFunction
= jsClass
->callAsFunction
) {
487 size_t argumentCount
= exec
->argumentCount();
488 Vector
<JSValueRef
, 16> arguments
;
489 arguments
.reserveInitialCapacity(argumentCount
);
490 for (size_t i
= 0; i
< argumentCount
; ++i
)
491 arguments
.uncheckedAppend(toRef(exec
, exec
->uncheckedArgument(i
)));
492 JSValueRef exception
= 0;
495 JSLock::DropAllLocks
dropAllLocks(exec
);
496 result
= toJS(exec
, callAsFunction(execRef
, functionRef
, thisObjRef
, argumentCount
, arguments
.data(), &exception
));
499 exec
->vm().throwException(exec
, toJS(exec
, exception
));
500 return JSValue::encode(result
);
504 RELEASE_ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here
505 return JSValue::encode(JSValue());
508 template <class Parent
>
509 void JSCallbackObject
<Parent
>::getOwnNonIndexPropertyNames(JSObject
* object
, ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
)
511 JSCallbackObject
* thisObject
= jsCast
<JSCallbackObject
*>(object
);
512 JSContextRef execRef
= toRef(exec
);
513 JSObjectRef thisRef
= toRef(thisObject
);
515 for (JSClassRef jsClass
= thisObject
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
516 if (JSObjectGetPropertyNamesCallback getPropertyNames
= jsClass
->getPropertyNames
) {
517 JSLock::DropAllLocks
dropAllLocks(exec
);
518 getPropertyNames(execRef
, thisRef
, toRef(&propertyNames
));
521 if (OpaqueJSClassStaticValuesTable
* staticValues
= jsClass
->staticValues(exec
)) {
522 typedef OpaqueJSClassStaticValuesTable::const_iterator iterator
;
523 iterator end
= staticValues
->end();
524 for (iterator it
= staticValues
->begin(); it
!= end
; ++it
) {
525 StringImpl
* name
= it
->key
.get();
526 StaticValueEntry
* entry
= it
->value
.get();
527 if (entry
->getProperty
&& (!(entry
->attributes
& kJSPropertyAttributeDontEnum
) || mode
.includeDontEnumProperties())) {
528 ASSERT(!name
->isSymbol());
529 propertyNames
.add(Identifier::fromString(exec
, String(name
)));
534 if (OpaqueJSClassStaticFunctionsTable
* staticFunctions
= jsClass
->staticFunctions(exec
)) {
535 typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator
;
536 iterator end
= staticFunctions
->end();
537 for (iterator it
= staticFunctions
->begin(); it
!= end
; ++it
) {
538 StringImpl
* name
= it
->key
.get();
539 StaticFunctionEntry
* entry
= it
->value
.get();
540 if (!(entry
->attributes
& kJSPropertyAttributeDontEnum
) || mode
.includeDontEnumProperties()) {
541 ASSERT(!name
->isSymbol());
542 propertyNames
.add(Identifier::fromString(exec
, String(name
)));
548 Parent::getOwnNonIndexPropertyNames(thisObject
, exec
, propertyNames
, mode
);
551 template <class Parent
>
552 void JSCallbackObject
<Parent
>::setPrivate(void* data
)
554 m_callbackObjectData
->privateData
= data
;
557 template <class Parent
>
558 void* JSCallbackObject
<Parent
>::getPrivate()
560 return m_callbackObjectData
->privateData
;
563 template <class Parent
>
564 bool JSCallbackObject
<Parent
>::inherits(JSClassRef c
) const
566 for (JSClassRef jsClass
= classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
573 template <class Parent
>
574 JSValue JSCallbackObject
<Parent
>::getStaticValue(ExecState
* exec
, PropertyName propertyName
)
576 JSObjectRef thisRef
= toRef(this);
578 if (StringImpl
* name
= propertyName
.uid()) {
579 for (JSClassRef jsClass
= classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
580 if (OpaqueJSClassStaticValuesTable
* staticValues
= jsClass
->staticValues(exec
)) {
581 if (StaticValueEntry
* entry
= staticValues
->get(name
)) {
582 if (JSObjectGetPropertyCallback getProperty
= entry
->getProperty
) {
583 JSValueRef exception
= 0;
586 JSLock::DropAllLocks
dropAllLocks(exec
);
587 value
= getProperty(toRef(exec
), thisRef
, entry
->propertyNameRef
.get(), &exception
);
590 exec
->vm().throwException(exec
, toJS(exec
, exception
));
591 return jsUndefined();
594 return toJS(exec
, value
);
604 template <class Parent
>
605 EncodedJSValue JSCallbackObject
<Parent
>::staticFunctionGetter(ExecState
* exec
, JSObject
* slotParent
, EncodedJSValue
, PropertyName propertyName
)
607 JSCallbackObject
* thisObj
= asCallbackObject(slotParent
);
609 // Check for cached or override property.
610 PropertySlot
slot2(thisObj
);
611 if (Parent::getOwnPropertySlot(thisObj
, exec
, propertyName
, slot2
))
612 return JSValue::encode(slot2
.getValue(exec
, propertyName
));
614 if (StringImpl
* name
= propertyName
.uid()) {
615 for (JSClassRef jsClass
= thisObj
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
616 if (OpaqueJSClassStaticFunctionsTable
* staticFunctions
= jsClass
->staticFunctions(exec
)) {
617 if (StaticFunctionEntry
* entry
= staticFunctions
->get(name
)) {
618 if (JSObjectCallAsFunctionCallback callAsFunction
= entry
->callAsFunction
) {
620 JSObject
* o
= JSCallbackFunction::create(vm
, thisObj
->globalObject(), callAsFunction
, name
);
621 thisObj
->putDirect(vm
, propertyName
, o
, entry
->attributes
);
622 return JSValue::encode(o
);
629 return JSValue::encode(exec
->vm().throwException(exec
, createReferenceError(exec
, ASCIILiteral("Static function property defined with NULL callAsFunction callback."))));
632 template <class Parent
>
633 EncodedJSValue JSCallbackObject
<Parent
>::callbackGetter(ExecState
* exec
, JSObject
* slotParent
, EncodedJSValue
, PropertyName propertyName
)
635 JSCallbackObject
* thisObj
= asCallbackObject(slotParent
);
637 JSObjectRef thisRef
= toRef(thisObj
);
638 RefPtr
<OpaqueJSString
> propertyNameRef
;
640 if (StringImpl
* name
= propertyName
.uid()) {
641 for (JSClassRef jsClass
= thisObj
->classRef(); jsClass
; jsClass
= jsClass
->parentClass
) {
642 if (JSObjectGetPropertyCallback getProperty
= jsClass
->getProperty
) {
643 if (!propertyNameRef
)
644 propertyNameRef
= OpaqueJSString::create(name
);
645 JSValueRef exception
= 0;
648 JSLock::DropAllLocks
dropAllLocks(exec
);
649 value
= getProperty(toRef(exec
), thisRef
, propertyNameRef
.get(), &exception
);
652 exec
->vm().throwException(exec
, toJS(exec
, exception
));
653 return JSValue::encode(jsUndefined());
656 return JSValue::encode(toJS(exec
, value
));
661 return JSValue::encode(exec
->vm().throwException(exec
, createReferenceError(exec
, ASCIILiteral("hasProperty callback returned true for a property that doesn't exist."))));