Commit | Line | Data |
---|---|---|
b37bf2e1 | 1 | /* |
9dae56ea | 2 | * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. |
b37bf2e1 A |
3 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
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 | ||
f9bf01c6 | 27 | #include "APIShims.h" |
b37bf2e1 | 28 | #include "APICast.h" |
9dae56ea | 29 | #include "Error.h" |
14957cd0 | 30 | #include "ExceptionHelpers.h" |
b37bf2e1 A |
31 | #include "JSCallbackFunction.h" |
32 | #include "JSClassRef.h" | |
14957cd0 | 33 | #include "JSFunction.h" |
b37bf2e1 | 34 | #include "JSGlobalObject.h" |
9dae56ea A |
35 | #include "JSLock.h" |
36 | #include "JSObjectRef.h" | |
37 | #include "JSString.h" | |
b37bf2e1 | 38 | #include "JSStringRef.h" |
9dae56ea | 39 | #include "OpaqueJSString.h" |
b37bf2e1 | 40 | #include "PropertyNameArray.h" |
b37bf2e1 A |
41 | #include <wtf/Vector.h> |
42 | ||
9dae56ea A |
43 | namespace JSC { |
44 | ||
6fe7ccc8 A |
45 | template <class Parent> |
46 | inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(JSValue value) | |
9dae56ea | 47 | { |
14957cd0 | 48 | ASSERT(asObject(value)->inherits(&s_info)); |
6fe7ccc8 | 49 | return jsCast<JSCallbackObject*>(asObject(value)); |
9dae56ea | 50 | } |
b37bf2e1 | 51 | |
6fe7ccc8 A |
52 | template <class Parent> |
53 | JSCallbackObject<Parent>::JSCallbackObject(ExecState* exec, Structure* structure, JSClassRef jsClass, void* data) | |
93a37866 | 54 | : Parent(exec->vm(), structure) |
14957cd0 | 55 | , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) |
b37bf2e1 | 56 | { |
b37bf2e1 A |
57 | } |
58 | ||
9dae56ea A |
59 | // Global object constructor. |
60 | // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. | |
6fe7ccc8 | 61 | template <class Parent> |
93a37866 A |
62 | JSCallbackObject<Parent>::JSCallbackObject(VM& vm, JSClassRef jsClass, Structure* structure) |
63 | : Parent(vm, structure) | |
14957cd0 | 64 | , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) |
b37bf2e1 | 65 | { |
b37bf2e1 A |
66 | } |
67 | ||
6fe7ccc8 A |
68 | template <class Parent> |
69 | void JSCallbackObject<Parent>::finishCreation(ExecState* exec) | |
70 | { | |
93a37866 | 71 | Base::finishCreation(exec->vm()); |
6fe7ccc8 A |
72 | ASSERT(Parent::inherits(&s_info)); |
73 | init(exec); | |
74 | } | |
75 | ||
76 | // This is just for Global object, so we can assume that Base::finishCreation is JSGlobalObject::finishCreation. | |
77 | template <class Parent> | |
93a37866 | 78 | void JSCallbackObject<Parent>::finishCreation(VM& vm) |
6fe7ccc8 A |
79 | { |
80 | ASSERT(Parent::inherits(&s_info)); | |
81 | ASSERT(Parent::isGlobalObject()); | |
93a37866 | 82 | Base::finishCreation(vm); |
6fe7ccc8 A |
83 | init(jsCast<JSGlobalObject*>(this)->globalExec()); |
84 | } | |
85 | ||
86 | template <class Parent> | |
87 | void JSCallbackObject<Parent>::init(ExecState* exec) | |
b37bf2e1 A |
88 | { |
89 | ASSERT(exec); | |
90 | ||
91 | Vector<JSObjectInitializeCallback, 16> initRoutines; | |
9dae56ea | 92 | JSClassRef jsClass = classRef(); |
b37bf2e1 A |
93 | do { |
94 | if (JSObjectInitializeCallback initialize = jsClass->initialize) | |
95 | initRoutines.append(initialize); | |
96 | } while ((jsClass = jsClass->parentClass)); | |
97 | ||
98 | // initialize from base to derived | |
99 | for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { | |
f9bf01c6 | 100 | APICallbackShim callbackShim(exec); |
b37bf2e1 A |
101 | JSObjectInitializeCallback initialize = initRoutines[i]; |
102 | initialize(toRef(exec), toRef(this)); | |
103 | } | |
b37bf2e1 | 104 | |
6fe7ccc8 A |
105 | for (JSClassRef jsClassPtr = classRef(); jsClassPtr; jsClassPtr = jsClassPtr->parentClass) { |
106 | if (jsClassPtr->finalize) { | |
107 | WeakSet::allocate(this, m_callbackObjectData.get(), classRef()); | |
108 | break; | |
109 | } | |
14957cd0 | 110 | } |
b37bf2e1 A |
111 | } |
112 | ||
6fe7ccc8 | 113 | template <class Parent> |
93a37866 | 114 | String JSCallbackObject<Parent>::className(const JSObject* object) |
b37bf2e1 | 115 | { |
6fe7ccc8 | 116 | const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object); |
93a37866 | 117 | String thisClassName = thisObject->classRef()->className(); |
ba379fdc | 118 | if (!thisClassName.isEmpty()) |
9dae56ea | 119 | return thisClassName; |
b37bf2e1 | 120 | |
6fe7ccc8 | 121 | return Parent::className(object); |
b37bf2e1 A |
122 | } |
123 | ||
6fe7ccc8 | 124 | template <class Parent> |
93a37866 | 125 | bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
b37bf2e1 | 126 | { |
6fe7ccc8 | 127 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); |
b37bf2e1 | 128 | JSContextRef ctx = toRef(exec); |
6fe7ccc8 | 129 | JSObjectRef thisRef = toRef(thisObject); |
9dae56ea | 130 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 131 | |
93a37866 A |
132 | if (StringImpl* name = propertyName.publicName()) { |
133 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
134 | // optional optimization to bypass getProperty in cases when we only need to know if the property exists | |
135 | if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { | |
136 | if (!propertyNameRef) | |
137 | propertyNameRef = OpaqueJSString::create(name); | |
f9bf01c6 | 138 | APICallbackShim callbackShim(exec); |
93a37866 A |
139 | if (hasProperty(ctx, thisRef, propertyNameRef.get())) { |
140 | slot.setCustom(thisObject, callbackGetter); | |
141 | return true; | |
142 | } | |
143 | } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { | |
144 | if (!propertyNameRef) | |
145 | propertyNameRef = OpaqueJSString::create(name); | |
146 | JSValueRef exception = 0; | |
147 | JSValueRef value; | |
148 | { | |
149 | APICallbackShim callbackShim(exec); | |
150 | value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); | |
151 | } | |
152 | if (exception) { | |
153 | throwError(exec, toJS(exec, exception)); | |
154 | slot.setValue(jsUndefined()); | |
155 | return true; | |
156 | } | |
14957cd0 | 157 | if (value) { |
93a37866 | 158 | slot.setValue(toJS(exec, value)); |
14957cd0 A |
159 | return true; |
160 | } | |
b37bf2e1 | 161 | } |
93a37866 A |
162 | |
163 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { | |
164 | if (staticValues->contains(name)) { | |
165 | JSValue value = thisObject->getStaticValue(exec, propertyName); | |
166 | if (value) { | |
167 | slot.setValue(value); | |
168 | return true; | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
173 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { | |
174 | if (staticFunctions->contains(name)) { | |
175 | slot.setCustom(thisObject, staticFunctionGetter); | |
176 | return true; | |
177 | } | |
b37bf2e1 A |
178 | } |
179 | } | |
180 | } | |
93a37866 | 181 | |
6fe7ccc8 A |
182 | return Parent::getOwnPropertySlot(thisObject, exec, propertyName, slot); |
183 | } | |
184 | ||
93a37866 A |
185 | template <class Parent> |
186 | bool JSCallbackObject<Parent>::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot) | |
187 | { | |
188 | return cell->methodTable()->getOwnPropertySlot(cell, exec, Identifier::from(exec, propertyName), slot); | |
189 | } | |
190 | ||
6fe7ccc8 A |
191 | template <class Parent> |
192 | JSValue JSCallbackObject<Parent>::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint) | |
193 | { | |
194 | const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object); | |
195 | JSContextRef ctx = toRef(exec); | |
196 | JSObjectRef thisRef = toRef(thisObject); | |
197 | ::JSType jsHint = hint == PreferString ? kJSTypeString : kJSTypeNumber; | |
198 | ||
199 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
200 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { | |
201 | JSValueRef exception = 0; | |
202 | JSValueRef result = convertToType(ctx, thisRef, jsHint, &exception); | |
203 | if (exception) { | |
204 | throwError(exec, toJS(exec, exception)); | |
205 | return jsUndefined(); | |
206 | } | |
207 | if (result) | |
208 | return toJS(exec, result); | |
209 | } | |
210 | } | |
211 | ||
212 | return Parent::defaultValue(object, exec, hint); | |
b37bf2e1 A |
213 | } |
214 | ||
6fe7ccc8 | 215 | template <class Parent> |
93a37866 | 216 | bool JSCallbackObject<Parent>::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) |
f9bf01c6 | 217 | { |
6fe7ccc8 | 218 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); |
93a37866 | 219 | PropertySlot slot(thisObject); |
6fe7ccc8 | 220 | if (thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot)) { |
f9bf01c6 A |
221 | // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing. |
222 | JSValue value = slot.getValue(exec, propertyName); | |
223 | if (!exec->hadException()) | |
224 | descriptor.setValue(value); | |
225 | // We don't know whether the property is configurable, but assume it is. | |
226 | descriptor.setConfigurable(true); | |
227 | // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't. | |
228 | descriptor.setEnumerable(false); | |
229 | return true; | |
230 | } | |
231 | ||
6fe7ccc8 | 232 | return Parent::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); |
f9bf01c6 A |
233 | } |
234 | ||
6fe7ccc8 | 235 | template <class Parent> |
93a37866 | 236 | void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) |
b37bf2e1 | 237 | { |
6fe7ccc8 | 238 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); |
b37bf2e1 | 239 | JSContextRef ctx = toRef(exec); |
6fe7ccc8 | 240 | JSObjectRef thisRef = toRef(thisObject); |
9dae56ea | 241 | RefPtr<OpaqueJSString> propertyNameRef; |
ba379fdc | 242 | JSValueRef valueRef = toRef(exec, value); |
b37bf2e1 | 243 | |
93a37866 A |
244 | if (StringImpl* name = propertyName.publicName()) { |
245 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
246 | if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { | |
247 | if (!propertyNameRef) | |
248 | propertyNameRef = OpaqueJSString::create(name); | |
249 | JSValueRef exception = 0; | |
250 | bool result; | |
251 | { | |
252 | APICallbackShim callbackShim(exec); | |
253 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); | |
254 | } | |
255 | if (exception) | |
256 | throwError(exec, toJS(exec, exception)); | |
257 | if (result || exception) | |
258 | return; | |
259 | } | |
260 | ||
261 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { | |
262 | if (StaticValueEntry* entry = staticValues->get(name)) { | |
263 | if (entry->attributes & kJSPropertyAttributeReadOnly) | |
264 | return; | |
265 | if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { | |
266 | if (!propertyNameRef) | |
267 | propertyNameRef = OpaqueJSString::create(name); | |
268 | JSValueRef exception = 0; | |
269 | bool result; | |
270 | { | |
271 | APICallbackShim callbackShim(exec); | |
272 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); | |
273 | } | |
274 | if (exception) | |
275 | throwError(exec, toJS(exec, exception)); | |
276 | if (result || exception) | |
277 | return; | |
278 | } | |
279 | } | |
280 | } | |
281 | ||
282 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { | |
283 | if (StaticFunctionEntry* entry = staticFunctions->get(name)) { | |
284 | if (entry->attributes & kJSPropertyAttributeReadOnly) | |
285 | return; | |
286 | thisObject->JSCallbackObject<Parent>::putDirect(exec->vm(), propertyName, value); // put as override property | |
287 | return; | |
288 | } | |
289 | } | |
290 | } | |
291 | } | |
292 | ||
293 | return Parent::put(thisObject, exec, propertyName, value, slot); | |
294 | } | |
295 | ||
296 | template <class Parent> | |
297 | void JSCallbackObject<Parent>::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyIndex, JSValue value, bool shouldThrow) | |
298 | { | |
299 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); | |
300 | JSContextRef ctx = toRef(exec); | |
301 | JSObjectRef thisRef = toRef(thisObject); | |
302 | RefPtr<OpaqueJSString> propertyNameRef; | |
303 | JSValueRef valueRef = toRef(exec, value); | |
304 | Identifier propertyName = Identifier(exec, String::number(propertyIndex)); | |
305 | ||
6fe7ccc8 | 306 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 307 | if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { |
9dae56ea | 308 | if (!propertyNameRef) |
93a37866 | 309 | propertyNameRef = OpaqueJSString::create(propertyName.impl()); |
ba379fdc A |
310 | JSValueRef exception = 0; |
311 | bool result; | |
312 | { | |
f9bf01c6 | 313 | APICallbackShim callbackShim(exec); |
ba379fdc A |
314 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
315 | } | |
f9bf01c6 | 316 | if (exception) |
14957cd0 | 317 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 318 | if (result || exception) |
b37bf2e1 A |
319 | return; |
320 | } | |
93a37866 | 321 | |
9dae56ea | 322 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
14957cd0 | 323 | if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { |
b37bf2e1 A |
324 | if (entry->attributes & kJSPropertyAttributeReadOnly) |
325 | return; | |
326 | if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { | |
9dae56ea | 327 | if (!propertyNameRef) |
93a37866 | 328 | propertyNameRef = OpaqueJSString::create(propertyName.impl()); |
ba379fdc A |
329 | JSValueRef exception = 0; |
330 | bool result; | |
331 | { | |
f9bf01c6 | 332 | APICallbackShim callbackShim(exec); |
ba379fdc A |
333 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
334 | } | |
f9bf01c6 | 335 | if (exception) |
14957cd0 | 336 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 337 | if (result || exception) |
b37bf2e1 | 338 | return; |
14957cd0 | 339 | } |
b37bf2e1 A |
340 | } |
341 | } | |
93a37866 | 342 | |
9dae56ea | 343 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
14957cd0 | 344 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { |
b37bf2e1 A |
345 | if (entry->attributes & kJSPropertyAttributeReadOnly) |
346 | return; | |
93a37866 | 347 | break; |
b37bf2e1 A |
348 | } |
349 | } | |
350 | } | |
93a37866 A |
351 | |
352 | return Parent::putByIndex(thisObject, exec, propertyIndex, value, shouldThrow); | |
b37bf2e1 A |
353 | } |
354 | ||
6fe7ccc8 | 355 | template <class Parent> |
93a37866 | 356 | bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) |
b37bf2e1 | 357 | { |
6fe7ccc8 | 358 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); |
b37bf2e1 | 359 | JSContextRef ctx = toRef(exec); |
6fe7ccc8 | 360 | JSObjectRef thisRef = toRef(thisObject); |
9dae56ea | 361 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 362 | |
93a37866 A |
363 | if (StringImpl* name = propertyName.publicName()) { |
364 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
365 | if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { | |
366 | if (!propertyNameRef) | |
367 | propertyNameRef = OpaqueJSString::create(name); | |
368 | JSValueRef exception = 0; | |
369 | bool result; | |
370 | { | |
371 | APICallbackShim callbackShim(exec); | |
372 | result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); | |
373 | } | |
374 | if (exception) | |
375 | throwError(exec, toJS(exec, exception)); | |
376 | if (result || exception) | |
377 | return true; | |
ba379fdc | 378 | } |
93a37866 A |
379 | |
380 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { | |
381 | if (StaticValueEntry* entry = staticValues->get(name)) { | |
382 | if (entry->attributes & kJSPropertyAttributeDontDelete) | |
383 | return false; | |
384 | return true; | |
385 | } | |
b37bf2e1 | 386 | } |
93a37866 A |
387 | |
388 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { | |
389 | if (StaticFunctionEntry* entry = staticFunctions->get(name)) { | |
390 | if (entry->attributes & kJSPropertyAttributeDontDelete) | |
391 | return false; | |
392 | return true; | |
393 | } | |
b37bf2e1 A |
394 | } |
395 | } | |
396 | } | |
93a37866 | 397 | |
6fe7ccc8 | 398 | return Parent::deleteProperty(thisObject, exec, propertyName); |
b37bf2e1 A |
399 | } |
400 | ||
6fe7ccc8 A |
401 | template <class Parent> |
402 | bool JSCallbackObject<Parent>::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) | |
b37bf2e1 | 403 | { |
6fe7ccc8 A |
404 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); |
405 | return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, propertyName)); | |
b37bf2e1 A |
406 | } |
407 | ||
6fe7ccc8 A |
408 | template <class Parent> |
409 | ConstructType JSCallbackObject<Parent>::getConstructData(JSCell* cell, ConstructData& constructData) | |
b37bf2e1 | 410 | { |
6fe7ccc8 A |
411 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); |
412 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
9dae56ea A |
413 | if (jsClass->callAsConstructor) { |
414 | constructData.native.function = construct; | |
415 | return ConstructTypeHost; | |
416 | } | |
417 | } | |
418 | return ConstructTypeNone; | |
b37bf2e1 A |
419 | } |
420 | ||
6fe7ccc8 A |
421 | template <class Parent> |
422 | EncodedJSValue JSCallbackObject<Parent>::construct(ExecState* exec) | |
b37bf2e1 | 423 | { |
14957cd0 | 424 | JSObject* constructor = exec->callee(); |
b37bf2e1 | 425 | JSContextRef execRef = toRef(exec); |
9dae56ea | 426 | JSObjectRef constructorRef = toRef(constructor); |
b37bf2e1 | 427 | |
6fe7ccc8 | 428 | for (JSClassRef jsClass = jsCast<JSCallbackObject<Parent>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 429 | if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { |
93a37866 A |
430 | size_t argumentCount = exec->argumentCount(); |
431 | Vector<JSValueRef, 16> arguments; | |
432 | arguments.reserveInitialCapacity(argumentCount); | |
433 | for (size_t i = 0; i < argumentCount; ++i) | |
434 | arguments.uncheckedAppend(toRef(exec, exec->argument(i))); | |
ba379fdc A |
435 | JSValueRef exception = 0; |
436 | JSObject* result; | |
437 | { | |
f9bf01c6 | 438 | APICallbackShim callbackShim(exec); |
ba379fdc A |
439 | result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); |
440 | } | |
f9bf01c6 | 441 | if (exception) |
14957cd0 A |
442 | throwError(exec, toJS(exec, exception)); |
443 | return JSValue::encode(result); | |
b37bf2e1 A |
444 | } |
445 | } | |
446 | ||
93a37866 | 447 | RELEASE_ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here |
14957cd0 | 448 | return JSValue::encode(JSValue()); |
b37bf2e1 A |
449 | } |
450 | ||
6fe7ccc8 | 451 | template <class Parent> |
93a37866 | 452 | bool JSCallbackObject<Parent>::customHasInstance(JSObject* object, ExecState* exec, JSValue value) |
b37bf2e1 | 453 | { |
6fe7ccc8 | 454 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); |
b37bf2e1 | 455 | JSContextRef execRef = toRef(exec); |
6fe7ccc8 | 456 | JSObjectRef thisRef = toRef(thisObject); |
b37bf2e1 | 457 | |
6fe7ccc8 | 458 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 459 | if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) { |
ba379fdc A |
460 | JSValueRef valueRef = toRef(exec, value); |
461 | JSValueRef exception = 0; | |
462 | bool result; | |
463 | { | |
f9bf01c6 | 464 | APICallbackShim callbackShim(exec); |
ba379fdc A |
465 | result = hasInstance(execRef, thisRef, valueRef, &exception); |
466 | } | |
f9bf01c6 | 467 | if (exception) |
14957cd0 | 468 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 469 | return result; |
b37bf2e1 | 470 | } |
9dae56ea A |
471 | } |
472 | return false; | |
b37bf2e1 A |
473 | } |
474 | ||
6fe7ccc8 A |
475 | template <class Parent> |
476 | CallType JSCallbackObject<Parent>::getCallData(JSCell* cell, CallData& callData) | |
b37bf2e1 | 477 | { |
6fe7ccc8 A |
478 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); |
479 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
9dae56ea A |
480 | if (jsClass->callAsFunction) { |
481 | callData.native.function = call; | |
482 | return CallTypeHost; | |
483 | } | |
484 | } | |
485 | return CallTypeNone; | |
b37bf2e1 A |
486 | } |
487 | ||
6fe7ccc8 A |
488 | template <class Parent> |
489 | EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec) | |
b37bf2e1 A |
490 | { |
491 | JSContextRef execRef = toRef(exec); | |
14957cd0 A |
492 | JSObjectRef functionRef = toRef(exec->callee()); |
493 | JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); | |
b37bf2e1 | 494 | |
6fe7ccc8 | 495 | for (JSClassRef jsClass = jsCast<JSCallbackObject<Parent>*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 496 | if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { |
93a37866 A |
497 | size_t argumentCount = exec->argumentCount(); |
498 | Vector<JSValueRef, 16> arguments; | |
499 | arguments.reserveInitialCapacity(argumentCount); | |
500 | for (size_t i = 0; i < argumentCount; ++i) | |
501 | arguments.uncheckedAppend(toRef(exec, exec->argument(i))); | |
ba379fdc A |
502 | JSValueRef exception = 0; |
503 | JSValue result; | |
504 | { | |
f9bf01c6 | 505 | APICallbackShim callbackShim(exec); |
ba379fdc A |
506 | result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); |
507 | } | |
f9bf01c6 | 508 | if (exception) |
14957cd0 A |
509 | throwError(exec, toJS(exec, exception)); |
510 | return JSValue::encode(result); | |
b37bf2e1 A |
511 | } |
512 | } | |
513 | ||
93a37866 | 514 | RELEASE_ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here |
14957cd0 | 515 | return JSValue::encode(JSValue()); |
b37bf2e1 A |
516 | } |
517 | ||
6fe7ccc8 | 518 | template <class Parent> |
93a37866 | 519 | void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) |
b37bf2e1 | 520 | { |
6fe7ccc8 | 521 | JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); |
b37bf2e1 | 522 | JSContextRef execRef = toRef(exec); |
6fe7ccc8 | 523 | JSObjectRef thisRef = toRef(thisObject); |
b37bf2e1 | 524 | |
6fe7ccc8 | 525 | for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 526 | if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { |
f9bf01c6 | 527 | APICallbackShim callbackShim(exec); |
b37bf2e1 A |
528 | getPropertyNames(execRef, thisRef, toRef(&propertyNames)); |
529 | } | |
530 | ||
9dae56ea A |
531 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
532 | typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; | |
b37bf2e1 A |
533 | iterator end = staticValues->end(); |
534 | for (iterator it = staticValues->begin(); it != end; ++it) { | |
93a37866 A |
535 | StringImpl* name = it->key.get(); |
536 | StaticValueEntry* entry = it->value.get(); | |
f9bf01c6 | 537 | if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) |
9dae56ea | 538 | propertyNames.add(Identifier(exec, name)); |
b37bf2e1 A |
539 | } |
540 | } | |
541 | ||
9dae56ea A |
542 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
543 | typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; | |
b37bf2e1 A |
544 | iterator end = staticFunctions->end(); |
545 | for (iterator it = staticFunctions->begin(); it != end; ++it) { | |
93a37866 A |
546 | StringImpl* name = it->key.get(); |
547 | StaticFunctionEntry* entry = it->value.get(); | |
f9bf01c6 | 548 | if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) |
9dae56ea | 549 | propertyNames.add(Identifier(exec, name)); |
b37bf2e1 A |
550 | } |
551 | } | |
552 | } | |
553 | ||
93a37866 | 554 | Parent::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); |
b37bf2e1 A |
555 | } |
556 | ||
6fe7ccc8 A |
557 | template <class Parent> |
558 | void JSCallbackObject<Parent>::setPrivate(void* data) | |
b37bf2e1 | 559 | { |
9dae56ea | 560 | m_callbackObjectData->privateData = data; |
b37bf2e1 A |
561 | } |
562 | ||
6fe7ccc8 A |
563 | template <class Parent> |
564 | void* JSCallbackObject<Parent>::getPrivate() | |
b37bf2e1 | 565 | { |
9dae56ea | 566 | return m_callbackObjectData->privateData; |
b37bf2e1 A |
567 | } |
568 | ||
6fe7ccc8 A |
569 | template <class Parent> |
570 | bool JSCallbackObject<Parent>::inherits(JSClassRef c) const | |
b37bf2e1 | 571 | { |
93a37866 | 572 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 A |
573 | if (jsClass == c) |
574 | return true; | |
93a37866 | 575 | } |
b37bf2e1 A |
576 | return false; |
577 | } | |
578 | ||
6fe7ccc8 | 579 | template <class Parent> |
93a37866 | 580 | JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName propertyName) |
b37bf2e1 | 581 | { |
14957cd0 | 582 | JSObjectRef thisRef = toRef(this); |
9dae56ea | 583 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 584 | |
93a37866 A |
585 | if (StringImpl* name = propertyName.publicName()) { |
586 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { | |
587 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { | |
588 | if (StaticValueEntry* entry = staticValues->get(name)) { | |
589 | if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { | |
590 | if (!propertyNameRef) | |
591 | propertyNameRef = OpaqueJSString::create(name); | |
592 | JSValueRef exception = 0; | |
593 | JSValueRef value; | |
594 | { | |
595 | APICallbackShim callbackShim(exec); | |
596 | value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); | |
597 | } | |
598 | if (exception) { | |
599 | throwError(exec, toJS(exec, exception)); | |
600 | return jsUndefined(); | |
601 | } | |
602 | if (value) | |
603 | return toJS(exec, value); | |
ba379fdc | 604 | } |
b37bf2e1 | 605 | } |
93a37866 A |
606 | } |
607 | } | |
608 | } | |
f9bf01c6 | 609 | |
14957cd0 | 610 | return JSValue(); |
b37bf2e1 A |
611 | } |
612 | ||
6fe7ccc8 | 613 | template <class Parent> |
93a37866 | 614 | JSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, JSValue slotParent, PropertyName propertyName) |
b37bf2e1 | 615 | { |
6fe7ccc8 | 616 | JSCallbackObject* thisObj = asCallbackObject(slotParent); |
b37bf2e1 A |
617 | |
618 | // Check for cached or override property. | |
9dae56ea | 619 | PropertySlot slot2(thisObj); |
6fe7ccc8 | 620 | if (Parent::getOwnPropertySlot(thisObj, exec, propertyName, slot2)) |
9dae56ea | 621 | return slot2.getValue(exec, propertyName); |
b37bf2e1 | 622 | |
93a37866 A |
623 | if (StringImpl* name = propertyName.publicName()) { |
624 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
625 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { | |
626 | if (StaticFunctionEntry* entry = staticFunctions->get(name)) { | |
627 | if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { | |
628 | ||
629 | JSObject* o = JSCallbackFunction::create(exec, thisObj->globalObject(), callAsFunction, name); | |
630 | thisObj->putDirect(exec->vm(), propertyName, o, entry->attributes); | |
631 | return o; | |
632 | } | |
b37bf2e1 A |
633 | } |
634 | } | |
635 | } | |
636 | } | |
93a37866 A |
637 | |
638 | return throwError(exec, createReferenceError(exec, ASCIILiteral("Static function property defined with NULL callAsFunction callback."))); | |
b37bf2e1 A |
639 | } |
640 | ||
6fe7ccc8 | 641 | template <class Parent> |
93a37866 | 642 | JSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, JSValue slotParent, PropertyName propertyName) |
b37bf2e1 | 643 | { |
6fe7ccc8 | 644 | JSCallbackObject* thisObj = asCallbackObject(slotParent); |
b37bf2e1 A |
645 | |
646 | JSObjectRef thisRef = toRef(thisObj); | |
9dae56ea | 647 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 648 | |
93a37866 A |
649 | if (StringImpl* name = propertyName.publicName()) { |
650 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { | |
651 | if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { | |
652 | if (!propertyNameRef) | |
653 | propertyNameRef = OpaqueJSString::create(name); | |
654 | JSValueRef exception = 0; | |
655 | JSValueRef value; | |
656 | { | |
657 | APICallbackShim callbackShim(exec); | |
658 | value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); | |
659 | } | |
660 | if (exception) { | |
661 | throwError(exec, toJS(exec, exception)); | |
662 | return jsUndefined(); | |
663 | } | |
664 | if (value) | |
665 | return toJS(exec, value); | |
f9bf01c6 | 666 | } |
b37bf2e1 | 667 | } |
93a37866 A |
668 | } |
669 | ||
670 | return throwError(exec, createReferenceError(exec, ASCIILiteral("hasProperty callback returned true for a property that doesn't exist."))); | |
b37bf2e1 A |
671 | } |
672 | ||
9dae56ea | 673 | } // namespace JSC |