JSCallbackObjectFunctions.h 29 KB

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