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

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

2009-05-01 Sam Weinig <[email protected]>

Reviewed by Geoff "The Minneapolis" Garen.

Add mechanism to vend heap allocated JS numbers to JavaScriptCore API clients with a
representation that is independent of the number representation in the VM.

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