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