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

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

2010-03-01 Oliver Hunt <[email protected]>

Reviewed by Maciej Stachowiak.

Refactor named getter function signature to be in line with indexing getter signature
https://bugs.webkit.org/show_bug.cgi?id=35563

This removes the PropertySlot argument from getter functions, and makes them directly
pass the slot base. This makes the semantics for the functions match that of the
indexing getters.

On the down side, this means that we can no longer simply use a proxy function for
JS getters, so we now add another marker value to indicate that a getter is present
and branch accordingly.

Against all rationality sunspider reports this as a perf win, but i suspect it's just noise.

  • API/JSCallbackObject.h:
  • API/JSCallbackObjectFunctions.h: (JSC::::staticValueGetter): (JSC::::staticFunctionGetter): (JSC::::callbackGetter):
  • JavaScriptCore.exp:
  • runtime/JSActivation.cpp: (JSC::JSActivation::argumentsGetter):
  • runtime/JSActivation.h:
  • runtime/JSFunction.cpp: (JSC::JSFunction::argumentsGetter): (JSC::JSFunction::callerGetter): (JSC::JSFunction::lengthGetter):
  • runtime/JSFunction.h:
  • runtime/NumberConstructor.cpp: (JSC::numberConstructorNaNValue): (JSC::numberConstructorNegInfinity): (JSC::numberConstructorPosInfinity): (JSC::numberConstructorMaxValue): (JSC::numberConstructorMinValue):
  • runtime/PropertySlot.cpp: (JSC::PropertySlot::functionGetter):
  • runtime/PropertySlot.h: (JSC::PropertySlot::getValue): (JSC::PropertySlot::setGetterSlot): (JSC::PropertySlot::setCacheableGetterSlot):
  • runtime/RegExpConstructor.cpp: (JSC::regExpConstructorDollar1): (JSC::regExpConstructorDollar2): (JSC::regExpConstructorDollar3): (JSC::regExpConstructorDollar4): (JSC::regExpConstructorDollar5): (JSC::regExpConstructorDollar6): (JSC::regExpConstructorDollar7): (JSC::regExpConstructorDollar8): (JSC::regExpConstructorDollar9): (JSC::regExpConstructorInput): (JSC::regExpConstructorMultiline): (JSC::regExpConstructorLastMatch): (JSC::regExpConstructorLastParen): (JSC::regExpConstructorLeftContext): (JSC::regExpConstructorRightContext):
  • runtime/RegExpObject.cpp: (JSC::regExpObjectGlobal): (JSC::regExpObjectIgnoreCase): (JSC::regExpObjectMultiline): (JSC::regExpObjectSource): (JSC::regExpObjectLastIndex):

2010-03-01 Oliver Hunt <[email protected]>

Reviewed by Maciej Stachowiak.

Refactor named getter function signature to be in line with indexing getter signature
https://bugs.webkit.org/show_bug.cgi?id=35563

Fix method signature and update code as appropriate

  • UserObjectImp.cpp: (UserObjectImp::userObjectGetter):
  • UserObjectImp.h:

2010-03-01 Oliver Hunt <[email protected]>

Reviewed by Maciej Stachowiak.

Refactor named getter function signature to be in line with indexing getter signature
https://bugs.webkit.org/show_bug.cgi?id=35563

