source: webkit/trunk/JavaScriptCore/API/JSCallbackObjectFunctions.h@ 52751

Last change on this file since 52751 was 52751, checked in by [email protected], 15 years ago

https://bugs.webkit.org/show_bug.cgi?id=33158
Refactor JSC API entry/exit to use RAII instead of copy/pasting code.
Make it easier to change set of actions taken when passing across the API boundary.

Reviewed by Sam "Shimmey Shimmey" Weinig.

  • API/APIShims.h: Added.

(JSC::APIEntryShimWithoutLock::APIEntryShimWithoutLock):
(JSC::APIEntryShimWithoutLock::~APIEntryShimWithoutLock):
(JSC::APIEntryShim::APIEntryShim):
(JSC::APICallbackShim::APICallbackShim):
(JSC::APICallbackShim::~APICallbackShim):

  • API/JSBase.cpp:

(JSEvaluateScript):
(JSCheckScriptSyntax):
(JSGarbageCollect):
(JSReportExtraMemoryCost):

  • API/JSCallbackConstructor.cpp:

(JSC::constructJSCallback):

  • API/JSCallbackFunction.cpp:

(JSC::JSCallbackFunction::call):

  • API/JSCallbackObjectFunctions.h:

(JSC::::init):
(JSC::::getOwnPropertySlot):
(JSC::::put):
(JSC::::deleteProperty):
(JSC::::construct):
(JSC::::hasInstance):
(JSC::::call):
(JSC::::getOwnPropertyNames):
(JSC::::toNumber):
(JSC::::toString):
(JSC::::staticValueGetter):
(JSC::::callbackGetter):

  • API/JSContextRef.cpp:
  • API/JSObjectRef.cpp:

(JSObjectMake):
(JSObjectMakeFunctionWithCallback):
(JSObjectMakeConstructor):
(JSObjectMakeFunction):
(JSObjectMakeArray):
(JSObjectMakeDate):
(JSObjectMakeError):
(JSObjectMakeRegExp):
(JSObjectGetPrototype):
(JSObjectSetPrototype):
(JSObjectHasProperty):
(JSObjectGetProperty):
(JSObjectSetProperty):
(JSObjectGetPropertyAtIndex):
(JSObjectSetPropertyAtIndex):
(JSObjectDeleteProperty):
(JSObjectCallAsFunction):
(JSObjectCallAsConstructor):
(JSObjectCopyPropertyNames):
(JSPropertyNameArrayRelease):
(JSPropertyNameAccumulatorAddName):

  • API/JSValueRef.cpp:

(JSValueGetType):
(JSValueIsUndefined):
(JSValueIsNull):
(JSValueIsBoolean):
(JSValueIsNumber):
(JSValueIsString):
(JSValueIsObject):
(JSValueIsObjectOfClass):
(JSValueIsEqual):
(JSValueIsStrictEqual):
(JSValueIsInstanceOfConstructor):
(JSValueMakeUndefined):
(JSValueMakeNull):
(JSValueMakeBoolean):
(JSValueMakeNumber):
(JSValueMakeString):
(JSValueToBoolean):
(JSValueToNumber):
(JSValueToStringCopy):
(JSValueToObject):
(JSValueProtect):
(JSValueUnprotect):

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