Object.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  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_V8
  23. #include "Utils.hpp"
  24. #include "Class.hpp"
  25. #include "ScriptEngine.hpp"
  26. #include "../MappingUtils.hpp"
  27. #include <memory>
  28. #include <unordered_map>
  29. namespace se {
  30. std::unique_ptr<std::unordered_map<Object*, void*>> __objectMap; // Currently, the value `void*` is always nullptr
  31. namespace {
  32. v8::Isolate* __isolate = nullptr;
  33. }
  34. Object::Object()
  35. : _cls(nullptr)
  36. , _rootCount(0)
  37. , _privateData(nullptr)
  38. , _finalizeCb(nullptr)
  39. , _internalData(nullptr)
  40. {
  41. }
  42. Object::~Object()
  43. {
  44. if (_rootCount > 0)
  45. {
  46. _obj.unref();
  47. }
  48. if(__objectMap){
  49. __objectMap->erase(this);
  50. }
  51. }
  52. /*static*/
  53. void Object::nativeObjectFinalizeHook(void* nativeObj)
  54. {
  55. if (nativeObj == nullptr)
  56. return;
  57. auto iter = NativePtrToObjectMap::find(nativeObj);
  58. if (iter != NativePtrToObjectMap::end())
  59. {
  60. Object* obj = iter->second;
  61. if (obj->_finalizeCb != nullptr)
  62. {
  63. obj->_finalizeCb(nativeObj);
  64. }
  65. else
  66. {
  67. assert(obj->_getClass() != nullptr);
  68. if (obj->_getClass()->_finalizeFunc != nullptr)
  69. obj->_getClass()->_finalizeFunc(nativeObj);
  70. }
  71. obj->decRef();
  72. NativePtrToObjectMap::erase(iter);
  73. }
  74. else
  75. {
  76. // assert(false);
  77. }
  78. }
  79. /* static */
  80. void Object::setIsolate(v8::Isolate* isolate)
  81. {
  82. __isolate = isolate;
  83. }
  84. void Object::setup()
  85. {
  86. __objectMap.reset(new std::unordered_map<Object*, void*>());
  87. }
  88. /* static */
  89. void Object::cleanup()
  90. {
  91. void* nativeObj = nullptr;
  92. Object* obj = nullptr;
  93. Class* cls = nullptr;
  94. const auto& nativePtrToObjectMap = NativePtrToObjectMap::instance();
  95. for (const auto& e : nativePtrToObjectMap)
  96. {
  97. nativeObj = e.first;
  98. obj = e.second;
  99. if (obj->_finalizeCb != nullptr)
  100. {
  101. obj->_finalizeCb(nativeObj);
  102. }
  103. else
  104. {
  105. if (obj->_getClass() != nullptr)
  106. {
  107. if (obj->_getClass()->_finalizeFunc != nullptr)
  108. {
  109. obj->_getClass()->_finalizeFunc(nativeObj);
  110. }
  111. }
  112. }
  113. // internal data should only be freed in Object::cleanup, since in other case, it is freed in ScriptEngine::privateDataFinalize
  114. if (obj->_internalData != nullptr)
  115. {
  116. free(obj->_internalData);
  117. obj->_internalData = nullptr;
  118. }
  119. obj->decRef();
  120. }
  121. NativePtrToObjectMap::clear();
  122. NonRefNativePtrCreatedByCtorMap::clear();
  123. if(__objectMap){
  124. std::vector<Object*> toReleaseObjects;
  125. for (const auto& e : *__objectMap)
  126. {
  127. obj = e.first;
  128. cls = obj->_getClass();
  129. obj->_obj.persistent().Reset();
  130. obj->_rootCount = 0;
  131. if (cls != nullptr && cls->_name == "__PrivateData")
  132. {
  133. toReleaseObjects.push_back(obj);
  134. }
  135. }
  136. for (auto e : toReleaseObjects)
  137. {
  138. e->decRef();
  139. }
  140. }
  141. __objectMap.reset();
  142. __isolate = nullptr;
  143. }
  144. Object* Object::createPlainObject()
  145. {
  146. v8::Local<v8::Object> jsobj = v8::Object::New(__isolate);
  147. Object* obj = _createJSObject(nullptr, jsobj);
  148. return obj;
  149. }
  150. Object* Object::getObjectWithPtr(void* ptr)
  151. {
  152. Object* obj = nullptr;
  153. auto iter = NativePtrToObjectMap::find(ptr);
  154. if (iter != NativePtrToObjectMap::end())
  155. {
  156. obj = iter->second;
  157. obj->incRef();
  158. }
  159. return obj;
  160. }
  161. Object* Object::_createJSObject(Class* cls, v8::Local<v8::Object> obj)
  162. {
  163. Object* ret = new Object();
  164. if (!ret->init(cls, obj))
  165. {
  166. delete ret;
  167. ret = nullptr;
  168. }
  169. return ret;
  170. }
  171. Object* Object::createObjectWithClass(Class* cls)
  172. {
  173. v8::Local<v8::Object> jsobj = Class::_createJSObjectWithClass(cls);
  174. Object* obj = Object::_createJSObject(cls, jsobj);
  175. return obj;
  176. }
  177. Object* Object::createArrayObject(size_t length)
  178. {
  179. v8::Local<v8::Array> jsobj = v8::Array::New(__isolate, (int)length);
  180. Object* obj = Object::_createJSObject(nullptr, jsobj);
  181. return obj;
  182. }
  183. Object* Object::createArrayBufferObject(void* data, size_t byteLength)
  184. {
  185. v8::Local<v8::ArrayBuffer> jsobj = v8::ArrayBuffer::New(__isolate, byteLength);
  186. if (data)
  187. {
  188. memcpy(jsobj->GetContents().Data(), data, byteLength);
  189. }
  190. else
  191. {
  192. memset(jsobj->GetContents().Data(), 0, byteLength);
  193. }
  194. Object* obj = Object::_createJSObject(nullptr, jsobj);
  195. return obj;
  196. }
  197. Object* Object::createTypedArray(TypedArrayType type, void* data, size_t byteLength)
  198. {
  199. if (type == TypedArrayType::NONE)
  200. {
  201. SE_LOGE("Don't pass se::Object::TypedArrayType::NONE to createTypedArray API!");
  202. return nullptr;
  203. }
  204. if (type == TypedArrayType::UINT8_CLAMPED)
  205. {
  206. SE_LOGE("Doesn't support to create Uint8ClampedArray with Object::createTypedArray API!");
  207. return nullptr;
  208. }
  209. v8::Local<v8::ArrayBuffer> jsobj = v8::ArrayBuffer::New(__isolate, byteLength);
  210. //If data has content,then will copy data into buffer,or will only clear buffer.
  211. if (data) {
  212. memcpy(jsobj->GetContents().Data(), data, byteLength);
  213. }else{
  214. memset(jsobj->GetContents().Data(), 0, byteLength);
  215. }
  216. v8::Local<v8::Object> arr;
  217. switch (type) {
  218. case TypedArrayType::INT8:
  219. arr = v8::Int8Array::New(jsobj, 0, byteLength);
  220. break;
  221. case TypedArrayType::INT16:
  222. arr = v8::Int16Array::New(jsobj, 0, byteLength / 2);
  223. break;
  224. case TypedArrayType::INT32:
  225. arr = v8::Int32Array::New(jsobj, 0, byteLength / 4);
  226. break;
  227. case TypedArrayType::UINT8:
  228. arr = v8::Uint8Array::New(jsobj, 0, byteLength);
  229. break;
  230. case TypedArrayType::UINT16:
  231. arr = v8::Uint16Array::New(jsobj, 0, byteLength / 2);
  232. break;
  233. case TypedArrayType::UINT32:
  234. arr = v8::Uint32Array::New(jsobj, 0, byteLength / 4);
  235. break;
  236. case TypedArrayType::FLOAT32:
  237. arr = v8::Float32Array::New(jsobj, 0, byteLength / 4);
  238. break;
  239. case TypedArrayType::FLOAT64:
  240. arr = v8::Float64Array::New(jsobj, 0, byteLength / 8);
  241. break;
  242. default:
  243. assert(false); // Should never go here.
  244. break;
  245. }
  246. Object* obj = Object::_createJSObject(nullptr, arr);
  247. return obj;
  248. }
  249. Object* Object::createUint8TypedArray(uint8_t* data, size_t dataCount)
  250. {
  251. return createTypedArray(TypedArrayType::UINT8, data, dataCount);
  252. }
  253. Object* Object::createJSONObject(const std::string& jsonStr)
  254. {
  255. v8::Local<v8::Context> context = __isolate->GetCurrentContext();
  256. Value strVal(jsonStr);
  257. v8::Local<v8::Value> jsStr;
  258. internal::seToJsValue(__isolate, strVal, &jsStr);
  259. v8::Local<v8::String> v8Str = v8::Local<v8::String>::Cast(jsStr);
  260. v8::MaybeLocal<v8::Value> ret = v8::JSON::Parse(context, v8Str);
  261. if (ret.IsEmpty())
  262. return nullptr;
  263. v8::Local<v8::Object> jsobj = v8::Local<v8::Object>::Cast(ret.ToLocalChecked());
  264. return Object::_createJSObject(nullptr, jsobj);
  265. }
  266. bool Object::init(Class* cls, v8::Local<v8::Object> obj)
  267. {
  268. _cls = cls;
  269. _obj.init(obj);
  270. _obj.setFinalizeCallback(nativeObjectFinalizeHook);
  271. if(__objectMap){
  272. assert(__objectMap->find(this) == __objectMap->end());
  273. __objectMap->emplace(this, nullptr);
  274. }
  275. return true;
  276. }
  277. bool Object::getProperty(const char *name, Value *data)
  278. {
  279. assert(data != nullptr);
  280. data->setUndefined();
  281. v8::HandleScope handle_scope(__isolate);
  282. if (_obj.persistent().IsEmpty())
  283. {
  284. return false;
  285. }
  286. v8::MaybeLocal<v8::String> nameValue = v8::String::NewFromUtf8(__isolate, name, v8::NewStringType::kNormal);
  287. if (nameValue.IsEmpty())
  288. return false;
  289. v8::Local<v8::String> nameValToLocal = nameValue.ToLocalChecked();
  290. v8::Local<v8::Context> context = __isolate->GetCurrentContext();
  291. v8::Maybe<bool> maybeExist = _obj.handle(__isolate)->Has(context, nameValToLocal);
  292. if (maybeExist.IsNothing())
  293. return false;
  294. if (!maybeExist.FromJust())
  295. return false;
  296. v8::MaybeLocal<v8::Value> result = _obj.handle(__isolate)->Get(context, nameValToLocal);
  297. if (result.IsEmpty())
  298. return false;
  299. internal::jsToSeValue(__isolate, result.ToLocalChecked(), data);
  300. return true;
  301. }
  302. bool Object::deleteProperty(const char *name)
  303. {
  304. v8::HandleScope handle_scope(__isolate);
  305. if (_obj.persistent().IsEmpty())
  306. {
  307. return false;
  308. }
  309. v8::MaybeLocal<v8::String> nameValue = v8::String::NewFromUtf8(__isolate, name, v8::NewStringType::kNormal);
  310. if (nameValue.IsEmpty())
  311. return false;
  312. v8::Local<v8::String> nameValToLocal = nameValue.ToLocalChecked();
  313. v8::Local<v8::Context> context = __isolate->GetCurrentContext();
  314. v8::Maybe<bool> maybeExist = _obj.handle(__isolate)->Delete(context, nameValToLocal);
  315. if (maybeExist.IsNothing())
  316. return false;
  317. if (!maybeExist.FromJust())
  318. return false;
  319. return true;
  320. }
  321. bool Object::setProperty(const char *name, const Value& data)
  322. {
  323. v8::MaybeLocal<v8::String> nameValue = v8::String::NewFromUtf8(__isolate, name, v8::NewStringType::kNormal);
  324. if (nameValue.IsEmpty())
  325. return false;
  326. v8::Local<v8::Value> value;
  327. internal::seToJsValue(__isolate, data, &value);
  328. v8::Maybe<bool> ret = _obj.handle(__isolate)->Set(__isolate->GetCurrentContext(), nameValue.ToLocalChecked(), value);
  329. if (ret.IsNothing())
  330. {
  331. SE_LOGD("ERROR: %s, Set return nothing ...\n", __FUNCTION__);
  332. return false;
  333. }
  334. return true;
  335. }
  336. bool Object::defineProperty(const char *name, v8::AccessorNameGetterCallback getter, v8::AccessorNameSetterCallback setter)
  337. {
  338. v8::MaybeLocal<v8::String> nameValue = v8::String::NewFromUtf8(__isolate, name, v8::NewStringType::kNormal);
  339. if (nameValue.IsEmpty())
  340. return false;
  341. v8::Local<v8::String> nameValChecked = nameValue.ToLocalChecked();
  342. v8::Local<v8::Name> jsName = v8::Local<v8::Name>::Cast(nameValChecked);
  343. v8::Maybe<bool> ret = _obj.handle(__isolate)->SetAccessor(__isolate->GetCurrentContext(), jsName, getter, setter);
  344. return ret.IsJust() && ret.FromJust();
  345. }
  346. bool Object::isFunction() const
  347. {
  348. return const_cast<Object*>(this)->_obj.handle(__isolate)->IsCallable();
  349. }
  350. bool Object::_isNativeFunction() const
  351. {
  352. if (isFunction())
  353. {
  354. std::string info = toString();
  355. if (info.find("[native code]") != std::string::npos)
  356. {
  357. return true;
  358. }
  359. }
  360. return false;
  361. }
  362. bool Object::isTypedArray() const
  363. {
  364. return const_cast<Object*>(this)->_obj.handle(__isolate)->IsTypedArray();
  365. }
  366. Object::TypedArrayType Object::getTypedArrayType() const
  367. {
  368. v8::Local<v8::Value> value = const_cast<Object*>(this)->_obj.handle(__isolate);
  369. TypedArrayType ret = TypedArrayType::NONE;
  370. if (value->IsInt8Array())
  371. ret = TypedArrayType::INT8;
  372. else if (value->IsInt16Array())
  373. ret = TypedArrayType::INT16;
  374. else if (value->IsInt32Array())
  375. ret = TypedArrayType::INT32;
  376. else if (value->IsUint8Array())
  377. ret = TypedArrayType::UINT8;
  378. else if (value->IsUint8ClampedArray())
  379. ret = TypedArrayType::UINT8_CLAMPED;
  380. else if (value->IsUint16Array())
  381. ret = TypedArrayType::UINT16;
  382. else if (value->IsUint32Array())
  383. ret = TypedArrayType::UINT32;
  384. else if (value->IsFloat32Array())
  385. ret = TypedArrayType::FLOAT32;
  386. else if (value->IsFloat64Array())
  387. ret = TypedArrayType::FLOAT64;
  388. return ret;
  389. }
  390. bool Object::getTypedArrayData(uint8_t** ptr, size_t* length) const
  391. {
  392. assert(isTypedArray());
  393. v8::Local<v8::Object> obj = const_cast<Object*>(this)->_obj.handle(__isolate);
  394. v8::Local<v8::TypedArray> arr = v8::Local<v8::TypedArray>::Cast(obj);
  395. v8::ArrayBuffer::Contents content = arr->Buffer()->GetContents();
  396. *ptr = (uint8_t*)content.Data() + arr->ByteOffset();
  397. *length = arr->ByteLength();
  398. return true;
  399. }
  400. bool Object::isArrayBuffer() const
  401. {
  402. v8::Local<v8::Object> obj = const_cast<Object*>(this)->_obj.handle(__isolate);
  403. return obj->IsArrayBuffer();
  404. }
  405. bool Object::getArrayBufferData(uint8_t** ptr, size_t* length) const
  406. {
  407. assert(isArrayBuffer());
  408. v8::Local<v8::Object> obj = const_cast<Object*>(this)->_obj.handle(__isolate);
  409. v8::Local<v8::ArrayBuffer> arrBuf = v8::Local<v8::ArrayBuffer>::Cast(obj);
  410. v8::ArrayBuffer::Contents content = arrBuf->GetContents();
  411. *ptr = (uint8_t*)content.Data();
  412. *length = content.ByteLength();
  413. return true;
  414. }
  415. void Object::setPrivateData(void* data)
  416. {
  417. assert(_privateData == nullptr);
  418. assert(NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end());
  419. internal::setPrivate(__isolate, _obj, data, &_internalData);
  420. NativePtrToObjectMap::emplace(data, this);
  421. _privateData = data;
  422. }
  423. void* Object::getPrivateData() const
  424. {
  425. if (_privateData == nullptr)
  426. {
  427. const_cast<Object*>(this)->_privateData = internal::getPrivate(__isolate, const_cast<Object*>(this)->_obj.handle(__isolate));
  428. }
  429. return _privateData;
  430. }
  431. void Object::clearPrivateData(bool clearMapping)
  432. {
  433. if (_privateData != nullptr)
  434. {
  435. if (clearMapping)
  436. NativePtrToObjectMap::erase(_privateData);
  437. internal::clearPrivate(__isolate, _obj);
  438. _privateData = nullptr;
  439. }
  440. }
  441. v8::Local<v8::Object> Object::_getJSObject() const
  442. {
  443. return const_cast<Object*>(this)->_obj.handle(__isolate);
  444. }
  445. ObjectWrap& Object::_getWrap()
  446. {
  447. return _obj;
  448. }
  449. bool Object::call(const ValueArray& args, Object* thisObject, Value* rval/* = nullptr*/)
  450. {
  451. if (_obj.persistent().IsEmpty())
  452. {
  453. SE_LOGD("Function object is released!\n");
  454. return false;
  455. }
  456. size_t argc = 0;
  457. std::vector<v8::Local<v8::Value>> argv;
  458. argv.reserve(10);
  459. argc = args.size();
  460. internal::seToJsArgs(__isolate, args, &argv);
  461. v8::Local<v8::Object> thiz = v8::Local<v8::Object>::Cast(v8::Undefined(__isolate));
  462. if (thisObject != nullptr)
  463. {
  464. if (thisObject->_obj.persistent().IsEmpty())
  465. {
  466. SE_LOGD("This object is released!\n");
  467. return false;
  468. }
  469. thiz = thisObject->_obj.handle(__isolate);
  470. }
  471. for (size_t i = 0; i < argc; ++i)
  472. {
  473. if (argv[i].IsEmpty())
  474. {
  475. SE_LOGD("%s argv[%d] is released!\n", __FUNCTION__, (int)i);
  476. return false;
  477. }
  478. }
  479. v8::Local<v8::Context> context = se::ScriptEngine::getInstance()->_getContext();
  480. v8::MaybeLocal<v8::Value> result = _obj.handle(__isolate)->CallAsFunction(context, thiz, (int)argc, argv.data());
  481. if (!result.IsEmpty())
  482. {
  483. if (rval != nullptr)
  484. {
  485. internal::jsToSeValue(__isolate, result.ToLocalChecked(), rval);
  486. }
  487. return true;
  488. }
  489. else
  490. {
  491. SE_REPORT_ERROR("Invoking function (%p) failed!", this);
  492. se::ScriptEngine::getInstance()->clearException();
  493. }
  494. // assert(false);
  495. return false;
  496. }
  497. bool Object::defineFunction(const char *funcName, void (*func)(const v8::FunctionCallbackInfo<v8::Value> &args))
  498. {
  499. v8::MaybeLocal<v8::String> maybeFuncName = v8::String::NewFromUtf8(__isolate, funcName, v8::NewStringType::kNormal);
  500. if (maybeFuncName.IsEmpty())
  501. return false;
  502. v8::Local<v8::Context> context = __isolate->GetCurrentContext();
  503. v8::MaybeLocal<v8::Function> maybeFunc = v8::FunctionTemplate::New(__isolate, func)->GetFunction(context);
  504. if (maybeFunc.IsEmpty())
  505. return false;
  506. v8::Maybe<bool> ret = _obj.handle(__isolate)->Set(context,
  507. v8::Local<v8::Name>::Cast(maybeFuncName.ToLocalChecked()),
  508. maybeFunc.ToLocalChecked());
  509. return ret.IsJust() && ret.FromJust();
  510. }
  511. bool Object::isArray() const
  512. {
  513. return const_cast<Object*>(this)->_obj.handle(__isolate)->IsArray();
  514. }
  515. bool Object::getArrayLength(uint32_t* length) const
  516. {
  517. assert(isArray());
  518. assert(length != nullptr);
  519. Object* thiz = const_cast<Object*>(this);
  520. v8::MaybeLocal<v8::String> lengthStr = v8::String::NewFromUtf8(__isolate, "length", v8::NewStringType::kNormal);
  521. if (lengthStr.IsEmpty())
  522. {
  523. *length = 0;
  524. return false;
  525. }
  526. v8::Local<v8::Context> context = __isolate->GetCurrentContext();
  527. v8::MaybeLocal<v8::Value> val = thiz->_obj.handle(__isolate)->Get(context, lengthStr.ToLocalChecked());
  528. if (val.IsEmpty())
  529. return false;
  530. v8::MaybeLocal<v8::Object> obj = val.ToLocalChecked()->ToObject(context);
  531. if (obj.IsEmpty())
  532. return false;
  533. v8::Maybe<uint32_t> mbLen= obj.ToLocalChecked()->Uint32Value(context);
  534. if (mbLen.IsNothing())
  535. return false;
  536. *length = mbLen.FromJust();
  537. return true;
  538. }
  539. bool Object::getArrayElement(uint32_t index, Value* data) const
  540. {
  541. assert(isArray());
  542. assert(data != nullptr);
  543. Object* thiz = const_cast<Object*>(this);
  544. v8::MaybeLocal<v8::Value> result = thiz->_obj.handle(__isolate)->Get(__isolate->GetCurrentContext(), index);
  545. if (result.IsEmpty())
  546. return false;
  547. internal::jsToSeValue(__isolate, result.ToLocalChecked(), data);
  548. return true;
  549. }
  550. bool Object::setArrayElement(uint32_t index, const Value& data)
  551. {
  552. assert(isArray());
  553. v8::Local<v8::Value> jsval;
  554. internal::seToJsValue(__isolate, data, &jsval);
  555. v8::Maybe<bool> ret = _obj.handle(__isolate)->Set(__isolate->GetCurrentContext(), index, jsval);
  556. return ret.IsJust() && ret.FromJust();
  557. }
  558. bool Object::getAllKeys(std::vector<std::string>* allKeys) const
  559. {
  560. assert(allKeys != nullptr);
  561. Object* thiz = const_cast<Object*>(this);
  562. v8::Local<v8::Context> context = __isolate->GetCurrentContext();
  563. v8::MaybeLocal<v8::Array> keys = thiz->_obj.handle(__isolate)->GetOwnPropertyNames(context);
  564. if (keys.IsEmpty())
  565. return false;
  566. v8::Local<v8::Array> keysChecked = keys.ToLocalChecked();
  567. Value keyVal;
  568. for (uint32_t i = 0, len = keysChecked->Length(); i < len; ++i)
  569. {
  570. v8::MaybeLocal<v8::Value> key = keysChecked->Get(context, i);
  571. if (key.IsEmpty())
  572. {
  573. allKeys->clear();
  574. return false;
  575. }
  576. internal::jsToSeValue(__isolate, key.ToLocalChecked(), &keyVal);
  577. if (keyVal.isString())
  578. {
  579. allKeys->push_back(keyVal.toString());
  580. }
  581. else if (keyVal.isNumber())
  582. {
  583. char buf[50] = {0};
  584. snprintf(buf, sizeof(buf), "%d", keyVal.toInt32());
  585. allKeys->push_back(buf);
  586. }
  587. else
  588. {
  589. assert(false);
  590. }
  591. }
  592. return true;
  593. }
  594. Class* Object::_getClass() const
  595. {
  596. return _cls;
  597. }
  598. void Object::_setFinalizeCallback(V8FinalizeFunc finalizeCb)
  599. {
  600. assert(finalizeCb != nullptr);
  601. _finalizeCb = finalizeCb;
  602. }
  603. void Object::root()
  604. {
  605. if (_rootCount == 0)
  606. {
  607. _obj.ref();
  608. }
  609. ++_rootCount;
  610. }
  611. void Object::unroot()
  612. {
  613. if (_rootCount > 0)
  614. {
  615. --_rootCount;
  616. if (_rootCount == 0)
  617. {
  618. _obj.unref();
  619. }
  620. }
  621. }
  622. bool Object::isRooted() const
  623. {
  624. return _rootCount > 0;
  625. }
  626. bool Object::strictEquals(Object *o) const
  627. {
  628. Object* a = const_cast<Object*>(this);
  629. return a->_obj.handle(__isolate) == o->_obj.handle(__isolate);
  630. }
  631. bool Object::attachObject(Object* obj)
  632. {
  633. assert(obj);
  634. Object* global = ScriptEngine::getInstance()->getGlobalObject();
  635. Value jsbVal;
  636. if (!global->getProperty("jsb", &jsbVal))
  637. return false;
  638. Object* jsbObj = jsbVal.toObject();
  639. Value func;
  640. if (!jsbObj->getProperty("registerNativeRef", &func))
  641. return false;
  642. ValueArray args;
  643. args.push_back(Value(this));
  644. args.push_back(Value(obj));
  645. func.toObject()->call(args, global);
  646. return true;
  647. }
  648. bool Object::detachObject(Object* obj)
  649. {
  650. assert(obj);
  651. Object* global = ScriptEngine::getInstance()->getGlobalObject();
  652. Value jsbVal;
  653. if (!global->getProperty("jsb", &jsbVal))
  654. return false;
  655. Object* jsbObj = jsbVal.toObject();
  656. Value func;
  657. if (!jsbObj->getProperty("unregisterNativeRef", &func))
  658. return false;
  659. ValueArray args;
  660. args.push_back(Value(this));
  661. args.push_back(Value(obj));
  662. func.toObject()->call(args, global);
  663. return true;
  664. }
  665. std::string Object::toString() const
  666. {
  667. std::string ret;
  668. if (isFunction() || isArray() || isTypedArray())
  669. {
  670. v8::String::Utf8Value utf8(__isolate, const_cast<Object*>(this)->_obj.handle(__isolate));
  671. ret = *utf8;
  672. }
  673. else if (isArrayBuffer())
  674. {
  675. ret = "[object ArrayBuffer]";
  676. }
  677. else
  678. {
  679. ret = "[object Object]";
  680. }
  681. return ret;
  682. }
  683. } // namespace se {
  684. #endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8