JSCRuntime.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include "JSCRuntime.h"
  8. #include <JavaScriptCore/JavaScript.h>
  9. #include <jsi/jsilib.h>
  10. #include <array>
  11. #include <atomic>
  12. #include <condition_variable>
  13. #include <cstdlib>
  14. #include <mutex>
  15. #include <queue>
  16. #include <sstream>
  17. #include <thread>
  18. namespace facebook {
  19. namespace jsc {
  20. namespace detail {
  21. class ArgsConverter;
  22. } // namespace detail
  23. class JSCRuntime;
  24. struct Lock {
  25. void lock(const jsc::JSCRuntime &) const {}
  26. void unlock(const jsc::JSCRuntime &) const {}
  27. };
  28. class JSCRuntime : public jsi::Runtime {
  29. public:
  30. // Creates new context in new context group
  31. JSCRuntime();
  32. // Retains ctx
  33. JSCRuntime(JSGlobalContextRef ctx);
  34. ~JSCRuntime();
  35. std::shared_ptr<const jsi::PreparedJavaScript> prepareJavaScript(
  36. const std::shared_ptr<const jsi::Buffer> &buffer,
  37. std::string sourceURL) override;
  38. jsi::Value evaluatePreparedJavaScript(
  39. const std::shared_ptr<const jsi::PreparedJavaScript> &js) override;
  40. jsi::Value evaluateJavaScript(
  41. const std::shared_ptr<const jsi::Buffer> &buffer,
  42. const std::string &sourceURL) override;
  43. jsi::Object global() override;
  44. std::string description() override;
  45. bool isInspectable() override;
  46. void setDescription(const std::string &desc);
  47. // Please don't use the following two functions, only exposed for
  48. // integration efforts.
  49. JSGlobalContextRef getContext() {
  50. return ctx_;
  51. }
  52. // JSValueRef->JSValue (needs make.*Value so it must be member function)
  53. jsi::Value createValue(JSValueRef value) const;
  54. // Value->JSValueRef (similar to above)
  55. JSValueRef valueRef(const jsi::Value &value);
  56. protected:
  57. friend class detail::ArgsConverter;
  58. class JSCSymbolValue final : public PointerValue {
  59. #ifndef NDEBUG
  60. JSCSymbolValue(
  61. JSGlobalContextRef ctx,
  62. const std::atomic<bool> &ctxInvalid,
  63. JSValueRef sym,
  64. std::atomic<intptr_t> &counter);
  65. #else
  66. JSCSymbolValue(
  67. JSGlobalContextRef ctx,
  68. const std::atomic<bool> &ctxInvalid,
  69. JSValueRef sym);
  70. #endif
  71. void invalidate() override;
  72. JSGlobalContextRef ctx_;
  73. const std::atomic<bool> &ctxInvalid_;
  74. // There is no C type in the JSC API to represent Symbol, so this stored
  75. // a JSValueRef which contains the Symbol.
  76. JSValueRef sym_;
  77. #ifndef NDEBUG
  78. std::atomic<intptr_t> &counter_;
  79. #endif
  80. protected:
  81. friend class JSCRuntime;
  82. };
  83. class JSCStringValue final : public PointerValue {
  84. #ifndef NDEBUG
  85. JSCStringValue(JSStringRef str, std::atomic<intptr_t> &counter);
  86. #else
  87. JSCStringValue(JSStringRef str);
  88. #endif
  89. void invalidate() override;
  90. JSStringRef str_;
  91. #ifndef NDEBUG
  92. std::atomic<intptr_t> &counter_;
  93. #endif
  94. protected:
  95. friend class JSCRuntime;
  96. };
  97. class JSCObjectValue final : public PointerValue {
  98. JSCObjectValue(
  99. JSGlobalContextRef ctx,
  100. const std::atomic<bool> &ctxInvalid,
  101. JSObjectRef obj
  102. #ifndef NDEBUG
  103. ,
  104. std::atomic<intptr_t> &counter
  105. #endif
  106. );
  107. void invalidate() override;
  108. JSGlobalContextRef ctx_;
  109. const std::atomic<bool> &ctxInvalid_;
  110. JSObjectRef obj_;
  111. #ifndef NDEBUG
  112. std::atomic<intptr_t> &counter_;
  113. #endif
  114. protected:
  115. friend class JSCRuntime;
  116. };
  117. PointerValue *cloneSymbol(const Runtime::PointerValue *pv) override;
  118. PointerValue *cloneString(const Runtime::PointerValue *pv) override;
  119. PointerValue *cloneObject(const Runtime::PointerValue *pv) override;
  120. PointerValue *clonePropNameID(const Runtime::PointerValue *pv) override;
  121. jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length)
  122. override;
  123. jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length)
  124. override;
  125. jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override;
  126. std::string utf8(const jsi::PropNameID &) override;
  127. bool compare(const jsi::PropNameID &, const jsi::PropNameID &) override;
  128. std::string symbolToString(const jsi::Symbol &) override;
  129. jsi::String createStringFromAscii(const char *str, size_t length) override;
  130. jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override;
  131. std::string utf8(const jsi::String &) override;
  132. jsi::Object createObject() override;
  133. jsi::Object createObject(std::shared_ptr<jsi::HostObject> ho) override;
  134. virtual std::shared_ptr<jsi::HostObject> getHostObject(
  135. const jsi::Object &) override;
  136. jsi::HostFunctionType &getHostFunction(const jsi::Function &) override;
  137. jsi::Value getProperty(const jsi::Object &, const jsi::String &name) override;
  138. jsi::Value getProperty(const jsi::Object &, const jsi::PropNameID &name)
  139. override;
  140. bool hasProperty(const jsi::Object &, const jsi::String &name) override;
  141. bool hasProperty(const jsi::Object &, const jsi::PropNameID &name) override;
  142. void setPropertyValue(
  143. jsi::Object &,
  144. const jsi::String &name,
  145. const jsi::Value &value) override;
  146. void setPropertyValue(
  147. jsi::Object &,
  148. const jsi::PropNameID &name,
  149. const jsi::Value &value) override;
  150. bool isArray(const jsi::Object &) const override;
  151. bool isArrayBuffer(const jsi::Object &) const override;
  152. bool isFunction(const jsi::Object &) const override;
  153. bool isHostObject(const jsi::Object &) const override;
  154. bool isHostFunction(const jsi::Function &) const override;
  155. jsi::Array getPropertyNames(const jsi::Object &) override;
  156. // TODO: revisit this implementation
  157. jsi::WeakObject createWeakObject(const jsi::Object &) override;
  158. jsi::Value lockWeakObject(const jsi::WeakObject &) override;
  159. jsi::Array createArray(size_t length) override;
  160. size_t size(const jsi::Array &) override;
  161. size_t size(const jsi::ArrayBuffer &) override;
  162. uint8_t *data(const jsi::ArrayBuffer &) override;
  163. jsi::Value getValueAtIndex(const jsi::Array &, size_t i) override;
  164. void setValueAtIndexImpl(jsi::Array &, size_t i, const jsi::Value &value)
  165. override;
  166. jsi::Function createFunctionFromHostFunction(
  167. const jsi::PropNameID &name,
  168. unsigned int paramCount,
  169. jsi::HostFunctionType func) override;
  170. jsi::Value call(
  171. const jsi::Function &,
  172. const jsi::Value &jsThis,
  173. const jsi::Value *args,
  174. size_t count) override;
  175. jsi::Value callAsConstructor(
  176. const jsi::Function &,
  177. const jsi::Value *args,
  178. size_t count) override;
  179. bool strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const override;
  180. bool strictEquals(const jsi::String &a, const jsi::String &b) const override;
  181. bool strictEquals(const jsi::Object &a, const jsi::Object &b) const override;
  182. bool instanceOf(const jsi::Object &o, const jsi::Function &f) override;
  183. private:
  184. // Basically convenience casts
  185. static JSValueRef symbolRef(const jsi::Symbol &str);
  186. static JSStringRef stringRef(const jsi::String &str);
  187. static JSStringRef stringRef(const jsi::PropNameID &sym);
  188. static JSObjectRef objectRef(const jsi::Object &obj);
  189. #ifdef RN_FABRIC_ENABLED
  190. static JSObjectRef objectRef(const jsi::WeakObject &obj);
  191. #endif
  192. // Factory methods for creating String/Object
  193. jsi::Symbol createSymbol(JSValueRef symbolRef) const;
  194. jsi::String createString(JSStringRef stringRef) const;
  195. jsi::PropNameID createPropNameID(JSStringRef stringRef);
  196. jsi::Object createObject(JSObjectRef objectRef) const;
  197. // Used by factory methods and clone methods
  198. jsi::Runtime::PointerValue *makeSymbolValue(JSValueRef sym) const;
  199. jsi::Runtime::PointerValue *makeStringValue(JSStringRef str) const;
  200. jsi::Runtime::PointerValue *makeObjectValue(JSObjectRef obj) const;
  201. void checkException(JSValueRef exc);
  202. void checkException(JSValueRef res, JSValueRef exc);
  203. void checkException(JSValueRef exc, const char *msg);
  204. void checkException(JSValueRef res, JSValueRef exc, const char *msg);
  205. JSGlobalContextRef ctx_;
  206. std::atomic<bool> ctxInvalid_;
  207. std::string desc_;
  208. #ifndef NDEBUG
  209. mutable std::atomic<intptr_t> objectCounter_;
  210. mutable std::atomic<intptr_t> symbolCounter_;
  211. mutable std::atomic<intptr_t> stringCounter_;
  212. #endif
  213. };
  214. #ifndef __has_builtin
  215. #define __has_builtin(x) 0
  216. #endif
  217. #if __has_builtin(__builtin_expect) || defined(__GNUC__)
  218. #define JSC_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
  219. #define JSC_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
  220. #else
  221. #define JSC_LIKELY(EXPR) (EXPR)
  222. #define JSC_UNLIKELY(EXPR) (EXPR)
  223. #endif
  224. #define JSC_ASSERT(x) \
  225. do { \
  226. if (JSC_UNLIKELY(!!(x))) { \
  227. abort(); \
  228. } \
  229. } while (0)
  230. #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
  231. // This takes care of watch and tvos (due to backwards compatibility in
  232. // Availability.h
  233. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0
  234. #define _JSC_FAST_IS_ARRAY
  235. #endif
  236. #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0
  237. #define _JSC_NO_ARRAY_BUFFERS
  238. #endif
  239. #endif
  240. #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
  241. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11
  242. // Only one of these should be set for a build. If somehow that's not
  243. // true, this will be a compile-time error and it can be resolved when
  244. // we understand why.
  245. #define _JSC_FAST_IS_ARRAY
  246. #endif
  247. #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12
  248. #define _JSC_NO_ARRAY_BUFFERS
  249. #endif
  250. #endif
  251. // JSStringRef utilities
  252. namespace {
  253. std::string JSStringToSTLString(JSStringRef str) {
  254. // Small string optimization: Avoid one heap allocation for strings that fit
  255. // in stackBuffer.size() bytes of UTF-8 (including the null terminator).
  256. std::array<char, 20> stackBuffer;
  257. std::unique_ptr<char[]> heapBuffer;
  258. char *buffer;
  259. // NOTE: By definition, maxBytes >= 1 since the null terminator is included.
  260. size_t maxBytes = JSStringGetMaximumUTF8CStringSize(str);
  261. if (maxBytes <= stackBuffer.size()) {
  262. buffer = stackBuffer.data();
  263. } else {
  264. heapBuffer = std::make_unique<char[]>(maxBytes);
  265. buffer = heapBuffer.get();
  266. }
  267. size_t actualBytes = JSStringGetUTF8CString(str, buffer, maxBytes);
  268. if (!actualBytes) {
  269. // Happens if maxBytes == 0 (never the case here) or if str contains
  270. // invalid UTF-16 data, since JSStringGetUTF8CString attempts a strict
  271. // conversion.
  272. // When converting an invalid string, JSStringGetUTF8CString writes a null
  273. // terminator before returning. So we can reliably treat our buffer as a C
  274. // string and return the truncated data to our caller. This is slightly
  275. // slower than if we knew the length (like below) but better than crashing.
  276. // TODO(T62295565): Perform a non-strict, best effort conversion of the
  277. // full string instead, like we did before the JSI migration.
  278. return std::string(buffer);
  279. }
  280. return std::string(buffer, actualBytes - 1);
  281. }
  282. JSStringRef getLengthString() {
  283. static JSStringRef length = JSStringCreateWithUTF8CString("length");
  284. return length;
  285. }
  286. JSStringRef getNameString() {
  287. static JSStringRef name = JSStringCreateWithUTF8CString("name");
  288. return name;
  289. }
  290. JSStringRef getFunctionString() {
  291. static JSStringRef func = JSStringCreateWithUTF8CString("Function");
  292. return func;
  293. }
  294. #if !defined(_JSC_FAST_IS_ARRAY)
  295. JSStringRef getArrayString() {
  296. static JSStringRef array = JSStringCreateWithUTF8CString("Array");
  297. return array;
  298. }
  299. JSStringRef getIsArrayString() {
  300. static JSStringRef isArray = JSStringCreateWithUTF8CString("isArray");
  301. return isArray;
  302. }
  303. #endif
  304. } // namespace
  305. // std::string utility
  306. namespace {
  307. std::string to_string(void *value) {
  308. std::ostringstream ss;
  309. ss << value;
  310. return ss.str();
  311. }
  312. } // namespace
  313. JSCRuntime::JSCRuntime()
  314. : JSCRuntime(JSGlobalContextCreateInGroup(nullptr, nullptr)) {
  315. JSGlobalContextRelease(ctx_);
  316. }
  317. JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
  318. : ctx_(JSGlobalContextRetain(ctx)),
  319. ctxInvalid_(false)
  320. #ifndef NDEBUG
  321. ,
  322. objectCounter_(0),
  323. stringCounter_(0)
  324. #endif
  325. {
  326. }
  327. JSCRuntime::~JSCRuntime() {
  328. // On shutting down and cleaning up: when JSC is actually torn down,
  329. // it calls JSC::Heap::lastChanceToFinalize internally which
  330. // finalizes anything left over. But at this point,
  331. // JSValueUnprotect() can no longer be called. We use an
  332. // atomic<bool> to avoid unsafe unprotects happening after shutdown
  333. // has started.
  334. ctxInvalid_ = true;
  335. JSGlobalContextRelease(ctx_);
  336. #ifndef NDEBUG
  337. assert(
  338. objectCounter_ == 0 && "JSCRuntime destroyed with a dangling API object");
  339. assert(
  340. stringCounter_ == 0 && "JSCRuntime destroyed with a dangling API string");
  341. #endif
  342. }
  343. std::shared_ptr<const jsi::PreparedJavaScript> JSCRuntime::prepareJavaScript(
  344. const std::shared_ptr<const jsi::Buffer> &buffer,
  345. std::string sourceURL) {
  346. return std::make_shared<jsi::SourceJavaScriptPreparation>(
  347. buffer, std::move(sourceURL));
  348. }
  349. jsi::Value JSCRuntime::evaluatePreparedJavaScript(
  350. const std::shared_ptr<const jsi::PreparedJavaScript> &js) {
  351. assert(
  352. dynamic_cast<const jsi::SourceJavaScriptPreparation *>(js.get()) &&
  353. "preparedJavaScript must be a SourceJavaScriptPreparation");
  354. auto sourceJs =
  355. std::static_pointer_cast<const jsi::SourceJavaScriptPreparation>(js);
  356. return evaluateJavaScript(sourceJs, sourceJs->sourceURL());
  357. }
  358. jsi::Value JSCRuntime::evaluateJavaScript(
  359. const std::shared_ptr<const jsi::Buffer> &buffer,
  360. const std::string &sourceURL) {
  361. std::string tmp(
  362. reinterpret_cast<const char *>(buffer->data()), buffer->size());
  363. JSStringRef sourceRef = JSStringCreateWithUTF8CString(tmp.c_str());
  364. JSStringRef sourceURLRef = nullptr;
  365. if (!sourceURL.empty()) {
  366. sourceURLRef = JSStringCreateWithUTF8CString(sourceURL.c_str());
  367. }
  368. JSValueRef exc = nullptr;
  369. JSValueRef res =
  370. JSEvaluateScript(ctx_, sourceRef, nullptr, sourceURLRef, 0, &exc);
  371. JSStringRelease(sourceRef);
  372. if (sourceURLRef) {
  373. JSStringRelease(sourceURLRef);
  374. }
  375. checkException(res, exc);
  376. return createValue(res);
  377. }
  378. jsi::Object JSCRuntime::global() {
  379. return createObject(JSContextGetGlobalObject(ctx_));
  380. }
  381. std::string JSCRuntime::description() {
  382. if (desc_.empty()) {
  383. desc_ = std::string("<JSCRuntime@") + to_string(this) + ">";
  384. }
  385. return desc_;
  386. }
  387. bool JSCRuntime::isInspectable() {
  388. return false;
  389. }
  390. namespace {
  391. bool smellsLikeES6Symbol(JSGlobalContextRef ctx, JSValueRef ref) {
  392. // Since iOS 13, JSValueGetType will return kJSTypeSymbol
  393. // Before: Empirically, an es6 Symbol is not an object, but its type is
  394. // object. This makes no sense, but we'll run with it.
  395. // https://github.com/WebKit/webkit/blob/master/Source/JavaScriptCore/API/JSValueRef.cpp#L79-L82
  396. JSType type = JSValueGetType(ctx, ref);
  397. if (type == /* kJSTypeSymbol */ 6) {
  398. return true;
  399. }
  400. return (!JSValueIsObject(ctx, ref) && type == kJSTypeObject);
  401. }
  402. } // namespace
  403. JSCRuntime::JSCSymbolValue::JSCSymbolValue(
  404. JSGlobalContextRef ctx,
  405. const std::atomic<bool> &ctxInvalid,
  406. JSValueRef sym
  407. #ifndef NDEBUG
  408. ,
  409. std::atomic<intptr_t> &counter
  410. #endif
  411. )
  412. : ctx_(ctx),
  413. ctxInvalid_(ctxInvalid),
  414. sym_(sym)
  415. #ifndef NDEBUG
  416. ,
  417. counter_(counter)
  418. #endif
  419. {
  420. assert(smellsLikeES6Symbol(ctx_, sym_));
  421. JSValueProtect(ctx_, sym_);
  422. #ifndef NDEBUG
  423. counter_ += 1;
  424. #endif
  425. }
  426. void JSCRuntime::JSCSymbolValue::invalidate() {
  427. #ifndef NDEBUG
  428. counter_ -= 1;
  429. #endif
  430. if (!ctxInvalid_) {
  431. JSValueUnprotect(ctx_, sym_);
  432. }
  433. delete this;
  434. }
  435. #ifndef NDEBUG
  436. JSCRuntime::JSCStringValue::JSCStringValue(
  437. JSStringRef str,
  438. std::atomic<intptr_t> &counter)
  439. : str_(JSStringRetain(str)), counter_(counter) {
  440. // Since std::atomic returns a copy instead of a reference when calling
  441. // operator+= we must do this explicitly in the constructor
  442. counter_ += 1;
  443. }
  444. #else
  445. JSCRuntime::JSCStringValue::JSCStringValue(JSStringRef str)
  446. : str_(JSStringRetain(str)) {}
  447. #endif
  448. void JSCRuntime::JSCStringValue::invalidate() {
  449. // These JSC{String,Object}Value objects are implicitly owned by the
  450. // {String,Object} objects, thus when a String/Object is destructed
  451. // the JSC{String,Object}Value should be released.
  452. #ifndef NDEBUG
  453. counter_ -= 1;
  454. #endif
  455. JSStringRelease(str_);
  456. // Angery reaccs only
  457. delete this;
  458. }
  459. JSCRuntime::JSCObjectValue::JSCObjectValue(
  460. JSGlobalContextRef ctx,
  461. const std::atomic<bool> &ctxInvalid,
  462. JSObjectRef obj
  463. #ifndef NDEBUG
  464. ,
  465. std::atomic<intptr_t> &counter
  466. #endif
  467. )
  468. : ctx_(ctx),
  469. ctxInvalid_(ctxInvalid),
  470. obj_(obj)
  471. #ifndef NDEBUG
  472. ,
  473. counter_(counter)
  474. #endif
  475. {
  476. JSValueProtect(ctx_, obj_);
  477. #ifndef NDEBUG
  478. counter_ += 1;
  479. #endif
  480. }
  481. void JSCRuntime::JSCObjectValue::invalidate() {
  482. #ifndef NDEBUG
  483. counter_ -= 1;
  484. #endif
  485. // When shutting down the VM, if there is a HostObject which
  486. // contains or otherwise owns a jsi::Object, then the final GC will
  487. // finalize the HostObject, leading to a call to invalidate(). But
  488. // at that point, making calls to JSValueUnprotect will crash.
  489. // It is up to the application to make sure that any other calls to
  490. // invalidate() happen before VM destruction; see the comment on
  491. // jsi::Runtime.
  492. //
  493. // Another potential concern here is that in the non-shutdown case,
  494. // if a HostObject is GCd, JSValueUnprotect will be called from the
  495. // JSC finalizer. The documentation warns against this: "You must
  496. // not call any function that may cause a garbage collection or an
  497. // allocation of a garbage collected object from within a
  498. // JSObjectFinalizeCallback. This includes all functions that have a
  499. // JSContextRef parameter." However, an audit of the source code for
  500. // JSValueUnprotect in late 2018 shows that it cannot cause
  501. // allocation or a GC, and further, this code has not changed in
  502. // about two years. In the future, we may choose to reintroduce the
  503. // mechanism previously used here which uses a separate thread for
  504. // JSValueUnprotect, in order to conform to the documented API, but
  505. // use the "unsafe" synchronous version on iOS 11 and earlier.
  506. if (!ctxInvalid_) {
  507. JSValueUnprotect(ctx_, obj_);
  508. }
  509. delete this;
  510. }
  511. jsi::Runtime::PointerValue *JSCRuntime::cloneSymbol(
  512. const jsi::Runtime::PointerValue *pv) {
  513. if (!pv) {
  514. return nullptr;
  515. }
  516. const JSCSymbolValue *symbol = static_cast<const JSCSymbolValue *>(pv);
  517. return makeSymbolValue(symbol->sym_);
  518. }
  519. jsi::Runtime::PointerValue *JSCRuntime::cloneString(
  520. const jsi::Runtime::PointerValue *pv) {
  521. if (!pv) {
  522. return nullptr;
  523. }
  524. const JSCStringValue *string = static_cast<const JSCStringValue *>(pv);
  525. return makeStringValue(string->str_);
  526. }
  527. jsi::Runtime::PointerValue *JSCRuntime::cloneObject(
  528. const jsi::Runtime::PointerValue *pv) {
  529. if (!pv) {
  530. return nullptr;
  531. }
  532. const JSCObjectValue *object = static_cast<const JSCObjectValue *>(pv);
  533. assert(
  534. object->ctx_ == ctx_ &&
  535. "Don't try to clone an object backed by a different Runtime");
  536. return makeObjectValue(object->obj_);
  537. }
  538. jsi::Runtime::PointerValue *JSCRuntime::clonePropNameID(
  539. const jsi::Runtime::PointerValue *pv) {
  540. if (!pv) {
  541. return nullptr;
  542. }
  543. const JSCStringValue *string = static_cast<const JSCStringValue *>(pv);
  544. return makeStringValue(string->str_);
  545. }
  546. jsi::PropNameID JSCRuntime::createPropNameIDFromAscii(
  547. const char *str,
  548. size_t length) {
  549. // For system JSC this must is identical to a string
  550. std::string tmp(str, length);
  551. JSStringRef strRef = JSStringCreateWithUTF8CString(tmp.c_str());
  552. auto res = createPropNameID(strRef);
  553. JSStringRelease(strRef);
  554. return res;
  555. }
  556. jsi::PropNameID JSCRuntime::createPropNameIDFromUtf8(
  557. const uint8_t *utf8,
  558. size_t length) {
  559. std::string tmp(reinterpret_cast<const char *>(utf8), length);
  560. JSStringRef strRef = JSStringCreateWithUTF8CString(tmp.c_str());
  561. auto res = createPropNameID(strRef);
  562. JSStringRelease(strRef);
  563. return res;
  564. }
  565. jsi::PropNameID JSCRuntime::createPropNameIDFromString(const jsi::String &str) {
  566. return createPropNameID(stringRef(str));
  567. }
  568. std::string JSCRuntime::utf8(const jsi::PropNameID &sym) {
  569. return JSStringToSTLString(stringRef(sym));
  570. }
  571. bool JSCRuntime::compare(const jsi::PropNameID &a, const jsi::PropNameID &b) {
  572. return JSStringIsEqual(stringRef(a), stringRef(b));
  573. }
  574. std::string JSCRuntime::symbolToString(const jsi::Symbol &sym) {
  575. return jsi::Value(*this, sym).toString(*this).utf8(*this);
  576. }
  577. jsi::String JSCRuntime::createStringFromAscii(const char *str, size_t length) {
  578. // Yes we end up double casting for semantic reasons (UTF8 contains ASCII,
  579. // not the other way around)
  580. return this->createStringFromUtf8(
  581. reinterpret_cast<const uint8_t *>(str), length);
  582. }
  583. jsi::String JSCRuntime::createStringFromUtf8(
  584. const uint8_t *str,
  585. size_t length) {
  586. std::string tmp(reinterpret_cast<const char *>(str), length);
  587. JSStringRef stringRef = JSStringCreateWithUTF8CString(tmp.c_str());
  588. auto result = createString(stringRef);
  589. JSStringRelease(stringRef);
  590. return result;
  591. }
  592. std::string JSCRuntime::utf8(const jsi::String &str) {
  593. return JSStringToSTLString(stringRef(str));
  594. }
  595. jsi::Object JSCRuntime::createObject() {
  596. return createObject(static_cast<JSObjectRef>(nullptr));
  597. }
  598. // HostObject details
  599. namespace detail {
  600. struct HostObjectProxyBase {
  601. HostObjectProxyBase(
  602. JSCRuntime &rt,
  603. const std::shared_ptr<jsi::HostObject> &sho)
  604. : runtime(rt), hostObject(sho) {}
  605. JSCRuntime &runtime;
  606. std::shared_ptr<jsi::HostObject> hostObject;
  607. };
  608. } // namespace detail
  609. namespace {
  610. std::once_flag hostObjectClassOnceFlag;
  611. JSClassRef hostObjectClass{};
  612. } // namespace
  613. jsi::Object JSCRuntime::createObject(std::shared_ptr<jsi::HostObject> ho) {
  614. struct HostObjectProxy : public detail::HostObjectProxyBase {
  615. static JSValueRef getProperty(
  616. JSContextRef ctx,
  617. JSObjectRef object,
  618. JSStringRef propName,
  619. JSValueRef *exception) {
  620. auto proxy = static_cast<HostObjectProxy *>(JSObjectGetPrivate(object));
  621. auto &rt = proxy->runtime;
  622. jsi::PropNameID sym = rt.createPropNameID(propName);
  623. jsi::Value ret;
  624. try {
  625. ret = proxy->hostObject->get(rt, sym);
  626. } catch (const jsi::JSError &error) {
  627. *exception = rt.valueRef(error.value());
  628. return JSValueMakeUndefined(ctx);
  629. } catch (const std::exception &ex) {
  630. auto excValue =
  631. rt.global()
  632. .getPropertyAsFunction(rt, "Error")
  633. .call(
  634. rt,
  635. std::string("Exception in HostObject::get(propName:") +
  636. JSStringToSTLString(propName) + std::string("): ") +
  637. ex.what());
  638. *exception = rt.valueRef(excValue);
  639. return JSValueMakeUndefined(ctx);
  640. } catch (...) {
  641. auto excValue =
  642. rt.global()
  643. .getPropertyAsFunction(rt, "Error")
  644. .call(
  645. rt,
  646. std::string("Exception in HostObject::get(propName:") +
  647. JSStringToSTLString(propName) +
  648. std::string("): <unknown>"));
  649. *exception = rt.valueRef(excValue);
  650. return JSValueMakeUndefined(ctx);
  651. }
  652. return rt.valueRef(ret);
  653. }
  654. #define JSC_UNUSED(x) (void)(x);
  655. static bool setProperty(
  656. JSContextRef ctx,
  657. JSObjectRef object,
  658. JSStringRef propName,
  659. JSValueRef value,
  660. JSValueRef *exception) {
  661. JSC_UNUSED(ctx);
  662. auto proxy = static_cast<HostObjectProxy *>(JSObjectGetPrivate(object));
  663. auto &rt = proxy->runtime;
  664. jsi::PropNameID sym = rt.createPropNameID(propName);
  665. try {
  666. proxy->hostObject->set(rt, sym, rt.createValue(value));
  667. } catch (const jsi::JSError &error) {
  668. *exception = rt.valueRef(error.value());
  669. return false;
  670. } catch (const std::exception &ex) {
  671. auto excValue =
  672. rt.global()
  673. .getPropertyAsFunction(rt, "Error")
  674. .call(
  675. rt,
  676. std::string("Exception in HostObject::set(propName:") +
  677. JSStringToSTLString(propName) + std::string("): ") +
  678. ex.what());
  679. *exception = rt.valueRef(excValue);
  680. return false;
  681. } catch (...) {
  682. auto excValue =
  683. rt.global()
  684. .getPropertyAsFunction(rt, "Error")
  685. .call(
  686. rt,
  687. std::string("Exception in HostObject::set(propName:") +
  688. JSStringToSTLString(propName) +
  689. std::string("): <unknown>"));
  690. *exception = rt.valueRef(excValue);
  691. return false;
  692. }
  693. return true;
  694. }
  695. // JSC does not provide means to communicate errors from this callback,
  696. // so the error handling strategy is very brutal - we'll just crash
  697. // due to noexcept.
  698. static void getPropertyNames(
  699. JSContextRef ctx,
  700. JSObjectRef object,
  701. JSPropertyNameAccumulatorRef propertyNames) noexcept {
  702. JSC_UNUSED(ctx);
  703. auto proxy = static_cast<HostObjectProxy *>(JSObjectGetPrivate(object));
  704. auto &rt = proxy->runtime;
  705. auto names = proxy->hostObject->getPropertyNames(rt);
  706. for (auto &name : names) {
  707. JSPropertyNameAccumulatorAddName(propertyNames, stringRef(name));
  708. }
  709. }
  710. #undef JSC_UNUSED
  711. static void finalize(JSObjectRef obj) {
  712. auto hostObject = static_cast<HostObjectProxy *>(JSObjectGetPrivate(obj));
  713. JSObjectSetPrivate(obj, nullptr);
  714. delete hostObject;
  715. }
  716. using HostObjectProxyBase::HostObjectProxyBase;
  717. };
  718. std::call_once(hostObjectClassOnceFlag, []() {
  719. JSClassDefinition hostObjectClassDef = kJSClassDefinitionEmpty;
  720. hostObjectClassDef.version = 0;
  721. hostObjectClassDef.attributes = kJSClassAttributeNoAutomaticPrototype;
  722. hostObjectClassDef.finalize = HostObjectProxy::finalize;
  723. hostObjectClassDef.getProperty = HostObjectProxy::getProperty;
  724. hostObjectClassDef.setProperty = HostObjectProxy::setProperty;
  725. hostObjectClassDef.getPropertyNames = HostObjectProxy::getPropertyNames;
  726. hostObjectClass = JSClassCreate(&hostObjectClassDef);
  727. });
  728. JSObjectRef obj =
  729. JSObjectMake(ctx_, hostObjectClass, new HostObjectProxy(*this, ho));
  730. return createObject(obj);
  731. }
  732. std::shared_ptr<jsi::HostObject> JSCRuntime::getHostObject(
  733. const jsi::Object &obj) {
  734. // We are guaranteed at this point to have isHostObject(obj) == true
  735. // so the private data should be HostObjectMetadata
  736. JSObjectRef object = objectRef(obj);
  737. auto metadata =
  738. static_cast<detail::HostObjectProxyBase *>(JSObjectGetPrivate(object));
  739. assert(metadata);
  740. return metadata->hostObject;
  741. }
  742. jsi::Value JSCRuntime::getProperty(
  743. const jsi::Object &obj,
  744. const jsi::String &name) {
  745. JSObjectRef objRef = objectRef(obj);
  746. JSValueRef exc = nullptr;
  747. JSValueRef res = JSObjectGetProperty(ctx_, objRef, stringRef(name), &exc);
  748. checkException(exc);
  749. return createValue(res);
  750. }
  751. jsi::Value JSCRuntime::getProperty(
  752. const jsi::Object &obj,
  753. const jsi::PropNameID &name) {
  754. JSObjectRef objRef = objectRef(obj);
  755. JSValueRef exc = nullptr;
  756. JSValueRef res = JSObjectGetProperty(ctx_, objRef, stringRef(name), &exc);
  757. checkException(exc);
  758. return createValue(res);
  759. }
  760. bool JSCRuntime::hasProperty(const jsi::Object &obj, const jsi::String &name) {
  761. JSObjectRef objRef = objectRef(obj);
  762. return JSObjectHasProperty(ctx_, objRef, stringRef(name));
  763. }
  764. bool JSCRuntime::hasProperty(
  765. const jsi::Object &obj,
  766. const jsi::PropNameID &name) {
  767. JSObjectRef objRef = objectRef(obj);
  768. return JSObjectHasProperty(ctx_, objRef, stringRef(name));
  769. }
  770. void JSCRuntime::setPropertyValue(
  771. jsi::Object &object,
  772. const jsi::PropNameID &name,
  773. const jsi::Value &value) {
  774. JSValueRef exc = nullptr;
  775. JSObjectSetProperty(
  776. ctx_,
  777. objectRef(object),
  778. stringRef(name),
  779. valueRef(value),
  780. kJSPropertyAttributeNone,
  781. &exc);
  782. checkException(exc);
  783. }
  784. void JSCRuntime::setPropertyValue(
  785. jsi::Object &object,
  786. const jsi::String &name,
  787. const jsi::Value &value) {
  788. JSValueRef exc = nullptr;
  789. JSObjectSetProperty(
  790. ctx_,
  791. objectRef(object),
  792. stringRef(name),
  793. valueRef(value),
  794. kJSPropertyAttributeNone,
  795. &exc);
  796. checkException(exc);
  797. }
  798. bool JSCRuntime::isArray(const jsi::Object &obj) const {
  799. #if !defined(_JSC_FAST_IS_ARRAY)
  800. JSObjectRef global = JSContextGetGlobalObject(ctx_);
  801. JSStringRef arrayString = getArrayString();
  802. JSValueRef exc = nullptr;
  803. JSValueRef arrayCtorValue =
  804. JSObjectGetProperty(ctx_, global, arrayString, &exc);
  805. JSC_ASSERT(exc);
  806. JSObjectRef arrayCtor = JSValueToObject(ctx_, arrayCtorValue, &exc);
  807. JSC_ASSERT(exc);
  808. JSStringRef isArrayString = getIsArrayString();
  809. JSValueRef isArrayValue =
  810. JSObjectGetProperty(ctx_, arrayCtor, isArrayString, &exc);
  811. JSC_ASSERT(exc);
  812. JSObjectRef isArray = JSValueToObject(ctx_, isArrayValue, &exc);
  813. JSC_ASSERT(exc);
  814. JSValueRef arg = objectRef(obj);
  815. JSValueRef result =
  816. JSObjectCallAsFunction(ctx_, isArray, nullptr, 1, &arg, &exc);
  817. JSC_ASSERT(exc);
  818. return JSValueToBoolean(ctx_, result);
  819. #else
  820. return JSValueIsArray(ctx_, objectRef(obj));
  821. #endif
  822. }
  823. bool JSCRuntime::isArrayBuffer(const jsi::Object &obj) const {
  824. #if defined(_JSC_NO_ARRAY_BUFFERS)
  825. throw std::runtime_error("Unsupported");
  826. #else
  827. auto typedArrayType = JSValueGetTypedArrayType(ctx_, objectRef(obj), nullptr);
  828. return typedArrayType == kJSTypedArrayTypeArrayBuffer;
  829. #endif
  830. }
  831. uint8_t *JSCRuntime::data(const jsi::ArrayBuffer &obj) {
  832. #if defined(_JSC_NO_ARRAY_BUFFERS)
  833. throw std::runtime_error("Unsupported");
  834. #else
  835. return static_cast<uint8_t *>(
  836. JSObjectGetArrayBufferBytesPtr(ctx_, objectRef(obj), nullptr));
  837. #endif
  838. }
  839. size_t JSCRuntime::size(const jsi::ArrayBuffer &obj) {
  840. #if defined(_JSC_NO_ARRAY_BUFFERS)
  841. throw std::runtime_error("Unsupported");
  842. #else
  843. return JSObjectGetArrayBufferByteLength(ctx_, objectRef(obj), nullptr);
  844. #endif
  845. }
  846. bool JSCRuntime::isFunction(const jsi::Object &obj) const {
  847. return JSObjectIsFunction(ctx_, objectRef(obj));
  848. }
  849. bool JSCRuntime::isHostObject(const jsi::Object &obj) const {
  850. auto cls = hostObjectClass;
  851. return cls != nullptr && JSValueIsObjectOfClass(ctx_, objectRef(obj), cls);
  852. }
  853. // Very expensive
  854. jsi::Array JSCRuntime::getPropertyNames(const jsi::Object &obj) {
  855. JSPropertyNameArrayRef names =
  856. JSObjectCopyPropertyNames(ctx_, objectRef(obj));
  857. size_t len = JSPropertyNameArrayGetCount(names);
  858. // Would be better if we could create an array with explicit elements
  859. auto result = createArray(len);
  860. for (size_t i = 0; i < len; i++) {
  861. JSStringRef str = JSPropertyNameArrayGetNameAtIndex(names, i);
  862. result.setValueAtIndex(*this, i, createString(str));
  863. }
  864. JSPropertyNameArrayRelease(names);
  865. return result;
  866. }
  867. jsi::WeakObject JSCRuntime::createWeakObject(const jsi::Object &obj) {
  868. #ifdef RN_FABRIC_ENABLED
  869. // TODO: revisit this implementation
  870. JSObjectRef objRef = objectRef(obj);
  871. return make<jsi::WeakObject>(makeObjectValue(objRef));
  872. #else
  873. throw std::logic_error("Not implemented");
  874. #endif
  875. }
  876. jsi::Value JSCRuntime::lockWeakObject(const jsi::WeakObject &obj) {
  877. #ifdef RN_FABRIC_ENABLED
  878. // TODO: revisit this implementation
  879. JSObjectRef objRef = objectRef(obj);
  880. return jsi::Value(createObject(objRef));
  881. #else
  882. throw std::logic_error("Not implemented");
  883. #endif
  884. }
  885. jsi::Array JSCRuntime::createArray(size_t length) {
  886. JSValueRef exc = nullptr;
  887. JSObjectRef obj = JSObjectMakeArray(ctx_, 0, nullptr, &exc);
  888. checkException(obj, exc);
  889. JSObjectSetProperty(
  890. ctx_,
  891. obj,
  892. getLengthString(),
  893. JSValueMakeNumber(ctx_, static_cast<double>(length)),
  894. 0,
  895. &exc);
  896. checkException(exc);
  897. return createObject(obj).getArray(*this);
  898. }
  899. size_t JSCRuntime::size(const jsi::Array &arr) {
  900. return static_cast<size_t>(
  901. getProperty(arr, createPropNameID(getLengthString())).getNumber());
  902. }
  903. jsi::Value JSCRuntime::getValueAtIndex(const jsi::Array &arr, size_t i) {
  904. JSValueRef exc = nullptr;
  905. auto res = JSObjectGetPropertyAtIndex(ctx_, objectRef(arr), (int)i, &exc);
  906. checkException(exc);
  907. return createValue(res);
  908. }
  909. void JSCRuntime::setValueAtIndexImpl(
  910. jsi::Array &arr,
  911. size_t i,
  912. const jsi::Value &value) {
  913. JSValueRef exc = nullptr;
  914. JSObjectSetPropertyAtIndex(
  915. ctx_, objectRef(arr), (int)i, valueRef(value), &exc);
  916. checkException(exc);
  917. }
  918. namespace {
  919. std::once_flag hostFunctionClassOnceFlag;
  920. JSClassRef hostFunctionClass{};
  921. class HostFunctionProxy {
  922. public:
  923. HostFunctionProxy(jsi::HostFunctionType hostFunction)
  924. : hostFunction_(hostFunction) {}
  925. jsi::HostFunctionType &getHostFunction() {
  926. return hostFunction_;
  927. }
  928. protected:
  929. jsi::HostFunctionType hostFunction_;
  930. };
  931. } // namespace
  932. jsi::Function JSCRuntime::createFunctionFromHostFunction(
  933. const jsi::PropNameID &name,
  934. unsigned int paramCount,
  935. jsi::HostFunctionType func) {
  936. class HostFunctionMetadata : public HostFunctionProxy {
  937. public:
  938. static void initialize(JSContextRef ctx, JSObjectRef object) {
  939. // We need to set up the prototype chain properly here. In theory we
  940. // could set func.prototype.prototype = Function.prototype to get the
  941. // same result. Not sure which approach is better.
  942. HostFunctionMetadata *metadata =
  943. static_cast<HostFunctionMetadata *>(JSObjectGetPrivate(object));
  944. JSValueRef exc = nullptr;
  945. JSObjectSetProperty(
  946. ctx,
  947. object,
  948. getLengthString(),
  949. JSValueMakeNumber(ctx, metadata->argCount),
  950. kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum |
  951. kJSPropertyAttributeDontDelete,
  952. &exc);
  953. if (exc) {
  954. // Silently fail to set length
  955. exc = nullptr;
  956. }
  957. JSStringRef name = nullptr;
  958. std::swap(metadata->name, name);
  959. JSObjectSetProperty(
  960. ctx,
  961. object,
  962. getNameString(),
  963. JSValueMakeString(ctx, name),
  964. kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum |
  965. kJSPropertyAttributeDontDelete,
  966. &exc);
  967. JSStringRelease(name);
  968. if (exc) {
  969. // Silently fail to set name
  970. exc = nullptr;
  971. }
  972. JSObjectRef global = JSContextGetGlobalObject(ctx);
  973. JSValueRef value =
  974. JSObjectGetProperty(ctx, global, getFunctionString(), &exc);
  975. // If we don't have Function then something bad is going on.
  976. if (JSC_UNLIKELY(exc)) {
  977. abort();
  978. }
  979. JSObjectRef funcCtor = JSValueToObject(ctx, value, &exc);
  980. if (!funcCtor) {
  981. // We can't do anything if Function is not an object
  982. return;
  983. }
  984. JSValueRef funcProto = JSObjectGetPrototype(ctx, funcCtor);
  985. JSObjectSetPrototype(ctx, object, funcProto);
  986. }
  987. static JSValueRef makeError(JSCRuntime &rt, const std::string &desc) {
  988. jsi::Value value =
  989. rt.global().getPropertyAsFunction(rt, "Error").call(rt, desc);
  990. return rt.valueRef(value);
  991. }
  992. static JSValueRef call(
  993. JSContextRef ctx,
  994. JSObjectRef function,
  995. JSObjectRef thisObject,
  996. size_t argumentCount,
  997. const JSValueRef arguments[],
  998. JSValueRef *exception) {
  999. HostFunctionMetadata *metadata =
  1000. static_cast<HostFunctionMetadata *>(JSObjectGetPrivate(function));
  1001. JSCRuntime &rt = *(metadata->runtime);
  1002. const unsigned maxStackArgCount = 8;
  1003. jsi::Value stackArgs[maxStackArgCount];
  1004. std::unique_ptr<jsi::Value[]> heapArgs;
  1005. jsi::Value *args;
  1006. if (argumentCount > maxStackArgCount) {
  1007. heapArgs = std::make_unique<jsi::Value[]>(argumentCount);
  1008. for (size_t i = 0; i < argumentCount; i++) {
  1009. heapArgs[i] = rt.createValue(arguments[i]);
  1010. }
  1011. args = heapArgs.get();
  1012. } else {
  1013. for (size_t i = 0; i < argumentCount; i++) {
  1014. stackArgs[i] = rt.createValue(arguments[i]);
  1015. }
  1016. args = stackArgs;
  1017. }
  1018. JSValueRef res;
  1019. jsi::Value thisVal(rt.createObject(thisObject));
  1020. try {
  1021. res = rt.valueRef(
  1022. metadata->hostFunction_(rt, thisVal, args, argumentCount));
  1023. } catch (const jsi::JSError &error) {
  1024. *exception = rt.valueRef(error.value());
  1025. res = JSValueMakeUndefined(ctx);
  1026. } catch (const std::exception &ex) {
  1027. std::string exceptionString("Exception in HostFunction: ");
  1028. exceptionString += ex.what();
  1029. *exception = makeError(rt, exceptionString);
  1030. res = JSValueMakeUndefined(ctx);
  1031. } catch (...) {
  1032. std::string exceptionString("Exception in HostFunction: <unknown>");
  1033. *exception = makeError(rt, exceptionString);
  1034. res = JSValueMakeUndefined(ctx);
  1035. }
  1036. return res;
  1037. }
  1038. static void finalize(JSObjectRef object) {
  1039. HostFunctionMetadata *metadata =
  1040. static_cast<HostFunctionMetadata *>(JSObjectGetPrivate(object));
  1041. JSObjectSetPrivate(object, nullptr);
  1042. delete metadata;
  1043. }
  1044. HostFunctionMetadata(
  1045. JSCRuntime *rt,
  1046. jsi::HostFunctionType hf,
  1047. unsigned ac,
  1048. JSStringRef n)
  1049. : HostFunctionProxy(hf),
  1050. runtime(rt),
  1051. argCount(ac),
  1052. name(JSStringRetain(n)) {}
  1053. JSCRuntime *runtime;
  1054. unsigned argCount;
  1055. JSStringRef name;
  1056. };
  1057. std::call_once(hostFunctionClassOnceFlag, []() {
  1058. JSClassDefinition functionClass = kJSClassDefinitionEmpty;
  1059. functionClass.version = 0;
  1060. functionClass.attributes = kJSClassAttributeNoAutomaticPrototype;
  1061. functionClass.initialize = HostFunctionMetadata::initialize;
  1062. functionClass.finalize = HostFunctionMetadata::finalize;
  1063. functionClass.callAsFunction = HostFunctionMetadata::call;
  1064. hostFunctionClass = JSClassCreate(&functionClass);
  1065. });
  1066. JSObjectRef funcRef = JSObjectMake(
  1067. ctx_,
  1068. hostFunctionClass,
  1069. new HostFunctionMetadata(this, func, paramCount, stringRef(name)));
  1070. return createObject(funcRef).getFunction(*this);
  1071. }
  1072. namespace detail {
  1073. class ArgsConverter {
  1074. public:
  1075. ArgsConverter(JSCRuntime &rt, const jsi::Value *args, size_t count) {
  1076. JSValueRef *destination = inline_;
  1077. if (count > maxStackArgs) {
  1078. outOfLine_ = std::make_unique<JSValueRef[]>(count);
  1079. destination = outOfLine_.get();
  1080. }
  1081. for (size_t i = 0; i < count; ++i) {
  1082. destination[i] = rt.valueRef(args[i]);
  1083. }
  1084. }
  1085. operator JSValueRef *() {
  1086. return outOfLine_ ? outOfLine_.get() : inline_;
  1087. }
  1088. private:
  1089. constexpr static unsigned maxStackArgs = 8;
  1090. JSValueRef inline_[maxStackArgs];
  1091. std::unique_ptr<JSValueRef[]> outOfLine_;
  1092. };
  1093. } // namespace detail
  1094. bool JSCRuntime::isHostFunction(const jsi::Function &obj) const {
  1095. auto cls = hostFunctionClass;
  1096. return cls != nullptr && JSValueIsObjectOfClass(ctx_, objectRef(obj), cls);
  1097. }
  1098. jsi::HostFunctionType &JSCRuntime::getHostFunction(const jsi::Function &obj) {
  1099. // We know that isHostFunction(obj) is true here, so its safe to proceed
  1100. auto proxy =
  1101. static_cast<HostFunctionProxy *>(JSObjectGetPrivate(objectRef(obj)));
  1102. return proxy->getHostFunction();
  1103. }
  1104. jsi::Value JSCRuntime::call(
  1105. const jsi::Function &f,
  1106. const jsi::Value &jsThis,
  1107. const jsi::Value *args,
  1108. size_t count) {
  1109. JSValueRef exc = nullptr;
  1110. auto res = JSObjectCallAsFunction(
  1111. ctx_,
  1112. objectRef(f),
  1113. jsThis.isUndefined() ? nullptr : objectRef(jsThis.getObject(*this)),
  1114. count,
  1115. detail::ArgsConverter(*this, args, count),
  1116. &exc);
  1117. checkException(exc);
  1118. return createValue(res);
  1119. }
  1120. jsi::Value JSCRuntime::callAsConstructor(
  1121. const jsi::Function &f,
  1122. const jsi::Value *args,
  1123. size_t count) {
  1124. JSValueRef exc = nullptr;
  1125. auto res = JSObjectCallAsConstructor(
  1126. ctx_,
  1127. objectRef(f),
  1128. count,
  1129. detail::ArgsConverter(*this, args, count),
  1130. &exc);
  1131. checkException(exc);
  1132. return createValue(res);
  1133. }
  1134. bool JSCRuntime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b)
  1135. const {
  1136. JSValueRef exc = nullptr;
  1137. bool ret = JSValueIsEqual(ctx_, symbolRef(a), symbolRef(b), &exc);
  1138. const_cast<JSCRuntime *>(this)->checkException(exc);
  1139. return ret;
  1140. }
  1141. bool JSCRuntime::strictEquals(const jsi::String &a, const jsi::String &b)
  1142. const {
  1143. return JSStringIsEqual(stringRef(a), stringRef(b));
  1144. }
  1145. bool JSCRuntime::strictEquals(const jsi::Object &a, const jsi::Object &b)
  1146. const {
  1147. return objectRef(a) == objectRef(b);
  1148. }
  1149. bool JSCRuntime::instanceOf(const jsi::Object &o, const jsi::Function &f) {
  1150. JSValueRef exc = nullptr;
  1151. bool res =
  1152. JSValueIsInstanceOfConstructor(ctx_, objectRef(o), objectRef(f), &exc);
  1153. checkException(exc);
  1154. return res;
  1155. }
  1156. jsi::Runtime::PointerValue *JSCRuntime::makeSymbolValue(
  1157. JSValueRef symbolRef) const {
  1158. #ifndef NDEBUG
  1159. return new JSCSymbolValue(ctx_, ctxInvalid_, symbolRef, symbolCounter_);
  1160. #else
  1161. return new JSCSymbolValue(ctx_, ctxInvalid_, symbolRef);
  1162. #endif
  1163. }
  1164. namespace {
  1165. JSStringRef getEmptyString() {
  1166. static JSStringRef empty = JSStringCreateWithUTF8CString("");
  1167. return empty;
  1168. }
  1169. } // namespace
  1170. jsi::Runtime::PointerValue *JSCRuntime::makeStringValue(
  1171. JSStringRef stringRef) const {
  1172. if (!stringRef) {
  1173. stringRef = getEmptyString();
  1174. }
  1175. #ifndef NDEBUG
  1176. return new JSCStringValue(stringRef, stringCounter_);
  1177. #else
  1178. return new JSCStringValue(stringRef);
  1179. #endif
  1180. }
  1181. jsi::Symbol JSCRuntime::createSymbol(JSValueRef sym) const {
  1182. return make<jsi::Symbol>(makeSymbolValue(sym));
  1183. }
  1184. jsi::String JSCRuntime::createString(JSStringRef str) const {
  1185. return make<jsi::String>(makeStringValue(str));
  1186. }
  1187. jsi::PropNameID JSCRuntime::createPropNameID(JSStringRef str) {
  1188. return make<jsi::PropNameID>(makeStringValue(str));
  1189. }
  1190. jsi::Runtime::PointerValue *JSCRuntime::makeObjectValue(
  1191. JSObjectRef objectRef) const {
  1192. if (!objectRef) {
  1193. objectRef = JSObjectMake(ctx_, nullptr, nullptr);
  1194. }
  1195. #ifndef NDEBUG
  1196. return new JSCObjectValue(ctx_, ctxInvalid_, objectRef, objectCounter_);
  1197. #else
  1198. return new JSCObjectValue(ctx_, ctxInvalid_, objectRef);
  1199. #endif
  1200. }
  1201. jsi::Object JSCRuntime::createObject(JSObjectRef obj) const {
  1202. return make<jsi::Object>(makeObjectValue(obj));
  1203. }
  1204. jsi::Value JSCRuntime::createValue(JSValueRef value) const {
  1205. JSType type = JSValueGetType(ctx_, value);
  1206. switch (type) {
  1207. case kJSTypeNumber:
  1208. return jsi::Value(JSValueToNumber(ctx_, value, nullptr));
  1209. case kJSTypeBoolean:
  1210. return jsi::Value(JSValueToBoolean(ctx_, value));
  1211. case kJSTypeNull:
  1212. return jsi::Value(nullptr);
  1213. case kJSTypeUndefined:
  1214. return jsi::Value();
  1215. case kJSTypeString: {
  1216. JSStringRef str = JSValueToStringCopy(ctx_, value, nullptr);
  1217. auto result = jsi::Value(createString(str));
  1218. JSStringRelease(str);
  1219. return result;
  1220. }
  1221. case kJSTypeObject: {
  1222. JSObjectRef objRef = JSValueToObject(ctx_, value, nullptr);
  1223. return jsi::Value(createObject(objRef));
  1224. }
  1225. // TODO: Uncomment this when all supported JSC versions have this symbol
  1226. // case kJSTypeSymbol:
  1227. default: {
  1228. if (smellsLikeES6Symbol(ctx_, value)) {
  1229. return jsi::Value(createSymbol(value));
  1230. } else {
  1231. // WHAT ARE YOU
  1232. abort();
  1233. }
  1234. }
  1235. }
  1236. }
  1237. JSValueRef JSCRuntime::valueRef(const jsi::Value &value) {
  1238. // I would rather switch on value.kind_
  1239. if (value.isUndefined()) {
  1240. return JSValueMakeUndefined(ctx_);
  1241. } else if (value.isNull()) {
  1242. return JSValueMakeNull(ctx_);
  1243. } else if (value.isBool()) {
  1244. return JSValueMakeBoolean(ctx_, value.getBool());
  1245. } else if (value.isNumber()) {
  1246. return JSValueMakeNumber(ctx_, value.getNumber());
  1247. } else if (value.isSymbol()) {
  1248. return symbolRef(value.getSymbol(*this));
  1249. } else if (value.isString()) {
  1250. return JSValueMakeString(ctx_, stringRef(value.getString(*this)));
  1251. } else if (value.isObject()) {
  1252. return objectRef(value.getObject(*this));
  1253. } else {
  1254. // What are you?
  1255. abort();
  1256. }
  1257. }
  1258. JSValueRef JSCRuntime::symbolRef(const jsi::Symbol &sym) {
  1259. return static_cast<const JSCSymbolValue *>(getPointerValue(sym))->sym_;
  1260. }
  1261. JSStringRef JSCRuntime::stringRef(const jsi::String &str) {
  1262. return static_cast<const JSCStringValue *>(getPointerValue(str))->str_;
  1263. }
  1264. JSStringRef JSCRuntime::stringRef(const jsi::PropNameID &sym) {
  1265. return static_cast<const JSCStringValue *>(getPointerValue(sym))->str_;
  1266. }
  1267. JSObjectRef JSCRuntime::objectRef(const jsi::Object &obj) {
  1268. return static_cast<const JSCObjectValue *>(getPointerValue(obj))->obj_;
  1269. }
  1270. #ifdef RN_FABRIC_ENABLED
  1271. JSObjectRef JSCRuntime::objectRef(const jsi::WeakObject &obj) {
  1272. // TODO: revisit this implementation
  1273. return static_cast<const JSCObjectValue *>(getPointerValue(obj))->obj_;
  1274. }
  1275. #endif
  1276. void JSCRuntime::checkException(JSValueRef exc) {
  1277. if (JSC_UNLIKELY(exc)) {
  1278. throw jsi::JSError(*this, createValue(exc));
  1279. }
  1280. }
  1281. void JSCRuntime::checkException(JSValueRef res, JSValueRef exc) {
  1282. if (JSC_UNLIKELY(!res)) {
  1283. throw jsi::JSError(*this, createValue(exc));
  1284. }
  1285. }
  1286. void JSCRuntime::checkException(JSValueRef exc, const char *msg) {
  1287. if (JSC_UNLIKELY(exc)) {
  1288. throw jsi::JSError(std::string(msg), *this, createValue(exc));
  1289. }
  1290. }
  1291. void JSCRuntime::checkException(
  1292. JSValueRef res,
  1293. JSValueRef exc,
  1294. const char *msg) {
  1295. if (JSC_UNLIKELY(!res)) {
  1296. throw jsi::JSError(std::string(msg), *this, createValue(exc));
  1297. }
  1298. }
  1299. std::unique_ptr<jsi::Runtime> makeJSCRuntime() {
  1300. return std::make_unique<JSCRuntime>();
  1301. }
  1302. } // namespace jsc
  1303. } // namespace facebook