Fix up WebCore to use the new named getter function signature, update the
codegenerator to the new calling convention, and fix the custom bindings.

  • bindings/js/JSCSSStyleDeclarationCustom.cpp: (WebCore::JSCSSStyleDeclaration::nameGetter):
  • bindings/js/JSDOMBinding.cpp: (WebCore::objectToStringFunctionGetter):
  • bindings/js/JSDOMBinding.h:
  • bindings/js/JSDOMWindowCustom.cpp: (WebCore::nonCachingStaticFunctionGetter): (WebCore::childFrameGetter): (WebCore::namedItemGetter):
  • bindings/js/JSDataGridColumnListCustom.cpp: (WebCore::JSDataGridColumnList::nameGetter):
  • bindings/js/JSHTMLAllCollectionCustom.cpp: (WebCore::JSHTMLAllCollection::nameGetter):
  • bindings/js/JSHTMLCollectionCustom.cpp: (WebCore::JSHTMLCollection::nameGetter):
  • bindings/js/JSHTMLDocumentCustom.cpp: (WebCore::JSHTMLDocument::nameGetter):
  • bindings/js/JSHTMLFormElementCustom.cpp: (WebCore::JSHTMLFormElement::nameGetter):
  • bindings/js/JSHTMLFrameSetElementCustom.cpp: (WebCore::JSHTMLFrameSetElement::nameGetter):
  • bindings/js/JSHistoryCustom.cpp: (WebCore::nonCachingStaticBackFunctionGetter): (WebCore::nonCachingStaticForwardFunctionGetter): (WebCore::nonCachingStaticGoFunctionGetter):
  • bindings/js/JSLocationCustom.cpp: (WebCore::nonCachingStaticReplaceFunctionGetter): (WebCore::nonCachingStaticReloadFunctionGetter): (WebCore::nonCachingStaticAssignFunctionGetter):
  • bindings/js/JSMimeTypeArrayCustom.cpp: (WebCore::JSMimeTypeArray::nameGetter):
  • bindings/js/JSNamedNodeMapCustom.cpp: (WebCore::JSNamedNodeMap::nameGetter):
  • bindings/js/JSNodeListCustom.cpp: (WebCore::JSNodeList::nameGetter):
  • bindings/js/JSPluginArrayCustom.cpp: (WebCore::JSPluginArray::nameGetter):
  • bindings/js/JSPluginCustom.cpp: (WebCore::JSPlugin::nameGetter):
  • bindings/js/JSPluginElementFunctions.cpp: (WebCore::runtimeObjectPropertyGetter):
  • bindings/js/JSPluginElementFunctions.h:
  • bindings/js/JSStorageCustom.cpp: (WebCore::JSStorage::nameGetter):
  • bindings/js/JSStyleSheetListCustom.cpp: (WebCore::JSStyleSheetList::nameGetter):
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/runtime_array.cpp: (JSC::RuntimeArray::lengthGetter):
  • bridge/runtime_array.h:
  • bridge/runtime_method.cpp: (JSC::RuntimeMethod::lengthGetter):
  • bridge/runtime_method.h:
  • bridge/runtime_object.cpp: (JSC::Bindings::RuntimeObject::fallbackObjectGetter): (JSC::Bindings::RuntimeObject::fieldGetter): (JSC::Bindings::RuntimeObject::methodGetter):
  • bridge/runtime_object.h:
  • Property svn:eol-style set to native
