source: webkit/trunk/JavaScriptCore/API/JSCallbackObject.cpp@ 15317

Last change on this file since 15317 was 15317, checked in by ggaren, 19 years ago

Reviewed by Darin.


Added exception out parameter to API object callbacks, removed semi-bogus
JSContext(.*)Exception functions.


To make these calls syntactically simple, I added an exceptionSlot()
method to the ExecState class, which provides a JSValue slot in which to
store a JSValue* exception.

  • API/APICast.h: (toRef):
  • API/JSCallbackConstructor.cpp: (KJS::JSCallbackConstructor::construct):
  • API/JSCallbackFunction.cpp: (KJS::JSCallbackFunction::callAsFunction):
  • API/JSCallbackObject.cpp: (KJS::JSCallbackObject::init): (KJS::JSCallbackObject::getOwnPropertySlot): (KJS::JSCallbackObject::put): (KJS::JSCallbackObject::deleteProperty): (KJS::JSCallbackObject::construct): (KJS::JSCallbackObject::callAsFunction): (KJS::JSCallbackObject::getPropertyList): (KJS::JSCallbackObject::toBoolean): (KJS::JSCallbackObject::toNumber): (KJS::JSCallbackObject::toString): (KJS::JSCallbackObject::staticValueGetter): (KJS::JSCallbackObject::callbackGetter):
  • API/JSContextRef.cpp: (JSCheckSyntax):
  • API/JSContextRef.h:
  • API/JSNode.c: (JSNodePrototype_appendChild): (JSNodePrototype_removeChild): (JSNodePrototype_replaceChild): (JSNode_getNodeType): (JSNode_getChildNodes): (JSNode_getFirstChild): (JSNode_construct):
  • API/JSNode.h:
  • API/JSNodeList.c: (JSNodeListPrototype_item): (JSNodeList_length): (JSNodeList_getProperty):
  • API/JSObjectRef.h:
  • API/minidom.c: (print):
  • API/testapi.c: (MyObject_initialize): (MyObject_hasProperty): (MyObject_getProperty): (MyObject_setProperty): (MyObject_deleteProperty): (MyObject_getPropertyList): (MyObject_callAsFunction): (MyObject_callAsConstructor): (MyObject_convertToType): (print_callAsFunction): (myConstructor_callAsConstructor): (main):
  • JavaScriptCore.exp:
  • kjs/ExecState.h: (KJS::ExecState::exceptionHandle):
