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

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

Reviewed by Maciej.

  • Moved the arguments passed to JSClassCreate into a single structure, called JSClassDefinition. This will enable easier structure migration/versioning in the future, if necessary.


  • Added support for class names.


  • kJSClassDefinitionNull replaces kJSObjectCallbacksNone.


  • JSClass is becoming a fairly complex struct, so I migrated all of its implementation other than reference counting to the sruct.


  • Also moved JSClass* functions in the API to JSObjectRef.cpp, since they're declared in JSObjectRef.h


  • Also added some more informative explanation to the class structure doc.
File size: 16.4 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 "JSStringRef.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 (JSObjectInitializeCallback initialize = jsClass->initialize)
63 initialize(context, thisRef, toRef(exec->exceptionSlot()));
64 } while ((jsClass = jsClass->parentClass));
65}
66
67JSCallbackObject::~JSCallbackObject()
68{
69 JSObjectRef thisRef = toRef(this);
70
71 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
72 if (JSObjectFinalizeCallback finalize = jsClass->finalize)
73 finalize(thisRef);
74
75 JSClassRelease(m_class);
76}
77
78UString JSCallbackObject::className() const
79{
80 if (!m_class->className.isNull())
81 return m_class->className;
82
83 return JSObject::className();
84}
85
86bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
87{
88 JSContextRef context = toRef(exec);
89 JSObjectRef thisRef = toRef(this);
90 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
91
92 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
93 // optional optimization to bypass getProperty in cases when we only need to know if the property exists
94 if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) {
95 if (hasProperty(context, thisRef, propertyNameRef)) {
96 slot.setCustom(this, callbackGetter);
97 return true;
98 }
99 } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
100 if (JSValueRef value = getProperty(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot()))) {
101 // cache the value so we don't have to compute it again
102 // FIXME: This violates the PropertySlot design a little bit.
103 // We should either use this optimization everywhere, or nowhere.
104 slot.setCustom(reinterpret_cast<JSObject*>(toJS(value)), cachedValueGetter);
105 return true;
106 }
107 }
108
109 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
110 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
111 if (entry->getProperty) {
112 slot.setCustom(this, staticValueGetter);
113 return true;
114 }
115 }
116 }
117
118 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
119 if (staticFunctions->contains(propertyName.ustring().rep())) {
120 slot.setCustom(this, staticFunctionGetter);
121 return true;
122 }
123 }
124 }
125
126 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
127}
128
129bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
130{
131 return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
132}
133
134void JSCallbackObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
135{
136 JSContextRef context = toRef(exec);
137 JSObjectRef thisRef = toRef(this);
138 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
139 JSValueRef valueRef = toRef(value);
140
141 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
142 if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) {
143 if (setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
144 return;
145 }
146
147 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
148 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
149 if (entry->attributes & kJSPropertyAttributeReadOnly)
150 return;
151 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
152 if (setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
153 return;
154 }
155 }
156 }
157
158 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
159 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
160 if (entry->attributes & kJSPropertyAttributeReadOnly)
161 return;
162 putDirect(propertyName, value, attr); // put as override property
163 return;
164 }
165 }
166 }
167
168 return JSObject::put(exec, propertyName, value, attr);
169}
170
171void JSCallbackObject::put(ExecState* exec, unsigned propertyName, JSValue* value, int attr)
172{
173 return put(exec, Identifier::from(propertyName), value, attr);
174}
175
176bool JSCallbackObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
177{
178 JSContextRef context = toRef(exec);
179 JSObjectRef thisRef = toRef(this);
180 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
181
182 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
183 if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) {
184 if (deleteProperty(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
185 return true;
186 }
187
188 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
189 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
190 if (entry->attributes & kJSPropertyAttributeDontDelete)
191 return false;
192 return true;
193 }
194 }
195
196 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
197 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
198 if (entry->attributes & kJSPropertyAttributeDontDelete)
199 return false;
200 return true;
201 }
202 }
203 }
204
205 return JSObject::deleteProperty(exec, propertyName);
206}
207
208bool JSCallbackObject::deleteProperty(ExecState* exec, unsigned propertyName)
209{
210 return deleteProperty(exec, Identifier::from(propertyName));
211}
212
213bool JSCallbackObject::implementsConstruct() const
214{
215 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
216 if (jsClass->callAsConstructor)
217 return true;
218
219 return false;
220}
221
222JSObject* JSCallbackObject::construct(ExecState* exec, const List& args)
223{
224 JSContextRef execRef = toRef(exec);
225 JSObjectRef thisRef = toRef(this);
226
227 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
228 if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) {
229 size_t argumentCount = args.size();
230 JSValueRef arguments[argumentCount];
231 for (size_t i = 0; i < argumentCount; i++)
232 arguments[i] = toRef(args[i]);
233 return toJS(callAsConstructor(execRef, thisRef, argumentCount, arguments, toRef(exec->exceptionSlot())));
234 }
235 }
236
237 ASSERT(0); // implementsConstruct should prevent us from reaching here
238 return 0;
239}
240
241bool JSCallbackObject::implementsHasInstance() const
242{
243 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
244 if (jsClass->hasInstance)
245 return true;
246
247 return false;
248}
249
250bool JSCallbackObject::hasInstance(ExecState *exec, JSValue *value)
251{
252 JSContextRef execRef = toRef(exec);
253 JSObjectRef thisRef = toRef(this);
254
255 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
256 if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance)
257 return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
258
259 ASSERT(0); // implementsHasInstance should prevent us from reaching here
260 return 0;
261}
262
263
264bool JSCallbackObject::implementsCall() const
265{
266 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
267 if (jsClass->callAsFunction)
268 return true;
269
270 return false;
271}
272
273JSValue* JSCallbackObject::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
274{
275 JSContextRef execRef = toRef(exec);
276 JSObjectRef thisRef = toRef(this);
277 JSObjectRef thisObjRef = toRef(thisObj);
278
279 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
280 if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) {
281 size_t argumentCount = args.size();
282 JSValueRef arguments[argumentCount];
283 for (size_t i = 0; i < argumentCount; i++)
284 arguments[i] = toRef(args[i]);
285 return toJS(callAsFunction(execRef, thisRef, thisObjRef, argumentCount, arguments, toRef(exec->exceptionSlot())));
286 }
287 }
288
289 ASSERT(0); // implementsCall should prevent us from reaching here
290 return 0;
291}
292
293void JSCallbackObject::getPropertyList(ReferenceList& propertyList, bool recursive)
294{
295 JSObjectRef thisRef = toRef(this);
296
297 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
298 if (JSObjectAddPropertiesToListCallback addPropertiesToList = jsClass->addPropertiesToList)
299 addPropertiesToList(thisRef, toRef(&propertyList));
300
301 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
302 typedef __JSClass::StaticValuesTable::const_iterator iterator;
303 iterator end = staticValues->end();
304 for (iterator it = staticValues->begin(); it != end; ++it) {
305 UString::Rep* name = it->first.get();
306 StaticValueEntry* entry = it->second;
307 if (entry->getProperty && !(entry->attributes & kJSPropertyAttributeDontEnum))
308 propertyList.append(Reference(this, Identifier(name)));
309 }
310 }
311
312 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
313 typedef __JSClass::StaticFunctionsTable::const_iterator iterator;
314 iterator end = staticFunctions->end();
315 for (iterator it = staticFunctions->begin(); it != end; ++it) {
316 UString::Rep* name = it->first.get();
317 StaticFunctionEntry* entry = it->second;
318 if (!(entry->attributes & kJSPropertyAttributeDontEnum))
319 propertyList.append(Reference(this, Identifier(name)));
320 }
321 }
322 }
323
324 JSObject::getPropertyList(propertyList, recursive);
325}
326
327double JSCallbackObject::toNumber(ExecState* exec) const
328{
329 JSContextRef context = toRef(exec);
330 JSObjectRef thisRef = toRef(this);
331
332 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
333 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType)
334 if (JSValueRef value = convertToType(context, thisRef, kJSTypeNumber, toRef(exec->exceptionSlot())))
335 return toJS(value)->getNumber();
336
337 return JSObject::toNumber(exec);
338}
339
340UString JSCallbackObject::toString(ExecState* exec) const
341{
342 JSContextRef context = toRef(exec);
343 JSObjectRef thisRef = toRef(this);
344
345 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
346 if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType)
347 if (JSValueRef value = convertToType(context, thisRef, kJSTypeString, toRef(exec->exceptionSlot())))
348 return toJS(value)->getString();
349
350 return JSObject::toString(exec);
351}
352
353void JSCallbackObject::setPrivate(void* data)
354{
355 m_privateData = data;
356}
357
358void* JSCallbackObject::getPrivate()
359{
360 return m_privateData;
361}
362
363bool JSCallbackObject::inherits(JSClassRef c) const
364{
365 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
366 if (jsClass == c)
367 return true;
368
369 return false;
370}
371
372JSValue* JSCallbackObject::cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
373{
374 JSValue* v = slot.slotBase();
375 ASSERT(v);
376 return v;
377}
378
379JSValue* JSCallbackObject::staticValueGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
380{
381 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
382 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
383
384 JSObjectRef thisRef = toRef(thisObj);
385 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
386
387 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
388 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues)
389 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
390 if (JSObjectGetPropertyCallback getProperty = entry->getProperty)
391 if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
392 return toJS(value);
393
394 return jsUndefined();
395}
396
397JSValue* JSCallbackObject::staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
398{
399 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
400 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
401
402 if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
403 return cachedOrOverrideValue;
404
405 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass) {
406 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
407 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
408 JSValue* v = toJS(JSObjectMakeFunction(toRef(exec), entry->callAsFunction));
409 thisObj->putDirect(propertyName, v, entry->attributes);
410 return v;
411 }
412 }
413 }
414
415 return jsUndefined();
416}
417
418JSValue* JSCallbackObject::callbackGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
419{
420 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
421 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
422
423 JSObjectRef thisRef = toRef(thisObj);
424 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
425
426 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
427 if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty)
428 if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
429 return toJS(value);
430
431 return jsUndefined();
432}
433
434} // namespace KJS
Note: See TracBrowser for help on using the repository browser.