File size: 23.2 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>
171bool JSCallbackObject<Base>::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
172{
173 PropertySlot slot;
174 if (getOwnPropertySlot(exec, propertyName, slot)) {
175 // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing.
176 JSValue value = slot.getValue(exec, propertyName);
177 if (!exec->hadException())
178 descriptor.setValue(value);
179 // We don't know whether the property is configurable, but assume it is.
180 descriptor.setConfigurable(true);
181 // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't.
182 descriptor.setEnumerable(false);
183 return true;
184 }
185
186 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
187}
188
189template <class Base>
190void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
191{
192 JSContextRef ctx = toRef(exec);
193 JSObjectRef thisRef = toRef(this);
194 RefPtr<OpaqueJSString> propertyNameRef;
195 JSValueRef valueRef = toRef(exec, value);
196
197 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) {
198 if (JSObjectSetPropertyCallback setProperty = jsClass->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 }
212
213 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) {
214 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
215 if (entry->attributes & kJSPropertyAttributeReadOnly)
216 return;
217 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
218 if (!propertyNameRef)
219 propertyNameRef = OpaqueJSString::create(propertyName.ustring());
220 JSValueRef exception = 0;
221 bool result;
222 {
223 APICallbackShim callbackShim(exec);
224 result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception);
225 }
226 if (exception)
227 exec->setException(toJS(exec, exception));
228 if (result || exception)
229 return;
230 } else
231 throwError(exec, ReferenceError, "Attempt to set a property that is not settable.");
232 }
233 }
234
235 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
236 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
237 if (entry->attributes & kJSPropertyAttributeReadOnly)
238 return;
239 JSCallbackObject<Base>::putDirect(propertyName, value); // put as override property
240 return;
241 }
242 }
243 }
244
245 return Base::put(exec, propertyName, value, slot);
246}
247
248template <class Base>
249bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, const Identifier& propertyName)
250{
251 JSContextRef ctx = toRef(exec);
252 JSObjectRef thisRef = toRef(this);
253 RefPtr<OpaqueJSString> propertyNameRef;
254
255 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) {
256 if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) {
257 if (!propertyNameRef)
258 propertyNameRef = OpaqueJSString::create(propertyName.ustring());
259 JSValueRef exception = 0;
260 bool result;
261 {
262 APICallbackShim callbackShim(exec);
263 result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception);
264 }
265 if (exception)
266 exec->setException(toJS(exec, exception));
267 if (result || exception)
268 return true;
269 }
270
271 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) {
272 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
273 if (entry->attributes & kJSPropertyAttributeDontDelete)
274 return false;
275 return true;
276 }
277 }
278
279 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
280 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
281 if (entry->attributes & kJSPropertyAttributeDontDelete)
282 return false;
283 return true;
284 }
285 }
286 }
287
288 return Base::deleteProperty(exec, propertyName);
289}
290
291template <class Base>
292bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, unsigned propertyName)
293{
294 return deleteProperty(exec, Identifier::from(exec, propertyName));
295}
296
297template <class Base>
298ConstructType JSCallbackObject<Base>::getConstructData(ConstructData& constructData)
299{
300 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) {
301 if (jsClass->callAsConstructor) {
302 constructData.native.function = construct;
303 return ConstructTypeHost;
304 }
305 }
306 return ConstructTypeNone;
307}
308
309template <class Base>
310JSObject* JSCallbackObject<Base>::construct(ExecState* exec, JSObject* constructor, const ArgList& args)
311{
312 JSContextRef execRef = toRef(exec);
313 JSObjectRef constructorRef = toRef(constructor);
314
315 for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) {
316 if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) {
317 int argumentCount = static_cast<int>(args.size());
318 Vector<JSValueRef, 16> arguments(argumentCount);
319 for (int i = 0; i < argumentCount; i++)
320 arguments[i] = toRef(exec, args.at(i));
321 JSValueRef exception = 0;
322 JSObject* result;
323 {
324 APICallbackShim callbackShim(exec);
325 result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception));
326 }
327 if (exception)
328 exec->setException(toJS(exec, exception));
329 return result;
330 }
331 }
332
333 ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here
334 return 0;
335}
336
337template <class Base>
338bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue value, JSValue)
339{
340 JSContextRef execRef = toRef(exec);
341 JSObjectRef thisRef = toRef(this);
342
343 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) {
344 if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) {
345 JSValueRef valueRef = toRef(exec, value);
346 JSValueRef exception = 0;
347 bool result;
348 {
349 APICallbackShim callbackShim(exec);
350 result = hasInstance(execRef, thisRef, valueRef, &exception);
351 }
352 if (exception)
353 exec->setException(toJS(exec, exception));
354 return result;
355 }
356 }
357 return false;
358}
359
360template <class Base>
361CallType JSCallbackObject<Base>::getCallData(CallData& callData)
362{
363 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) {
364 if (jsClass->callAsFunction) {
365 callData.native.function = call;
366 return CallTypeHost;
367 }
368 }
369 return CallTypeNone;
370}
371
372template <class Base>
373JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, JSValue thisValue, const ArgList& args)
374{
375 JSContextRef execRef = toRef(exec);
376 JSObjectRef functionRef = toRef(functionObject);
377 JSObjectRef thisObjRef = toRef(thisValue.toThisObject(exec));
378
379 for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(functionObject)->classRef(); jsClass; jsClass = jsClass->parentClass) {
380 if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) {
381 int argumentCount = static_cast<int>(args.size());
382 Vector<JSValueRef, 16> arguments(argumentCount);
383 for (int i = 0; i < argumentCount; i++)
384 arguments[i] = toRef(exec, args.at(i));
385 JSValueRef exception = 0;
386 JSValue result;
387 {
388 APICallbackShim callbackShim(exec);
389 result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception));
390 }
391 if (exception)
392 exec->setException(toJS(exec, exception));
393 return result;
394 }
395 }
396
397 ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here
398 return JSValue();
399}
400
401template <class Base>
402void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
403{
404 JSContextRef execRef = toRef(exec);
405 JSObjectRef thisRef = toRef(this);
406
407 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) {
408 if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) {
409 APICallbackShim callbackShim(exec);
410 getPropertyNames(execRef, thisRef, toRef(&propertyNames));
411 }
412
413 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) {
414 typedef OpaqueJSClassStaticValuesTable::const_iterator iterator;
415 iterator end = staticValues->end();
416 for (iterator it = staticValues->begin(); it != end; ++it) {
417 UString::Rep* name = it->first.get();
418 StaticValueEntry* entry = it->second;
419 if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)))
420 propertyNames.add(Identifier(exec, name));
421 }
422 }
423
424 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
425 typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator;
426 iterator end = staticFunctions->end();
427 for (iterator it = staticFunctions->begin(); it != end; ++it) {
428 UString::Rep* name = it->first.get();
429 StaticFunctionEntry* entry = it->second;
430 if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))
431 propertyNames.add(Identifier(exec, name));
432 }
433 }
434 }
435
436 Base::getOwnPropertyNames(exec, propertyNames, mode);
437}
438
439template <class Base>
440double JSCallbackObject<Base>::toNumber(ExecState* exec) const
441{
442 // We need this check to guard against the case where this object is rhs of
443 // a binary expression where lhs threw an exception in its conversion to
444 // primitive
445 if (exec->hadException())
446 return NaN;
447 JSContextRef ctx = toRef(exec);
448 JSObjectRef thisRef = toRef(this);
449
450 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass)
451 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
452 JSValueRef exception = 0;
453 JSValueRef value;
454 {
455 APICallbackShim callbackShim(exec);
456 value = convertToType(ctx, thisRef, kJSTypeNumber, &exception);
457 }
458 if (exception) {
459 exec->setException(toJS(exec, exception));
460 return 0;
461 }
462
463 double dValue;
464 if (value)
465 return toJS(exec, value).getNumber(dValue) ? dValue : NaN;
466 }
467
468 return Base::toNumber(exec);
469}
470
471template <class Base>
472UString JSCallbackObject<Base>::toString(ExecState* exec) const
473{
474 JSContextRef ctx = toRef(exec);
475 JSObjectRef thisRef = toRef(this);
476
477 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass)
478 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
479 JSValueRef exception = 0;
480 JSValueRef value;
481 {
482 APICallbackShim callbackShim(exec);
483 value = convertToType(ctx, thisRef, kJSTypeString, &exception);
484 }
485 if (exception) {
486 exec->setException(toJS(exec, exception));
487 return "";
488 }
489 if (value)
490 return toJS(exec, value).getString(exec);
491 }
492
493 return Base::toString(exec);
494}
495
496template <class Base>
497void JSCallbackObject<Base>::setPrivate(void* data)
498{
499 m_callbackObjectData->privateData = data;
500}
501
502template <class Base>
503void* JSCallbackObject<Base>::getPrivate()
504{
505 return m_callbackObjectData->privateData;
506}
507
508template <class Base>
509bool JSCallbackObject<Base>::inherits(JSClassRef c) const
510{
511 for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass)
512 if (jsClass == c)
513 return true;
514
515 return false;
516}
517
518template <class Base>
519JSValue JSCallbackObject<Base>::staticValueGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
520{
521 JSCallbackObject* thisObj = asCallbackObject(slotBase);
522
523 JSObjectRef thisRef = toRef(thisObj);
524 RefPtr<OpaqueJSString> propertyNameRef;
525
526 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass)
527 if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec))
528 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
529 if (JSObjectGetPropertyCallback getProperty = entry->getProperty) {
530 if (!propertyNameRef)
531 propertyNameRef = OpaqueJSString::create(propertyName.ustring());
532 JSValueRef exception = 0;
533 JSValueRef value;
534 {
535 APICallbackShim callbackShim(exec);
536 value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception);
537 }
538 if (exception) {
539 exec->setException(toJS(exec, exception));
540 return jsUndefined();
541 }
542 if (value)
543 return toJS(exec, value);
544 }
545
546 return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback.");
547}
548
549template <class Base>
550JSValue JSCallbackObject<Base>::staticFunctionGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
551{
552 JSCallbackObject* thisObj = asCallbackObject(slotBase);
553
554 // Check for cached or override property.
555 PropertySlot slot2(thisObj);
556 if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2))
557 return slot2.getValue(exec, propertyName);
558
559 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) {
560 if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
561 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
562 if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) {
563 JSObject* o = new (exec) JSCallbackFunction(exec, callAsFunction, propertyName);
564 thisObj->putDirect(propertyName, o, entry->attributes);
565 return o;
566 }
567 }
568 }
569 }
570
571 return throwError(exec, ReferenceError, "Static function property defined with NULL callAsFunction callback.");
572}
573
574template <class Base>
575JSValue JSCallbackObject<Base>::callbackGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
576{
577 JSCallbackObject* thisObj = asCallbackObject(slotBase);
578
579 JSObjectRef thisRef = toRef(thisObj);
580 RefPtr<OpaqueJSString> propertyNameRef;
581
582 for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass)
583 if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
584 if (!propertyNameRef)
585 propertyNameRef = OpaqueJSString::create(propertyName.ustring());
586 JSValueRef exception = 0;
587 JSValueRef value;
588 {
589 APICallbackShim callbackShim(exec);
590 value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception);
591 }
592 if (exception) {
593 exec->setException(toJS(exec, exception));
594 return jsUndefined();
595 }
596 if (value)
597 return toJS(exec, value);
598 }
599
600 return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist.");
601}
602
603} // namespace JSC
Note: See TracBrowser for help on using the repository browser.