File size: 16.6 KB
Line 
1// -*- mode: c++; c-basic-offset: 4 -*-
2/*
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
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 "JSCallbackObject.h"
29#include "JSInternalStringRef.h"
30#include "JSClassRef.h"
31#include "JSObjectRef.h"
32#include "internal.h"
33#include "reference.h"
34#include "reference_list.h"
35
36namespace KJS {
37
38const ClassInfo JSCallbackObject::info = { "CallbackObject", 0, 0, 0 };
39
40JSCallbackObject::JSCallbackObject(JSContextRef context, JSClassRef jsClass)
41 : JSObject()
42{
43 init(context, jsClass);
44}
45
46JSCallbackObject::JSCallbackObject(JSContextRef context, JSClassRef jsClass, JSValue* prototype)
47 : JSObject(prototype)
48{
49 init(context, jsClass);
50}
51
52void JSCallbackObject::init(JSContextRef context, JSClassRef jsClass)
53{
54 ExecState* exec = toJS(context);
55
56 m_privateData = 0;
57 m_class = JSClassRetain(jsClass);
58
59 JSObjectRef thisRef = toRef(this);
60
61 do {
62 if (JSInitializeCallback initialize = jsClass->callbacks.initialize)
63 initialize(context, thisRef, toRef(exec->exceptionSlot()));
64 } while ((jsClass = jsClass->parent));
65}
66
67JSCallbackObject::~JSCallbackObject()
68{
69 JSObjectRef thisRef = toRef(this);
70
71 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
72 if (JSFinalizeCallback finalize = jsClass->callbacks.finalize)
73 finalize(thisRef);
74
75 JSClassRelease(m_class);
76}
77
78UString JSCallbackObject::className() const
79{
80 return classInfo()->className;
81}
82
83bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
84{
85 JSContextRef context = toRef(exec);
86 JSObjectRef thisRef = toRef(this);
87 JSInternalStringRef propertyNameRef = toRef(propertyName.ustring().rep());
88
89 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
90 // optional optimization to bypass getProperty in cases when we only need to know if the property exists
91 if (JSHasPropertyCallback hasPropertyCallback = jsClass->callbacks.hasProperty) {
92 if (hasPropertyCallback(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot()))) {
93 slot.setCustom(this, callbackGetter);
94 return true;
95 }
96 } else if (JSGetPropertyCallback getPropertyCallback = jsClass->callbacks.getProperty) {
97 JSValueRef returnValue;
98 if (getPropertyCallback(context, thisRef, propertyNameRef, &returnValue, toRef(exec->exceptionSlot()))) {
99 // cache the value so we don't have to compute it again
100 // FIXME: This violates the PropertySlot design a little bit.
101 // We should either use this optimization everywhere, or nowhere.
102 slot.setCustom(reinterpret_cast<JSObject*>(toJS(returnValue)), cachedValueGetter);
103 return true;
104 }
105 }
106
107 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
108 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
109 if (entry->getProperty) {
110 slot.setCustom(this, staticValueGetter);
111 return true;
112 }
113 }
114 }
115
116 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
117 if (staticFunctions->contains(propertyName.ustring().rep())) {
118 slot.setCustom(this, staticFunctionGetter);
119 return true;
120 }
121 }
122 }
123
124 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
125}
126
127bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
128{
129 return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
130}
131
132void JSCallbackObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
133{
134 JSContextRef context = toRef(exec);
135 JSObjectRef thisRef = toRef(this);
136 JSInternalStringRef propertyNameRef = toRef(propertyName.ustring().rep());
137 JSValueRef valueRef = toRef(value);
138
139 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
140 if (JSSetPropertyCallback setPropertyCallback = jsClass->callbacks.setProperty) {
141 if (setPropertyCallback(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
142 return;
143 }
144
145 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
146 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
147 if (entry->attributes & kJSPropertyAttributeReadOnly)
148 return;
149 if (JSSetPropertyCallback setPropertyCallback = entry->setProperty) {
150 if (setPropertyCallback(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
151 return;
152 }
153 }
154 }
155
156 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
157 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
158 if (entry->attributes & kJSPropertyAttributeReadOnly)
159 return;
160 putDirect(propertyName, value, attr); // put as override property
161 return;
162 }
163 }
164 }
165 return JSObject::put(exec, propertyName, value, attr);
166}
167
168void JSCallbackObject::put(ExecState* exec, unsigned propertyName, JSValue* value, int attr)
169{
170 return put(exec, Identifier::from(propertyName), value, attr);
171}
172
173bool JSCallbackObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
174{
175 JSContextRef context = toRef(exec);
176 JSObjectRef thisRef = toRef(this);
177 JSInternalStringRef propertyNameRef = toRef(propertyName.ustring().rep());
178
179 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
180 if (JSDeletePropertyCallback deletePropertyCallback = jsClass->callbacks.deleteProperty) {
181 if (deletePropertyCallback(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
182 return true;
183 }
184
185 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
186 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
187 if (entry->attributes & kJSPropertyAttributeDontDelete)
188 return false;
189 return true;
190 }
191 }
192
193 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
194 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
195 if (entry->attributes & kJSPropertyAttributeDontDelete)
196 return false;
197 return true;
198 }
199 }
200 }
201 return JSObject::deleteProperty(exec, propertyName);
202}
203
204bool JSCallbackObject::deleteProperty(ExecState* exec, unsigned propertyName)
205{
206 return deleteProperty(exec, Identifier::from(propertyName));
207}
208
209bool JSCallbackObject::implementsConstruct() const
210{
211 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
212 if (jsClass->callbacks.callAsConstructor)
213 return true;
214
215 return false;
216}
217
218JSObject* JSCallbackObject::construct(ExecState* exec, const List& args)
219{
220 JSContextRef execRef = toRef(exec);
221 JSObjectRef thisRef = toRef(this);
222
223 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
224 if (JSCallAsConstructorCallback callAsConstructorCallback = jsClass->callbacks.callAsConstructor) {
225 size_t argc = args.size();
226 JSValueRef argv[argc];
227 for (size_t i = 0; i < argc; i++)
228 argv[i] = toRef(args[i]);
229 return toJS(callAsConstructorCallback(execRef, thisRef, argc, argv, toRef(exec->exceptionSlot())));
230 }
231 }
232
233 ASSERT(0); // implementsConstruct should prevent us from reaching here
234 return 0;
235}
236
237bool JSCallbackObject::implementsCall() const
238{
239 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
240 if (jsClass->callbacks.callAsFunction)
241 return true;
242
243 return false;
244}
245
246JSValue* JSCallbackObject::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
247{
248 JSContextRef execRef = toRef(exec);
249 JSObjectRef thisRef = toRef(this);
250 JSObjectRef thisObjRef = toRef(thisObj);
251
252 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
253 if (JSCallAsFunctionCallback callAsFunctionCallback = jsClass->callbacks.callAsFunction) {
254 size_t argc = args.size();
255 JSValueRef argv[argc];
256 for (size_t i = 0; i < argc; i++)
257 argv[i] = toRef(args[i]);
258 return toJS(callAsFunctionCallback(execRef, thisRef, thisObjRef, argc, argv, toRef(exec->exceptionSlot())));
259 }
260 }
261
262 ASSERT(0); // implementsCall should prevent us from reaching here
263 return 0;
264}
265
266void JSCallbackObject::getPropertyList(ExecState* exec, ReferenceList& propertyList, bool recursive)
267{
268 JSContextRef context = toRef(exec);
269 JSObjectRef thisRef = toRef(this);
270
271 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
272 if (JSGetPropertyListCallback getPropertyListCallback = jsClass->callbacks.getPropertyList)
273 getPropertyListCallback(context, thisRef, toRef(&propertyList), toRef(exec->exceptionSlot()));
274
275 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
276 typedef __JSClass::StaticValuesTable::const_iterator iterator;
277 iterator end = staticValues->end();
278 for (iterator it = staticValues->begin(); it != end; ++it) {
279 UString::Rep* name = it->first.get();
280 StaticValueEntry* entry = it->second;
281 if (entry->getProperty && !(entry->attributes & kJSPropertyAttributeDontEnum))
282 propertyList.append(Reference(this, Identifier(name)));
283 }
284 }
285
286 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
287 typedef __JSClass::StaticFunctionsTable::const_iterator iterator;
288 iterator end = staticFunctions->end();
289 for (iterator it = staticFunctions->begin(); it != end; ++it) {
290 UString::Rep* name = it->first.get();
291 StaticFunctionEntry* entry = it->second;
292 if (!(entry->attributes & kJSPropertyAttributeDontEnum))
293 propertyList.append(Reference(this, Identifier(name)));
294 }
295 }
296 }
297
298 JSObject::getPropertyList(exec, propertyList, recursive);
299}
300
301bool JSCallbackObject::toBoolean(ExecState* exec) const
302{
303 JSContextRef context = toRef(exec);
304 JSObjectRef thisRef = toRef(this);
305
306 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
307 if (JSConvertToTypeCallback convertToTypeCallback = jsClass->callbacks.convertToType) {
308 JSValueRef returnValue;
309 if (convertToTypeCallback(context, thisRef, kJSTypeBoolean, &returnValue, toRef(exec->exceptionSlot())))
310 return toJS(returnValue)->getBoolean();
311 }
312 }
313 return JSObject::toBoolean(exec);
314}
315
316double JSCallbackObject::toNumber(ExecState* exec) const
317{
318 JSContextRef context = toRef(exec);
319 JSObjectRef thisRef = toRef(this);
320
321 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
322 if (JSConvertToTypeCallback convertToTypeCallback = jsClass->callbacks.convertToType) {
323 JSValueRef returnValue;
324 if (convertToTypeCallback(context, thisRef, kJSTypeNumber, &returnValue, toRef(exec->exceptionSlot())))
325 return toJS(returnValue)->getNumber();
326 }
327 }
328 return JSObject::toNumber(exec);
329}
330
331UString JSCallbackObject::toString(ExecState* exec) const
332{
333 JSContextRef context = toRef(exec);
334 JSObjectRef thisRef = toRef(this);
335
336 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
337 if (JSConvertToTypeCallback convertToTypeCallback = jsClass->callbacks.convertToType) {
338 JSValueRef returnValue;
339 if (convertToTypeCallback(context, thisRef, kJSTypeString, &returnValue, toRef(exec->exceptionSlot())))
340 return toJS(returnValue)->getString();
341 }
342 }
343 return JSObject::toString(exec);
344}
345
346void JSCallbackObject::setPrivate(void* data)
347{
348 m_privateData = data;
349}
350
351void* JSCallbackObject::getPrivate()
352{
353 return m_privateData;
354}
355
356bool JSCallbackObject::inherits(JSClassRef c) const
357{
358 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
359 if (jsClass == c)
360 return true;
361 return false;
362}
363
364JSValue* JSCallbackObject::cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
365{
366 JSValue* v = slot.slotBase();
367 ASSERT(v);
368 return v;
369}
370
371JSValue* JSCallbackObject::staticValueGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
372{
373 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
374 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
375
376 JSObjectRef thisRef = toRef(thisObj);
377 JSInternalStringRef propertyNameRef = toRef(propertyName.ustring().rep());
378
379 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent) {
380 JSValueRef returnValue;
381
382 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues)
383 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
384 if (JSGetPropertyCallback getPropertyCallback = entry->getProperty)
385 if (getPropertyCallback(toRef(exec), thisRef, propertyNameRef, &returnValue, toRef(exec->exceptionSlot())))
386 return toJS(returnValue);
387 }
388
389 return jsUndefined();
390}
391
392JSValue* JSCallbackObject::staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
393{
394 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
395 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
396
397 if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
398 return cachedOrOverrideValue;
399
400 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent) {
401 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
402 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
403 JSValue* v = toJS(JSFunctionMake(toRef(exec), entry->callAsFunction));
404 thisObj->putDirect(propertyName, v, entry->attributes);
405 return v;
406 }
407 }
408 }
409
410 return jsUndefined();
411}
412
413JSValue* JSCallbackObject::callbackGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
414{
415 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
416 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
417
418 JSObjectRef thisRef = toRef(thisObj);
419 JSInternalStringRef propertyNameRef = toRef(propertyName.ustring().rep());
420
421 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent) {
422 JSValueRef returnValue;
423
424 if (JSGetPropertyCallback getPropertyCallback = jsClass->callbacks.getProperty)
425 if (getPropertyCallback(toRef(exec), thisRef, propertyNameRef, &returnValue, toRef(exec->exceptionSlot())))
426 return toJS(returnValue);
427 }
428
429 return jsUndefined();
430}
431
432} // namespace KJS
Note: See TracBrowser for help on using the repository browser.