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