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

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

Reviewed by Darin.

Disable JSLock for per-thread contexts.

No change on SunSpider.

  • kjs/JSGlobalData.h:
  • kjs/JSGlobalData.cpp: (KJS::JSGlobalData::JSGlobalData): (KJS::JSGlobalData::sharedInstance): Added isSharedInstance as a better way to tell whether the instance is shared (legacy).
  • kjs/JSLock.cpp: (KJS::createJSLockCount): (KJS::JSLock::lockCount): (KJS::setLockCount): (KJS::JSLock::JSLock): (KJS::JSLock::lock): (KJS::JSLock::unlock): (KJS::JSLock::currentThreadIsHoldingLock): (KJS::JSLock::DropAllLocks::DropAllLocks): (KJS::JSLock::DropAllLocks::~DropAllLocks):
  • kjs/JSLock.h: (KJS::JSLock::JSLock): (KJS::JSLock::~JSLock): Made JSLock and JSLock::DropAllLocks constructors take a parameter to decide whether to actually lock a mutex, or only to increment recursion count. We cannot turn it into no-op if we want to keep existing assertions working. Made recursion count per-thread, now that locks may not lock.
  • API/JSBase.cpp: (JSEvaluateScript): Take JSLock after casting JSContextRef to ExecState* (which doesn't need locking in any case), so that a decision whether to actually lock can be made. (JSCheckScriptSyntax): Ditto. (JSGarbageCollect): Only lock while collecting the shared heap, not the per-thread one.
  • API/JSObjectRef.cpp: (JSClassCreate): Don't lock, as there is no reason to. (JSClassRetain): Ditto. (JSClassRelease): Ditto. (JSPropertyNameArrayRetain): Ditto. (JSPropertyNameArrayRelease): Only lock while deleting the array, as that may touch identifier table. (JSPropertyNameAccumulatorAddName): Adding a string also involves an identifier table lookup, and possibly modification.
  • API/JSStringRef.cpp: (JSStringCreateWithCharacters): (JSStringCreateWithUTF8CString): (JSStringRetain): (JSStringRelease): (JSStringGetUTF8CString): (JSStringIsEqual):
  • API/JSStringRefCF.cpp: (JSStringCreateWithCFString): JSStringRef operations other than releasing do not need locking.
  • VM/Machine.cpp: Don't include unused JSLock.h.
  • kjs/CollectorHeapIntrospector.cpp: (KJS::CollectorHeapIntrospector::statistics): Don't take the lock for real, as heap introspection pauses the process anyway. It seems that the existing code could cause deadlocks.
  • kjs/Shell.cpp: (functionGC): (main): (jscmain): The test tool uses a per-thread context, so no real locking is required.
  • kjs/collector.h: (KJS::Heap::setGCProtectNeedsLocking): Optionally protect m_protectedValues access with a per-heap mutex. This is only needed for WebCore Database code, which violates the "no data migration between threads" by using ProtectedPtr on a background thread. (KJS::Heap::isShared): Keep a shared flag here, as well.
  • kjs/protect.h: (KJS::::ProtectedPtr): (KJS::::~ProtectedPtr): (KJS::::operator): (KJS::operator==): (KJS::operator!=): ProtectedPtr is ony used from WebCore, so it doesn't need to take JSLock. An assertion in Heap::protect/unprotect guards agains possible future unlocked uses of ProtectedPtr in JSC.
  • kjs/collector.cpp: (KJS::Heap::Heap): Initialize m_isShared. (KJS::Heap::~Heap): No need to lock for real during destruction, but must keep assertions in sweep() working. (KJS::destroyRegisteredThread): Registered thread list is only accessed for shared heap, so locking is always needed here. (KJS::Heap::registerThread): Ditto. (KJS::Heap::markStackObjectsConservatively): Use m_isShared instead of comparing to a shared instance for a small speedup. (KJS::Heap::setGCProtectNeedsLocking): Create m_protectedValuesMutex. There is currently no way to undo this - and ideally, Database code will be fixed to lo longer require this quirk. (KJS::Heap::protect): Take m_protectedValuesMutex (if it exists) while accessing m_protectedValues. (KJS::Heap::unprotect): Ditto. (KJS::Heap::markProtectedObjects): Ditto. (KJS::Heap::protectedGlobalObjectCount): Ditto. (KJS::Heap::protectedObjectCount): Ditto. (KJS::Heap::protectedObjectTypeCounts): Ditto.
  • kjs/ustring.cpp:
  • kjs/ustring.h: Don't include JSLock.h, which is no longer used here. As a result, an explicit include had to be added to many files in JavaScriptGlue, WebCore and WebKit.
  • kjs/JSGlobalObject.cpp: (KJS::JSGlobalObject::init):
  • API/JSCallbackConstructor.cpp: (KJS::constructJSCallback):
  • API/JSCallbackFunction.cpp: (KJS::JSCallbackFunction::call):
  • API/JSCallbackObjectFunctions.h: (KJS::::init): (KJS::::getOwnPropertySlot): (KJS::::put): (KJS::::deleteProperty): (KJS::::construct): (KJS::::hasInstance): (KJS::::call): (KJS::::getPropertyNames): (KJS::::toNumber): (KJS::::toString): (KJS::::staticValueGetter): (KJS::::callbackGetter):
  • API/JSContextRef.cpp: (JSGlobalContextCreate): (JSGlobalContextRetain): (JSGlobalContextRelease):
  • API/JSValueRef.cpp: (JSValueIsEqual): (JSValueIsStrictEqual): (JSValueIsInstanceOfConstructor): (JSValueMakeNumber): (JSValueMakeString): (JSValueToNumber): (JSValueToStringCopy): (JSValueToObject): (JSValueProtect): (JSValueUnprotect):
  • JavaScriptCore.exp:
  • kjs/PropertyNameArray.h: (KJS::PropertyNameArray::globalData):
  • kjs/interpreter.cpp: (KJS::Interpreter::checkSyntax): (KJS::Interpreter::evaluate): Pass a parameter to JSLock/JSLock::DropAllLocks to decide whether the lock needs to be taken.
  • Property svn:eol-style set to native
File size: 19.8 KB
Line 
1// -*- mode: c++; c-basic-offset: 4 -*-
2/*
3 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Eric Seidel <[email protected]>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "APICast.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 "PropertyNameArray.h"
37#include <wtf/Vector.h>
38
39namespace KJS {
40
41template <class Base>
42JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype, void* data)
43 : Base(prototype)
44 , m_privateData(data)
45 , m_class(JSClassRetain(jsClass))
46{
47 init(exec);
48}
49
50// Global object constructor.
51// FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one.
52template <class Base>
53JSCallbackObject<Base>::JSCallbackObject(JSClassRef jsClass)
54 : m_privateData(0)
55 , m_class(JSClassRetain(jsClass))
56{
57 ASSERT(Base::isGlobalObject());
58 init(static_cast<JSGlobalObject*>(this)->globalExec());
59}
60
61template <class Base>
62void JSCallbackObject<Base>::init(ExecState* exec)
63{
64 ASSERT(exec);
65
66 Vector<JSObjectInitializeCallback, 16> initRoutines;
67 JSClassRef jsClass = m_class;
68 do {
69 if (JSObjectInitializeCallback initialize = jsClass->initialize)
70 initRoutines.append(initialize);
71 } while ((jsClass = jsClass->parentClass));
72
73 // initialize from base to derived
74 for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) {
75 JSLock::DropAllLocks dropAllLocks(exec);
76 JSObjectInitializeCallback initialize = initRoutines[i];
77 initialize(toRef(exec), toRef(this));
78 }
79}
80
81template <class Base>
82JSCallbackObject<Base>::~JSCallbackObject()
83{
84 JSObjectRef thisRef = toRef(this);
85
86 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
87 if (JSObjectFinalizeCallback finalize = jsClass->finalize) {
88 finalize(thisRef);
89 }
90
91 JSClassRelease(m_class);
92}
93
94template <class Base>
95UString JSCallbackObject<Base>::className() const
96{
97 if (!m_class->className.isNull())
98 return m_class->className;
99
100 return Base::className();
101}
102
103template <class Base>
104bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
105{
106 JSContextRef ctx = toRef(exec);
107 JSObjectRef thisRef = toRef(this);
108 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
109
110 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
111 // optional optimization to bypass getProperty in cases when we only need to know if the property exists
112 if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) {
113 JSLock::DropAllLocks dropAllLocks(exec);
114 if (hasProperty(ctx, thisRef, propertyNameRef)) {
115 slot.setCustom(this, callbackGetter);
116 return true;
117 }
118 } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
119 JSLock::DropAllLocks dropAllLocks(exec);
120 if (JSValueRef value = getProperty(ctx, thisRef, propertyNameRef, toRef(exec->exceptionSlot()))) {
121 // cache the value so we don't have to compute it again
122 // FIXME: This violates the PropertySlot design a little bit.
123 // We should either use this optimization everywhere, or nowhere.
124 slot.setCustom(reinterpret_cast<JSObject*>(toJS(value)), cachedValueGetter);
125 return true;
126 }
127 }
128
129 if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
130 if (staticValues->contains(propertyName.ustring().rep())) {
131 slot.setCustom(this, staticValueGetter);
132 return true;
133 }
134 }
135
136 if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
137 if (staticFunctions->contains(propertyName.ustring().rep())) {
138 slot.setCustom(this, staticFunctionGetter);
139 return true;
140 }
141 }
142 }
143
144 return Base::getOwnPropertySlot(exec, propertyName, slot);
145}
146
147template <class Base>
148bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
149{
150 return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
151}
152
153template <class Base>
154void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
155{
156 JSContextRef ctx = toRef(exec);
157 JSObjectRef thisRef = toRef(this);
158 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
159 JSValueRef valueRef = toRef(value);
160
161 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
162 if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) {
163 JSLock::DropAllLocks dropAllLocks(exec);
164 if (setProperty(ctx, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
165 return;
166 }
167
168 if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
169 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
170 if (entry->attributes & kJSPropertyAttributeReadOnly)
171 return;
172 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
173 JSLock::DropAllLocks dropAllLocks(exec);
174 if (setProperty(ctx, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
175 return;
176 } else
177 throwError(exec, ReferenceError, "Attempt to set a property that is not settable.");
178 }
179 }
180
181 if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
182 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
183 if (entry->attributes & kJSPropertyAttributeReadOnly)
184 return;
185 JSCallbackObject<Base>::putDirect(propertyName, value); // put as override property
186 return;
187 }
188 }
189 }
190
191 return Base::put(exec, propertyName, value);
192}
193
194template <class Base>
195void JSCallbackObject<Base>::put(ExecState* exec, unsigned propertyName, JSValue* value)
196{
197 return put(exec, Identifier::from(exec, propertyName), value);
198}
199
200template <class Base>
201bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, const Identifier& propertyName)
202{
203 JSContextRef ctx = toRef(exec);
204 JSObjectRef thisRef = toRef(this);
205 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
206
207 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
208 if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) {
209 JSLock::DropAllLocks dropAllLocks(exec);
210 if (deleteProperty(ctx, thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
211 return true;
212 }
213
214 if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
215 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
216 if (entry->attributes & kJSPropertyAttributeDontDelete)
217 return false;
218 return true;
219 }
220 }
221
222 if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
223 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
224 if (entry->attributes & kJSPropertyAttributeDontDelete)
225 return false;
226 return true;
227 }
228 }
229 }
230
231 return Base::deleteProperty(exec, propertyName);
232}
233
234template <class Base>
235bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, unsigned propertyName)
236{
237 return deleteProperty(exec, Identifier::from(exec, propertyName));
238}
239
240template <class Base>
241ConstructType JSCallbackObject<Base>::getConstructData(ConstructData& constructData)
242{
243 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
244 if (jsClass->callAsConstructor) {
245 constructData.native.function = construct;
246 return ConstructTypeNative;
247 }
248 }
249 return ConstructTypeNone;
250}
251
252template <class Base>
253JSObject* JSCallbackObject<Base>::construct(ExecState* exec, JSObject* constructor, const ArgList& args)
254{
255 JSContextRef execRef = toRef(exec);
256 JSObjectRef constructorRef = toRef(constructor);
257
258 for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) {
259 if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) {
260 int argumentCount = static_cast<int>(args.size());
261 Vector<JSValueRef, 16> arguments(argumentCount);
262 for (int i = 0; i < argumentCount; i++)
263 arguments[i] = toRef(args[i]);
264 JSLock::DropAllLocks dropAllLocks(exec);
265 return toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), toRef(exec->exceptionSlot())));
266 }
267 }
268
269 ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here
270 return 0;
271}
272
273template <class Base>
274bool JSCallbackObject<Base>::implementsHasInstance() const
275{
276 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
277 if (jsClass->hasInstance)
278 return true;
279
280 return false;
281}
282
283template <class Base>
284bool JSCallbackObject<Base>::hasInstance(ExecState *exec, JSValue *value)
285{
286 JSContextRef execRef = toRef(exec);
287 JSObjectRef thisRef = toRef(this);
288
289 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
290 if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) {
291 JSLock::DropAllLocks dropAllLocks(exec);
292 return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
293 }
294
295 ASSERT_NOT_REACHED(); // implementsHasInstance should prevent us from reaching here
296 return 0;
297}
298
299template <class Base>
300CallType JSCallbackObject<Base>::getCallData(CallData& callData)
301{
302 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
303 if (jsClass->callAsFunction) {
304 callData.native.function = call;
305 return CallTypeNative;
306 }
307 }
308 return CallTypeNone;
309}
310
311template <class Base>
312JSValue* JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, JSValue* thisValue, const ArgList& args)
313{
314 JSContextRef execRef = toRef(exec);
315 JSObjectRef functionRef = toRef(functionObject);
316 JSObjectRef thisObjRef = toRef(thisValue->toThisObject(exec));
317
318 for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(functionObject)->m_class; jsClass; jsClass = jsClass->parentClass) {
319 if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) {
320 int argumentCount = static_cast<int>(args.size());
321 Vector<JSValueRef, 16> arguments(argumentCount);
322 for (int i = 0; i < argumentCount; i++)
323 arguments[i] = toRef(args[i]);
324 JSLock::DropAllLocks dropAllLocks(exec);
325 return toJS(callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), toRef(exec->exceptionSlot())));
326 }
327 }
328
329 ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here
330 return 0;
331}
332
333template <class Base>
334void JSCallbackObject<Base>::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
335{
336 JSContextRef execRef = toRef(exec);
337 JSObjectRef thisRef = toRef(this);
338
339 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
340 if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) {
341 JSLock::DropAllLocks dropAllLocks(exec);
342 getPropertyNames(execRef, thisRef, toRef(&propertyNames));
343 }
344
345 if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
346 typedef OpaqueJSClass::StaticValuesTable::const_iterator iterator;
347 iterator end = staticValues->end();
348 for (iterator it = staticValues->begin(); it != end; ++it) {
349 UString::Rep* name = it->first.get();
350 StaticValueEntry* entry = it->second;
351 if (entry->getProperty && !(entry->attributes & kJSPropertyAttributeDontEnum))
352 propertyNames.add(Identifier(exec, name));
353 }
354 }
355
356 if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
357 typedef OpaqueJSClass::StaticFunctionsTable::const_iterator iterator;
358 iterator end = staticFunctions->end();
359 for (iterator it = staticFunctions->begin(); it != end; ++it) {
360 UString::Rep* name = it->first.get();
361 StaticFunctionEntry* entry = it->second;
362 if (!(entry->attributes & kJSPropertyAttributeDontEnum))
363 propertyNames.add(Identifier(exec, name));
364 }
365 }
366 }
367
368 Base::getPropertyNames(exec, propertyNames);
369}
370
371template <class Base>
372double JSCallbackObject<Base>::toNumber(ExecState* exec) const
373{
374 // We need this check to guard against the case where this object is rhs of
375 // a binary expression where lhs threw an exception in its conversion to
376 // primitive
377 if (exec->hadException())
378 return NaN;
379 JSContextRef ctx = toRef(exec);
380 JSObjectRef thisRef = toRef(this);
381
382 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
383 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
384 JSLock::DropAllLocks dropAllLocks(exec);
385 if (JSValueRef value = convertToType(ctx, thisRef, kJSTypeNumber, toRef(exec->exceptionSlot())))
386 return toJS(value)->getNumber();
387 }
388
389 return Base::toNumber(exec);
390}
391
392template <class Base>
393UString JSCallbackObject<Base>::toString(ExecState* exec) const
394{
395 JSContextRef ctx = toRef(exec);
396 JSObjectRef thisRef = toRef(this);
397
398 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
399 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
400 JSValueRef value;
401 {
402 JSLock::DropAllLocks dropAllLocks(exec);
403 value = convertToType(ctx, thisRef, kJSTypeString, toRef(exec->exceptionSlot()));
404 }
405 if (value)
406 return toJS(value)->getString();
407 }
408
409 return Base::toString(exec);
410}
411
412template <class Base>
413void JSCallbackObject<Base>::setPrivate(void* data)
414{
415 m_privateData = data;
416}
417
418template <class Base>
419void* JSCallbackObject<Base>::getPrivate()
420{
421 return m_privateData;
422}
423
424template <class Base>
425bool JSCallbackObject<Base>::inherits(JSClassRef c) const
426{
427 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
428 if (jsClass == c)
429 return true;
430
431 return false;
432}
433
434template <class Base>
435JSValue* JSCallbackObject<Base>::cachedValueGetter(ExecState*, const Identifier&, const PropertySlot& slot)
436{
437 JSValue* v = slot.slotBase();
438 ASSERT(v);
439 return v;
440}
441
442template <class Base>
443JSValue* JSCallbackObject<Base>::staticValueGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
444{
445 ASSERT(slot.slotBase()->isObject(&JSCallbackObject::info));
446 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
447
448 JSObjectRef thisRef = toRef(thisObj);
449 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
450
451 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
452 if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues)
453 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
454 if (JSObjectGetPropertyCallback getProperty = entry->getProperty) {
455 JSLock::DropAllLocks dropAllLocks(exec);
456 if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
457 return toJS(value);
458 }
459
460 return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback.");
461}
462
463template <class Base>
464JSValue* JSCallbackObject<Base>::staticFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
465{
466 ASSERT(slot.slotBase()->isObject(&JSCallbackObject::info));
467 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
468
469 // Check for cached or override property.
470 PropertySlot slot2(thisObj);
471 if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2))
472 return slot2.getValue(exec, propertyName);
473
474 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass) {
475 if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
476 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
477 if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) {
478 JSObject* o = new (exec) JSCallbackFunction(exec, callAsFunction, propertyName);
479 thisObj->putDirect(propertyName, o, entry->attributes);
480 return o;
481 }
482 }
483 }
484 }
485
486 return throwError(exec, ReferenceError, "Static function property defined with NULL callAsFunction callback.");
487}
488
489template <class Base>
490JSValue* JSCallbackObject<Base>::callbackGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
491{
492 ASSERT(slot.slotBase()->isObject(&JSCallbackObject::info));
493 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
494
495 JSObjectRef thisRef = toRef(thisObj);
496 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
497
498 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
499 if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
500 JSLock::DropAllLocks dropAllLocks(exec);
501 if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
502 return toJS(value);
503 }
504
505 return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist.");
506}
507
508} // namespace KJS
Note: See TracBrowser for help on using the repository browser.