Object.mm 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. /****************************************************************************
  2. Copyright (c) 2016 Chukong Technologies Inc.
  3. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. #include "Object.hpp"
  22. #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_JSC
  23. #include "Utils.hpp"
  24. #include "Class.hpp"
  25. #include "ScriptEngine.hpp"
  26. #include "PlatformUtils.h"
  27. #include "../MappingUtils.hpp"
  28. #include "EJConvertTypedArray.h"
  29. namespace se {
  30. namespace {
  31. JSContextRef __cx = nullptr;
  32. #if SE_DEBUG > 0
  33. uint32_t __id = 0;
  34. #endif
  35. bool isInstanceOfConstructor(JSContextRef ctx, JSValueRef value, const char* ctorName)
  36. {
  37. if (ctorName == nullptr)
  38. return false;
  39. Object* global = ScriptEngine::getInstance()->getGlobalObject();
  40. Value ctorVal;
  41. bool ret = false;
  42. if (global->getProperty(ctorName, &ctorVal), ctorVal.isObject())
  43. {
  44. ret = JSValueIsInstanceOfConstructor(ctx, value, ctorVal.toObject()->_getJSObject(), nullptr);
  45. }
  46. return ret;
  47. }
  48. }
  49. Object::Object()
  50. : _cls(nullptr)
  51. , _obj(nullptr)
  52. , _privateData(nullptr)
  53. , _finalizeCb(nullptr)
  54. , _rootCount(0)
  55. #if SE_DEBUG > 0
  56. , _id(++__id)
  57. #endif
  58. , _isCleanup(false)
  59. , _type(Type::UNKNOWN)
  60. {
  61. _currentVMId = ScriptEngine::getInstance()->getVMId();
  62. }
  63. Object::~Object()
  64. {
  65. _cleanup();
  66. }
  67. Object* Object::createPlainObject()
  68. {
  69. Object* obj = _createJSObject(nullptr, JSObjectMake(__cx, nullptr, nullptr));
  70. if (obj != nullptr)
  71. obj->_type = Type::PLAIN;
  72. return obj;
  73. }
  74. Object* Object::createArrayObject(size_t length)
  75. {
  76. JSValueRef exception = nullptr;
  77. JSObjectRef jsObj = JSObjectMakeArray(__cx, 0, nullptr, &exception);
  78. if (exception != nullptr)
  79. {
  80. ScriptEngine::getInstance()->_clearException(exception);
  81. return nullptr;
  82. }
  83. Object* obj = _createJSObject(nullptr, jsObj);
  84. if (obj != nullptr)
  85. obj->_type = Type::ARRAY;
  86. return obj;
  87. }
  88. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  89. static void myJSTypedArrayBytesDeallocator(void* bytes, void* deallocatorContext)
  90. {
  91. free(bytes);
  92. }
  93. #endif
  94. Object* Object::createArrayBufferObject(void* data, size_t byteLength)
  95. {
  96. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  97. if (isSupportTypedArrayAPI())
  98. {
  99. void* copiedData = malloc(byteLength);
  100. if (data)
  101. {
  102. memcpy(copiedData, data, byteLength);
  103. }
  104. else
  105. {
  106. memset(copiedData, 0, byteLength);
  107. }
  108. JSValueRef exception = nullptr;
  109. JSObjectRef jsobj = JSObjectMakeArrayBufferWithBytesNoCopy(__cx, copiedData, byteLength, myJSTypedArrayBytesDeallocator, nullptr, &exception);
  110. if (exception != nullptr)
  111. {
  112. ScriptEngine::getInstance()->_clearException(exception);
  113. return nullptr;
  114. }
  115. Object* obj = Object::_createJSObject(nullptr, jsobj);
  116. if (obj != nullptr)
  117. obj->_type = Type::ARRAY_BUFFER;
  118. return obj;
  119. }
  120. #endif
  121. JSObjectRef ret = EJJSObjectMakeTypedArray(__cx, kEJJSTypedArrayTypeArrayBuffer, byteLength);
  122. if (data)
  123. {
  124. NSData* nsData = [NSData dataWithBytes:data length:byteLength];
  125. EJJSObjectSetTypedArrayData(__cx, ret, nsData);
  126. }
  127. Object* obj = Object::_createJSObject(nullptr, ret);
  128. if (obj != nullptr)
  129. obj->_type = Type::ARRAY_BUFFER;
  130. return obj;
  131. }
  132. Object* Object::createTypedArray(TypedArrayType type, void* data, size_t byteLength)
  133. {
  134. if (type == TypedArrayType::NONE)
  135. {
  136. SE_LOGE("Don't pass se::Object::TypedArrayType::NONE to createTypedArray API!");
  137. return nullptr;
  138. }
  139. if (type == TypedArrayType::UINT8_CLAMPED)
  140. {
  141. SE_LOGE("Doesn't support to create Uint8ClampedArray with Object::createTypedArray API!");
  142. return nullptr;
  143. }
  144. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  145. if (isSupportTypedArrayAPI())
  146. {
  147. void* copiedData = malloc(byteLength);
  148. //If data has content,then will copy data into buffer,or will only clear buffer.
  149. if (data){
  150. memcpy(copiedData, data, byteLength);
  151. }
  152. else
  153. {
  154. memset(copiedData, 0, byteLength);
  155. }
  156. JSValueRef exception = nullptr;
  157. JSTypedArrayType jscTypedArrayType = kJSTypedArrayTypeNone;
  158. Type objectType = Type::UNKNOWN;
  159. switch (type) {
  160. case TypedArrayType::INT8:
  161. objectType = Type::TYPED_ARRAY_INT8;
  162. jscTypedArrayType = kJSTypedArrayTypeInt8Array;
  163. break;
  164. case TypedArrayType::INT16:
  165. objectType = Type::TYPED_ARRAY_INT16;
  166. jscTypedArrayType = kJSTypedArrayTypeInt16Array;
  167. break;
  168. case TypedArrayType::INT32:
  169. objectType = Type::TYPED_ARRAY_INT32;
  170. jscTypedArrayType = kJSTypedArrayTypeInt32Array;
  171. break;
  172. case TypedArrayType::UINT8:
  173. objectType = Type::TYPED_ARRAY_UINT8;
  174. jscTypedArrayType = kJSTypedArrayTypeUint8Array;
  175. break;
  176. case TypedArrayType::UINT8_CLAMPED:
  177. objectType = Type::TYPED_ARRAY_UINT8_CLAMPED;
  178. jscTypedArrayType = kJSTypedArrayTypeUint8ClampedArray;
  179. break;
  180. case TypedArrayType::UINT16:
  181. objectType = Type::TYPED_ARRAY_UINT16;
  182. jscTypedArrayType = kJSTypedArrayTypeUint16Array;
  183. break;
  184. case TypedArrayType::UINT32:
  185. objectType = Type::TYPED_ARRAY_UINT32;
  186. jscTypedArrayType = kJSTypedArrayTypeUint32Array;
  187. break;
  188. case TypedArrayType::FLOAT32:
  189. objectType = Type::TYPED_ARRAY_FLOAT32;
  190. jscTypedArrayType = kJSTypedArrayTypeFloat32Array;
  191. break;
  192. case TypedArrayType::FLOAT64:
  193. objectType = Type::TYPED_ARRAY_FLOAT64;
  194. jscTypedArrayType = kJSTypedArrayTypeFloat64Array;
  195. break;
  196. default:
  197. break;
  198. }
  199. JSObjectRef jsobj = JSObjectMakeTypedArrayWithBytesNoCopy(__cx, jscTypedArrayType, copiedData, byteLength, myJSTypedArrayBytesDeallocator, nullptr, &exception);
  200. if (exception != nullptr)
  201. {
  202. ScriptEngine::getInstance()->_clearException(exception);
  203. return nullptr;
  204. }
  205. Object* obj = Object::_createJSObject(nullptr, jsobj);
  206. if (obj != nullptr)
  207. obj->_type = objectType;
  208. return obj;
  209. }
  210. #endif
  211. size_t numElements = 0;
  212. EJJSTypedArrayType jscTypedArrayType = kEJJSTypedArrayTypeNone;
  213. Type objectType = Type::UNKNOWN;
  214. switch (type) {
  215. case TypedArrayType::INT8:
  216. objectType = Type::TYPED_ARRAY_INT8;
  217. jscTypedArrayType = kEJJSTypedArrayTypeInt8Array;
  218. numElements = byteLength;
  219. break;
  220. case TypedArrayType::INT16:
  221. objectType = Type::TYPED_ARRAY_INT16;
  222. jscTypedArrayType = kEJJSTypedArrayTypeInt16Array;
  223. numElements = byteLength / 2;
  224. break;
  225. case TypedArrayType::INT32:
  226. objectType = Type::TYPED_ARRAY_INT32;
  227. jscTypedArrayType = kEJJSTypedArrayTypeInt32Array;
  228. numElements = byteLength / 4;
  229. break;
  230. case TypedArrayType::UINT8:
  231. objectType = Type::TYPED_ARRAY_UINT8;
  232. jscTypedArrayType = kEJJSTypedArrayTypeUint8Array;
  233. numElements = byteLength;
  234. break;
  235. case TypedArrayType::UINT8_CLAMPED:
  236. objectType = Type::TYPED_ARRAY_UINT8_CLAMPED;
  237. jscTypedArrayType = kEJJSTypedArrayTypeUint8ClampedArray;
  238. numElements = byteLength;
  239. break;
  240. case TypedArrayType::UINT16:
  241. objectType = Type::TYPED_ARRAY_UINT16;
  242. jscTypedArrayType = kEJJSTypedArrayTypeUint16Array;
  243. numElements = byteLength / 2;
  244. break;
  245. case TypedArrayType::UINT32:
  246. objectType = Type::TYPED_ARRAY_UINT32;
  247. jscTypedArrayType = kEJJSTypedArrayTypeUint32Array;
  248. numElements = byteLength / 4;
  249. break;
  250. case TypedArrayType::FLOAT32:
  251. objectType = Type::TYPED_ARRAY_FLOAT32;
  252. jscTypedArrayType = kEJJSTypedArrayTypeFloat32Array;
  253. numElements = byteLength / 4;
  254. break;
  255. case TypedArrayType::FLOAT64:
  256. objectType = Type::TYPED_ARRAY_FLOAT64;
  257. jscTypedArrayType = kEJJSTypedArrayTypeFloat64Array;
  258. numElements = byteLength / 8;
  259. break;
  260. default:
  261. break;
  262. }
  263. JSObjectRef ret = EJJSObjectMakeTypedArray(__cx, jscTypedArrayType, numElements);
  264. if (data)
  265. {
  266. NSData* nsData = nsData = [NSData dataWithBytes:data length:byteLength];
  267. EJJSObjectSetTypedArrayData(__cx, ret, nsData);
  268. }
  269. Object* obj = Object::_createJSObject(nullptr, ret);
  270. if (obj != nullptr)
  271. obj->_type = objectType;
  272. return obj;
  273. }
  274. Object* Object::createUint8TypedArray(uint8_t* data, size_t dataCount)
  275. {
  276. return createTypedArray(TypedArrayType::UINT8, data, dataCount);
  277. }
  278. Object* Object::createJSONObject(const std::string& jsonStr)
  279. {
  280. Object* obj = nullptr;
  281. JSStringRef jsStr = JSStringCreateWithUTF8CString(jsonStr.c_str());
  282. JSValueRef ret = JSValueMakeFromJSONString(__cx, jsStr);
  283. if (ret != nullptr)
  284. {
  285. JSValueRef exception = nullptr;
  286. JSObjectRef jsobj = JSValueToObject(__cx, ret, &exception);
  287. if (exception != nullptr)
  288. {
  289. ScriptEngine::getInstance()->_clearException(exception);
  290. return nullptr;
  291. }
  292. obj = Object::_createJSObject(nullptr, jsobj);
  293. if (obj != nullptr)
  294. obj->_type = Type::PLAIN;
  295. }
  296. return obj;
  297. }
  298. Object* Object::getObjectWithPtr(void* ptr)
  299. {
  300. Object* obj = nullptr;
  301. auto iter = NativePtrToObjectMap::find(ptr);
  302. if (iter != NativePtrToObjectMap::end())
  303. {
  304. obj = iter->second;
  305. obj->incRef();
  306. }
  307. return obj;
  308. }
  309. Object* Object::createObjectWithClass(Class* cls)
  310. {
  311. JSObjectRef jsobj = Class::_createJSObjectWithClass(cls);
  312. Object* obj = Object::_createJSObject(cls, jsobj);
  313. return obj;
  314. }
  315. Object* Object::_createJSObject(Class* cls, JSObjectRef obj)
  316. {
  317. Object* ret = new Object();
  318. if (!ret->init(cls, obj))
  319. {
  320. delete ret;
  321. ret = nullptr;
  322. }
  323. return ret;
  324. }
  325. bool Object::init(Class* cls, JSObjectRef obj)
  326. {
  327. _obj = obj;
  328. _cls = cls;
  329. return true;
  330. }
  331. void Object::_cleanup(void* nativeObj/* = nullptr*/)
  332. {
  333. if (_isCleanup)
  334. return;
  335. auto se = ScriptEngine::getInstance();
  336. if (_currentVMId == se->getVMId())
  337. {
  338. if (_privateData != nullptr)
  339. {
  340. if (nativeObj == nullptr)
  341. {
  342. nativeObj = internal::getPrivate(_obj);
  343. }
  344. if (nativeObj != nullptr)
  345. {
  346. auto iter = NativePtrToObjectMap::find(nativeObj);
  347. if (iter != NativePtrToObjectMap::end())
  348. {
  349. NativePtrToObjectMap::erase(iter);
  350. }
  351. }
  352. else
  353. {
  354. assert(false);
  355. }
  356. }
  357. if (_rootCount > 0)
  358. {
  359. // SE_LOGD("Object::_cleanup, (%p) rootCount: %u\n", this, _rootCount);
  360. // Don't unprotect if it's in cleanup, otherwise, it will trigger crash.
  361. if (!se->isInCleanup() && !se->isGarbageCollecting())
  362. JSValueUnprotect(__cx, _obj);
  363. _rootCount = 0;
  364. }
  365. }
  366. else
  367. {
  368. SE_LOGD("Object::_cleanup, ScriptEngine was initialized again, ignore cleanup work, oldVMId: %u, newVMId: %u\n", _currentVMId, se->getVMId());
  369. }
  370. _isCleanup = true;
  371. }
  372. void Object::_setFinalizeCallback(JSObjectFinalizeCallback finalizeCb)
  373. {
  374. assert(finalizeCb != nullptr);
  375. _finalizeCb = finalizeCb;
  376. }
  377. bool Object::getProperty(const char* name, Value* data)
  378. {
  379. assert(data != nullptr);
  380. data->setUndefined();
  381. JSStringRef jsName = JSStringCreateWithUTF8CString(name);
  382. bool exist = JSObjectHasProperty(__cx, _obj, jsName);
  383. if (exist)
  384. {
  385. JSValueRef exception = nullptr;
  386. JSValueRef jsValue = JSObjectGetProperty(__cx, _obj, jsName, &exception);
  387. if (exception != nullptr)
  388. {
  389. ScriptEngine::getInstance()->_clearException(exception);
  390. return false;
  391. }
  392. internal::jsToSeValue(__cx, jsValue, data);
  393. }
  394. else
  395. {
  396. data->setUndefined();
  397. }
  398. JSStringRelease(jsName);
  399. return exist;
  400. }
  401. bool Object::setProperty(const char* name, const Value& v)
  402. {
  403. bool ret = true;
  404. JSStringRef jsName = JSStringCreateWithUTF8CString(name);
  405. JSValueRef jsValue = nullptr;
  406. JSObjectRef obj = _obj;
  407. if (v.getType() == Value::Type::Number)
  408. {
  409. jsValue = JSValueMakeNumber(__cx, v.toNumber());
  410. }
  411. else if (v.getType() == Value::Type::String)
  412. {
  413. JSStringRef jsstr = JSStringCreateWithUTF8CString(v.toString().c_str());
  414. jsValue = JSValueMakeString(__cx, jsstr);
  415. JSStringRelease(jsstr);
  416. }
  417. else if (v.getType() == Value::Type::Boolean)
  418. {
  419. jsValue = JSValueMakeBoolean(__cx, v.toBoolean());
  420. }
  421. else if (v.getType() == Value::Type::Object)
  422. {
  423. jsValue = v.toObject()->_obj;
  424. }
  425. else if (v.getType() == Value::Type::Null)
  426. {
  427. jsValue = JSValueMakeNull(__cx);
  428. }
  429. else
  430. {
  431. jsValue = JSValueMakeUndefined(__cx);
  432. }
  433. JSValueRef exception = nullptr;
  434. JSObjectSetProperty(__cx, obj, jsName, jsValue, kJSPropertyAttributeNone, &exception);
  435. if (exception != nullptr)
  436. {
  437. ScriptEngine::getInstance()->_clearException(exception);
  438. ret = false;
  439. }
  440. JSStringRelease(jsName);
  441. return ret;
  442. }
  443. bool Object::defineProperty(const char *name, JSObjectCallAsFunctionCallback getter, JSObjectCallAsFunctionCallback setter)
  444. {
  445. return internal::defineProperty(this, name, getter, setter);
  446. }
  447. bool Object::deleteProperty(const char *name)
  448. {
  449. bool ret = true;
  450. JSStringRef jsName = JSStringCreateWithUTF8CString(name);
  451. JSValueRef exception = nullptr;
  452. JSObjectDeleteProperty(__cx, _obj, jsName, &exception);
  453. if (exception != nullptr)
  454. {
  455. ScriptEngine::getInstance()->_clearException(exception);
  456. ret = false;
  457. }
  458. JSStringRelease(jsName);
  459. return ret;
  460. }
  461. bool Object::call(const ValueArray& args, Object* thisObject, Value* rval/* = nullptr*/)
  462. {
  463. assert(isFunction());
  464. JSObjectRef contextObject = nullptr;
  465. if (thisObject != nullptr)
  466. {
  467. contextObject = thisObject->_obj;
  468. }
  469. JSValueRef* jsArgs = nullptr;
  470. if (!args.empty())
  471. {
  472. jsArgs = (JSValueRef*)malloc(sizeof(JSValueRef) * args.size());
  473. internal::seToJsArgs(__cx, args, jsArgs);
  474. }
  475. JSValueRef exception = nullptr;
  476. JSValueRef rcValue = JSObjectCallAsFunction(__cx, _obj, contextObject, args.size(), jsArgs, &exception);
  477. free(jsArgs);
  478. if (rcValue != nullptr)
  479. {
  480. if (rval != nullptr && !JSValueIsUndefined(__cx, rcValue))
  481. {
  482. internal::jsToSeValue(__cx, rcValue, rval);
  483. }
  484. return true;
  485. }
  486. // Function call failed, try to output exception
  487. if (exception != nullptr)
  488. {
  489. ScriptEngine::getInstance()->_clearException(exception);
  490. }
  491. return false;
  492. }
  493. bool Object::defineFunction(const char* funcName, JSObjectCallAsFunctionCallback func)
  494. {
  495. JSStringRef jsName = JSStringCreateWithUTF8CString(funcName);
  496. JSObjectRef jsFunc = JSObjectMakeFunctionWithCallback(__cx, jsName, func);
  497. JSValueRef exception = nullptr;
  498. JSObjectSetProperty(__cx, _obj, jsName, jsFunc, kJSPropertyAttributeNone, &exception);
  499. if (exception != nullptr)
  500. {
  501. ScriptEngine::getInstance()->_clearException(exception);
  502. }
  503. JSStringRelease(jsName);
  504. return true;
  505. }
  506. bool Object::getArrayLength(uint32_t* length) const
  507. {
  508. assert(isArray());
  509. assert(length != nullptr);
  510. JSStringRef key = JSStringCreateWithUTF8CString("length");
  511. JSValueRef exception = nullptr;
  512. JSValueRef v = JSObjectGetProperty(__cx, _obj, key, &exception);
  513. if (exception != nullptr)
  514. {
  515. ScriptEngine::getInstance()->_clearException(exception);
  516. JSStringRelease(key);
  517. *length = 0;
  518. return false;
  519. }
  520. assert(JSValueIsNumber(__cx, v));
  521. double len = JSValueToNumber(__cx, v, nullptr);
  522. JSStringRelease(key);
  523. *length = (uint32_t)len;
  524. return true;
  525. }
  526. bool Object::getArrayElement(uint32_t index, Value* data) const
  527. {
  528. assert(isArray());
  529. assert(data != nullptr);
  530. JSValueRef exception = nullptr;
  531. JSValueRef v = JSObjectGetPropertyAtIndex(__cx, _obj, index, &exception);
  532. if (exception != nullptr)
  533. {
  534. ScriptEngine::getInstance()->_clearException(exception);
  535. return false;
  536. }
  537. internal::jsToSeValue(__cx, v, data);
  538. return true;
  539. }
  540. bool Object::setArrayElement(uint32_t index, const Value& data)
  541. {
  542. assert(isArray());
  543. JSValueRef v;
  544. internal::seToJsValue(__cx, data, &v);
  545. JSValueRef exception = nullptr;
  546. JSObjectSetPropertyAtIndex(__cx, _obj, index, v, &exception);
  547. if (exception != nullptr)
  548. {
  549. ScriptEngine::getInstance()->_clearException(exception);
  550. return false;
  551. }
  552. return true;
  553. }
  554. bool Object::getAllKeys(std::vector<std::string>* allKeys) const
  555. {
  556. JSPropertyNameArrayRef keys = JSObjectCopyPropertyNames(__cx, _obj);
  557. size_t expectedCount = JSPropertyNameArrayGetCount(keys);
  558. std::string tmp;
  559. for (size_t count = 0; count < expectedCount; ++count)
  560. {
  561. JSStringRef key = JSPropertyNameArrayGetNameAtIndex(keys, count);
  562. internal::jsStringToStdString(__cx, key, &tmp);
  563. allKeys->push_back(tmp);
  564. }
  565. JSPropertyNameArrayRelease(keys);
  566. return true;
  567. }
  568. bool Object::isFunction() const
  569. {
  570. return JSObjectIsFunction(__cx, _obj);
  571. }
  572. bool Object::isTypedArray() const
  573. {
  574. if (_type == Type::TYPED_ARRAY_INT8
  575. || _type == Type::TYPED_ARRAY_INT16
  576. || _type == Type::TYPED_ARRAY_INT32
  577. || _type == Type::TYPED_ARRAY_UINT8
  578. || _type == Type::TYPED_ARRAY_UINT8_CLAMPED
  579. || _type == Type::TYPED_ARRAY_UINT16
  580. || _type == Type::TYPED_ARRAY_UINT32
  581. || _type == Type::TYPED_ARRAY_FLOAT32
  582. || _type == Type::TYPED_ARRAY_FLOAT64
  583. )
  584. {
  585. return true;
  586. }
  587. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  588. if (isSupportTypedArrayAPI())
  589. {
  590. JSTypedArrayType type = JSValueGetTypedArrayType(__cx, _obj, nullptr);
  591. bool ret = (type != kJSTypedArrayTypeNone && type != kJSTypedArrayTypeArrayBuffer);
  592. if (ret)
  593. {
  594. switch (type) {
  595. case kJSTypedArrayTypeInt8Array:
  596. _type = Type::TYPED_ARRAY_INT8;
  597. break;
  598. case kJSTypedArrayTypeInt16Array:
  599. _type = Type::TYPED_ARRAY_INT16;
  600. break;
  601. case kJSTypedArrayTypeInt32Array:
  602. _type = Type::TYPED_ARRAY_INT32;
  603. break;
  604. case kJSTypedArrayTypeUint8Array:
  605. _type = Type::TYPED_ARRAY_UINT8;
  606. break;
  607. case kJSTypedArrayTypeUint8ClampedArray:
  608. _type = Type::TYPED_ARRAY_UINT8_CLAMPED;
  609. break;
  610. case kJSTypedArrayTypeUint16Array:
  611. _type = Type::TYPED_ARRAY_UINT16;
  612. break;
  613. case kJSTypedArrayTypeUint32Array:
  614. _type = Type::TYPED_ARRAY_UINT32;
  615. break;
  616. case kJSTypedArrayTypeFloat32Array:
  617. _type = Type::TYPED_ARRAY_FLOAT32;
  618. break;
  619. case kJSTypedArrayTypeFloat64Array:
  620. _type = Type::TYPED_ARRAY_FLOAT64;
  621. break;
  622. default:
  623. break;
  624. }
  625. }
  626. return ret;
  627. }
  628. #endif
  629. EJJSTypedArrayType typedArrayType = EJJSObjectGetTypedArrayType(__cx, _obj);
  630. return typedArrayType >= kEJJSTypedArrayTypeInt8Array && typedArrayType <= kEJJSTypedArrayTypeFloat64Array;
  631. }
  632. Object::TypedArrayType Object::getTypedArrayType() const
  633. {
  634. if (_type == Type::TYPED_ARRAY_INT8)
  635. return TypedArrayType::INT8;
  636. else if (_type == Type::TYPED_ARRAY_INT16)
  637. return TypedArrayType::INT16;
  638. else if (_type == Type::TYPED_ARRAY_INT32)
  639. return TypedArrayType::INT32;
  640. else if (_type == Type::TYPED_ARRAY_UINT8)
  641. return TypedArrayType::UINT8;
  642. else if (_type == Type::TYPED_ARRAY_UINT8_CLAMPED)
  643. return TypedArrayType::UINT8_CLAMPED;
  644. else if (_type == Type::TYPED_ARRAY_UINT16)
  645. return TypedArrayType::UINT16;
  646. else if (_type == Type::TYPED_ARRAY_UINT32)
  647. return TypedArrayType::UINT32;
  648. else if (_type == Type::TYPED_ARRAY_FLOAT32)
  649. return TypedArrayType::FLOAT32;
  650. else if (_type == Type::TYPED_ARRAY_FLOAT64)
  651. return TypedArrayType::FLOAT64;
  652. TypedArrayType typedArrayType = TypedArrayType::NONE;
  653. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  654. if (isSupportTypedArrayAPI())
  655. {
  656. JSTypedArrayType type = JSValueGetTypedArrayType(__cx, _obj, nullptr);
  657. bool ret = (type != kJSTypedArrayTypeNone && type != kJSTypedArrayTypeArrayBuffer);
  658. if (ret)
  659. {
  660. switch (type) {
  661. case kJSTypedArrayTypeInt8Array:
  662. _type = Type::TYPED_ARRAY_INT8;
  663. typedArrayType = TypedArrayType::INT8;
  664. break;
  665. case kJSTypedArrayTypeInt16Array:
  666. _type = Type::TYPED_ARRAY_INT16;
  667. typedArrayType = TypedArrayType::INT16;
  668. break;
  669. case kJSTypedArrayTypeInt32Array:
  670. _type = Type::TYPED_ARRAY_INT32;
  671. typedArrayType = TypedArrayType::INT32;
  672. break;
  673. case kJSTypedArrayTypeUint8Array:
  674. _type = Type::TYPED_ARRAY_UINT8;
  675. typedArrayType = TypedArrayType::UINT8;
  676. break;
  677. case kJSTypedArrayTypeUint8ClampedArray:
  678. _type = Type::TYPED_ARRAY_UINT8_CLAMPED;
  679. typedArrayType = TypedArrayType::UINT8_CLAMPED;
  680. break;
  681. case kJSTypedArrayTypeUint16Array:
  682. _type = Type::TYPED_ARRAY_UINT16;
  683. typedArrayType = TypedArrayType::UINT16;
  684. break;
  685. case kJSTypedArrayTypeUint32Array:
  686. _type = Type::TYPED_ARRAY_UINT32;
  687. typedArrayType = TypedArrayType::UINT32;
  688. break;
  689. case kJSTypedArrayTypeFloat32Array:
  690. _type = Type::TYPED_ARRAY_FLOAT32;
  691. typedArrayType = TypedArrayType::FLOAT32;
  692. break;
  693. case kJSTypedArrayTypeFloat64Array:
  694. _type = Type::TYPED_ARRAY_FLOAT64;
  695. typedArrayType = TypedArrayType::FLOAT64;
  696. break;
  697. default:
  698. break;
  699. }
  700. }
  701. return typedArrayType;
  702. }
  703. #endif
  704. EJJSTypedArrayType ejTypedArrayType = EJJSObjectGetTypedArrayType(__cx, _obj);
  705. switch (ejTypedArrayType) {
  706. case kEJJSTypedArrayTypeInt8Array:
  707. _type = Type::TYPED_ARRAY_INT8;
  708. typedArrayType = TypedArrayType::INT8;
  709. break;
  710. case kEJJSTypedArrayTypeInt16Array:
  711. _type = Type::TYPED_ARRAY_INT16;
  712. typedArrayType = TypedArrayType::INT16;
  713. break;
  714. case kEJJSTypedArrayTypeInt32Array:
  715. _type = Type::TYPED_ARRAY_INT32;
  716. typedArrayType = TypedArrayType::INT32;
  717. break;
  718. case kEJJSTypedArrayTypeUint8Array:
  719. _type = Type::TYPED_ARRAY_UINT8;
  720. typedArrayType = TypedArrayType::UINT8;
  721. break;
  722. case kEJJSTypedArrayTypeUint8ClampedArray:
  723. _type = Type::TYPED_ARRAY_UINT8_CLAMPED;
  724. typedArrayType = TypedArrayType::UINT8_CLAMPED;
  725. break;
  726. case kEJJSTypedArrayTypeUint16Array:
  727. _type = Type::TYPED_ARRAY_UINT16;
  728. typedArrayType = TypedArrayType::UINT16;
  729. break;
  730. case kEJJSTypedArrayTypeUint32Array:
  731. _type = Type::TYPED_ARRAY_UINT32;
  732. typedArrayType = TypedArrayType::UINT32;
  733. break;
  734. case kEJJSTypedArrayTypeFloat32Array:
  735. _type = Type::TYPED_ARRAY_FLOAT32;
  736. typedArrayType = TypedArrayType::FLOAT32;
  737. break;
  738. case kEJJSTypedArrayTypeFloat64Array:
  739. _type = Type::TYPED_ARRAY_FLOAT64;
  740. typedArrayType = TypedArrayType::FLOAT64;
  741. break;
  742. default:
  743. typedArrayType = TypedArrayType::NONE;
  744. break;
  745. }
  746. return typedArrayType;
  747. }
  748. bool Object::getTypedArrayData(uint8_t** ptr, size_t* length) const
  749. {
  750. assert(isTypedArray());
  751. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  752. if (isSupportTypedArrayAPI())
  753. {
  754. bool succeed = false;
  755. JSValueRef exception = nullptr;
  756. do
  757. {
  758. *length = JSObjectGetTypedArrayByteLength(__cx, _obj, &exception);
  759. if (exception != nullptr)
  760. break;
  761. size_t offset = JSObjectGetTypedArrayByteOffset(__cx, _obj, &exception);
  762. if (exception != nullptr)
  763. break;
  764. uint8_t* buf = (uint8_t*)JSObjectGetTypedArrayBytesPtr(__cx, _obj, &exception);
  765. if (exception != nullptr)
  766. break;
  767. if (buf == nullptr)
  768. break;
  769. *ptr = buf + offset;
  770. succeed = true;
  771. } while (false);
  772. if (!succeed)
  773. {
  774. *ptr = nullptr;
  775. *length = 0;
  776. ScriptEngine::getInstance()->_clearException(exception);
  777. return false;
  778. }
  779. return true;
  780. }
  781. #endif
  782. NSMutableData* data = EJJSObjectGetTypedArrayData(__cx, _obj);
  783. *ptr = (uint8_t*)data.mutableBytes;
  784. *length = data.length;
  785. return true;
  786. }
  787. bool Object::_isNativeFunction() const
  788. {
  789. if (isFunction())
  790. {
  791. std::string info = toString();
  792. if (info.find("[native code]") != std::string::npos)
  793. {
  794. return true;
  795. }
  796. }
  797. return false;
  798. }
  799. bool Object::isArray() const
  800. {
  801. if (_type == Type::ARRAY)
  802. return true;
  803. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000)
  804. if (isSupportArrayTestAPI())
  805. {
  806. return JSValueIsArray(__cx, _obj);
  807. }
  808. #endif
  809. bool ret = isInstanceOfConstructor(__cx, _obj, "Array");
  810. if (ret)
  811. _type = Type::ARRAY;
  812. return ret;
  813. }
  814. bool Object::isArrayBuffer() const
  815. {
  816. if (_type == Type::ARRAY_BUFFER)
  817. return true;
  818. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  819. if (isSupportTypedArrayAPI())
  820. {
  821. JSValueRef exception = nullptr;
  822. JSTypedArrayType type = JSValueGetTypedArrayType(__cx, _obj, &exception);
  823. if (exception != nullptr)
  824. {
  825. ScriptEngine::getInstance()->_clearException(exception);
  826. return false;
  827. }
  828. bool ret = type == kJSTypedArrayTypeArrayBuffer;
  829. if (ret)
  830. _type = Type::ARRAY_BUFFER;
  831. return ret;
  832. }
  833. #endif
  834. bool ret = isInstanceOfConstructor(__cx, _obj, "ArrayBuffer");
  835. if (ret)
  836. _type = Type::ARRAY_BUFFER;
  837. return ret;
  838. }
  839. bool Object::getArrayBufferData(uint8_t** ptr, size_t* length) const
  840. {
  841. assert(ptr && length);
  842. assert(isArrayBuffer());
  843. #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000)
  844. if (isSupportTypedArrayAPI())
  845. {
  846. JSValueRef exception = nullptr;
  847. *length = JSObjectGetArrayBufferByteLength(__cx, _obj, &exception);
  848. if (exception != nullptr)
  849. {
  850. ScriptEngine::getInstance()->_clearException(exception);
  851. return false;
  852. }
  853. *ptr = (uint8_t*)JSObjectGetArrayBufferBytesPtr(__cx, _obj, &exception);
  854. if (exception != nullptr)
  855. {
  856. ScriptEngine::getInstance()->_clearException(exception);
  857. return false;
  858. }
  859. return (*ptr != nullptr);
  860. }
  861. #endif
  862. NSMutableData* data = EJJSObjectGetTypedArrayData(__cx, _obj);
  863. *ptr = (uint8_t*)data.mutableBytes;
  864. *length = data.length;
  865. return true;
  866. }
  867. void* Object::getPrivateData() const
  868. {
  869. if (_privateData == nullptr)
  870. {
  871. const_cast<Object*>(this)->_privateData = internal::getPrivate(_obj);
  872. }
  873. return _privateData;
  874. }
  875. void Object::setPrivateData(void* data)
  876. {
  877. assert(_privateData == nullptr);
  878. assert(NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end());
  879. internal::setPrivate(_obj, data, _finalizeCb);
  880. NativePtrToObjectMap::emplace(data, this);
  881. _privateData = data;
  882. }
  883. void Object::clearPrivateData(bool clearMapping)
  884. {
  885. if (_privateData != nullptr)
  886. {
  887. if (clearMapping)
  888. NativePtrToObjectMap::erase(_privateData);
  889. internal::clearPrivate(_obj);
  890. _privateData = nullptr;
  891. }
  892. }
  893. void Object::setContext(JSContextRef cx)
  894. {
  895. __cx = cx;
  896. }
  897. void Object::cleanup()
  898. {
  899. ScriptEngine::getInstance()->addAfterCleanupHook([](){
  900. const auto& instance = NativePtrToObjectMap::instance();
  901. se::Object* obj = nullptr;
  902. for (const auto& e : instance)
  903. {
  904. obj = e.second;
  905. obj->_isCleanup = true; // _cleanup will invoke NativePtrToObjectMap::erase method which will break this for loop. It isn't needed at ScriptEngine::cleanup step.
  906. obj->decRef();
  907. }
  908. NativePtrToObjectMap::clear();
  909. NonRefNativePtrCreatedByCtorMap::clear();
  910. __cx = nullptr;
  911. });
  912. }
  913. JSObjectRef Object::_getJSObject() const
  914. {
  915. return _obj;
  916. }
  917. Class* Object::_getClass() const
  918. {
  919. return _cls;
  920. }
  921. void Object::root()
  922. {
  923. if (_rootCount == 0)
  924. {
  925. JSValueProtect(__cx, _obj);
  926. }
  927. ++_rootCount;
  928. }
  929. void Object::unroot()
  930. {
  931. if (_rootCount > 0)
  932. {
  933. --_rootCount;
  934. if (_rootCount == 0)
  935. {
  936. // Don't unprotect if it's in cleanup, otherwise, it will trigger crash.
  937. auto se = ScriptEngine::getInstance();
  938. if (_currentVMId == se->getVMId())
  939. {
  940. if (!se->isInCleanup() && !se->isGarbageCollecting())
  941. JSValueUnprotect(__cx, _obj);
  942. }
  943. else
  944. {
  945. SE_LOGD("Object::unroot, ScriptEngine was initialized again, ignore cleanup work, oldVMId: %u, newVMId: %u\n", _currentVMId, se->getVMId());
  946. }
  947. }
  948. }
  949. }
  950. bool Object::isRooted() const
  951. {
  952. return _rootCount > 0;
  953. }
  954. bool Object::strictEquals(Object* o) const
  955. {
  956. return JSValueIsStrictEqual(__cx, _obj, o->_obj);
  957. }
  958. bool Object::attachObject(Object* obj)
  959. {
  960. assert(obj);
  961. Object* global = ScriptEngine::getInstance()->getGlobalObject();
  962. Value jsbVal;
  963. if (!global->getProperty("jsb", &jsbVal))
  964. return false;
  965. Object* jsbObj = jsbVal.toObject();
  966. Value func;
  967. if (!jsbObj->getProperty("registerNativeRef", &func))
  968. return false;
  969. ValueArray args;
  970. args.push_back(Value(this));
  971. args.push_back(Value(obj));
  972. func.toObject()->call(args, global);
  973. return true;
  974. }
  975. bool Object::detachObject(Object* obj)
  976. {
  977. assert(obj);
  978. Object* global = ScriptEngine::getInstance()->getGlobalObject();
  979. Value jsbVal;
  980. if (!global->getProperty("jsb", &jsbVal))
  981. return false;
  982. Object* jsbObj = jsbVal.toObject();
  983. Value func;
  984. if (!jsbObj->getProperty("unregisterNativeRef", &func))
  985. return false;
  986. ValueArray args;
  987. args.push_back(Value(this));
  988. args.push_back(Value(obj));
  989. func.toObject()->call(args, global);
  990. return true;
  991. }
  992. std::string Object::toString() const
  993. {
  994. std::string ret;
  995. if (isFunction() || isArray() || isTypedArray())
  996. {
  997. internal::forceConvertJsValueToStdString(__cx, _obj, &ret);
  998. }
  999. else if (isArrayBuffer())
  1000. {
  1001. ret = "[object ArrayBuffer]";
  1002. }
  1003. else
  1004. {
  1005. ret = "[object Object]";
  1006. }
  1007. return ret;
  1008. }
  1009. } // namespace se {
  1010. #endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_JSC