react-native-windows 0.78.5 → 0.78.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/Directory.Build.props +6 -4
  2. package/Folly/Folly.vcxproj +46 -6
  3. package/Folly/Folly.vcxproj.filters +16 -4
  4. package/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h +26 -18
  5. package/Folly/TEMP_UntilFollyUpdate/Conv.cpp +1205 -0
  6. package/Folly/TEMP_UntilFollyUpdate/chrono/Hardware.h +155 -0
  7. package/Folly/TEMP_UntilFollyUpdate/concurrency/CacheLocality.cpp +633 -0
  8. package/Folly/TEMP_UntilFollyUpdate/{dynamic-inl.h → json/dynamic-inl.h} +3 -4
  9. package/Folly/TEMP_UntilFollyUpdate/{json.cpp → json/json.cpp} +14 -10
  10. package/Folly/TEMP_UntilFollyUpdate/lang/SafeAssert.h +7 -14
  11. package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h +6 -6
  12. package/Folly/ThreadNameStub.cpp +10 -0
  13. package/Folly/cgmanifest.json +11 -1
  14. package/Libraries/Components/View/View.windows.js +107 -56
  15. package/Libraries/Components/View/ViewAccessibility.d.ts +60 -1
  16. package/Libraries/Image/Image.windows.js +42 -21
  17. package/Libraries/Modal/Modal.d.ts +7 -0
  18. package/Libraries/Modal/Modal.windows.js +7 -1
  19. package/Libraries/NativeComponent/BaseViewConfig.windows.js +3 -0
  20. package/Libraries/Text/Text.d.ts +18 -0
  21. package/Microsoft.ReactNative/AsynchronousEventBeat.cpp +4 -25
  22. package/Microsoft.ReactNative/AsynchronousEventBeat.h +0 -3
  23. package/Microsoft.ReactNative/Base/FollyIncludes.h +1 -0
  24. package/Microsoft.ReactNative/CallInvoker.cpp +42 -0
  25. package/Microsoft.ReactNative/CallInvoker.h +34 -0
  26. package/Microsoft.ReactNative/{JSDispatcherWriter.cpp → CallInvokerWriter.cpp} +35 -47
  27. package/Microsoft.ReactNative/CallInvokerWriter.h +74 -0
  28. package/Microsoft.ReactNative/CompositionComponentView.idl +0 -5
  29. package/Microsoft.ReactNative/CompositionSwitcher.idl +7 -0
  30. package/Microsoft.ReactNative/Fabric/AbiViewProps.cpp +8 -10
  31. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +4 -1
  32. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp +12 -2
  33. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h +2 -0
  34. package/Microsoft.ReactNative/Fabric/Composition/CompositionAnnotationProvider.cpp +100 -0
  35. package/Microsoft.ReactNative/Fabric/Composition/CompositionAnnotationProvider.h +31 -0
  36. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +77 -11
  37. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +43 -1
  38. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +7 -0
  39. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +86 -56
  40. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +5 -1
  41. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +0 -4
  42. package/Microsoft.ReactNative/Fabric/Composition/CompositionUIService.cpp +0 -2
  43. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +118 -63
  44. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
  45. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +133 -8
  46. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +16 -2
  47. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +4 -2
  48. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +9 -1
  49. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +34 -11
  50. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +3 -0
  51. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +133 -135
  52. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +9 -6
  53. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +46 -49
  54. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +6 -1
  55. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +13 -8
  56. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +5 -2
  57. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +146 -25
  58. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +14 -0
  59. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +160 -12
  60. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +6 -0
  61. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp +47 -0
  62. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h +15 -1
  63. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.cpp +6 -2
  64. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +4 -1
  65. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +7 -9
  66. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +4 -1
  67. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +5 -0
  68. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +40 -36
  69. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +68 -0
  70. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +11 -0
  71. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +70 -13
  72. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +10 -2
  73. package/Microsoft.ReactNative/Fabric/ImageManager.cpp +5 -5
  74. package/Microsoft.ReactNative/Fabric/ImageRequestParams.cpp +26 -0
  75. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +47 -8
  76. package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +10 -1
  77. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/CompositionAccessibilityProps.h +67 -0
  78. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +22 -4
  79. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.h +15 -2
  80. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +20 -0
  81. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +5 -0
  82. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/MouseEvent.h +20 -0
  83. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/HostPlatformColor.h +5 -8
  84. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorParser.h +1 -2
  85. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +247 -45
  86. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +15 -0
  87. package/Microsoft.ReactNative/Fabric/platform/react/threading/MessageQueueThreadImpl.cpp +39 -0
  88. package/Microsoft.ReactNative/Fabric/platform/react/threading/MessageQueueThreadImpl.h +54 -0
  89. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.cpp +126 -0
  90. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.h +73 -0
  91. package/Microsoft.ReactNative/IReactContext.cpp +17 -0
  92. package/Microsoft.ReactNative/IReactContext.h +1 -0
  93. package/Microsoft.ReactNative/IReactContext.idl +18 -1
  94. package/Microsoft.ReactNative/IReactDispatcher.idl +1 -0
  95. package/Microsoft.ReactNative/IReactModuleBuilder.cpp +12 -0
  96. package/Microsoft.ReactNative/IReactModuleBuilder.h +2 -0
  97. package/Microsoft.ReactNative/IReactModuleBuilder.idl +8 -0
  98. package/Microsoft.ReactNative/JsiApi.cpp +10 -2
  99. package/Microsoft.ReactNative/JsiApi.h +1 -0
  100. package/Microsoft.ReactNative/JsiApi.idl +1 -0
  101. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +0 -3
  102. package/Microsoft.ReactNative/Modules/AccessibilityInfoModule.cpp +2 -3
  103. package/Microsoft.ReactNative/Modules/AlertModule.cpp +7 -12
  104. package/Microsoft.ReactNative/Modules/Animated/AnimationDriver.cpp +2 -1
  105. package/Microsoft.ReactNative/Modules/Animated/NativeAnimatedModule.cpp +4 -8
  106. package/Microsoft.ReactNative/Modules/AppStateModule.cpp +2 -2
  107. package/Microsoft.ReactNative/Modules/ClipboardModule.cpp +6 -8
  108. package/Microsoft.ReactNative/Modules/ClipboardModule.h +1 -1
  109. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +6 -15
  110. package/Microsoft.ReactNative/Modules/NativeUIManager.cpp +13 -24
  111. package/Microsoft.ReactNative/QuirkSettings.cpp +0 -16
  112. package/Microsoft.ReactNative/QuirkSettings.h +0 -3
  113. package/Microsoft.ReactNative/ReactHost/ReactHost.cpp +11 -1
  114. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +78 -68
  115. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -2
  116. package/Microsoft.ReactNative/ReactInstanceSettings.cpp +12 -0
  117. package/Microsoft.ReactNative/ReactInstanceSettings.h +2 -0
  118. package/Microsoft.ReactNative/ReactInstanceSettings.idl +6 -0
  119. package/Microsoft.ReactNative/ReactNativeIsland.idl +3 -0
  120. package/Microsoft.ReactNative/ReactSupport.cpp +44 -11
  121. package/Microsoft.ReactNative/RedBox.cpp +30 -1
  122. package/Microsoft.ReactNative/SchedulerSettings.cpp +4 -4
  123. package/Microsoft.ReactNative/SchedulerSettings.h +1 -1
  124. package/Microsoft.ReactNative/TurboModulesProvider.cpp +30 -12
  125. package/Microsoft.ReactNative/Utils/ImageUtils.h +1 -0
  126. package/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +37 -31
  127. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.cpp +1 -0
  128. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.inc +2 -0
  129. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_posix.cpp +1 -1
  130. package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp +94 -27
  131. package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h +27 -6
  132. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.cpp +45 -11
  133. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.h +6 -0
  134. package/Microsoft.ReactNative.Cxx/JSI/decorator.h +220 -0
  135. package/Microsoft.ReactNative.Cxx/JSI/instrumentation.h +28 -0
  136. package/Microsoft.ReactNative.Cxx/JSI/jsi-inl.h +6 -0
  137. package/Microsoft.ReactNative.Cxx/JSI/jsi.cpp +241 -4
  138. package/Microsoft.ReactNative.Cxx/JSI/jsi.h +207 -19
  139. package/Microsoft.ReactNative.Cxx/JSValue.cpp +19 -3
  140. package/Microsoft.ReactNative.Cxx/JSValue.h +15 -7
  141. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +2 -2
  142. package/Microsoft.ReactNative.Cxx/NativeModules.h +60 -2
  143. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.cpp +1267 -614
  144. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.h +4 -2
  145. package/Microsoft.ReactNative.Cxx/ReactContext.h +7 -0
  146. package/Microsoft.ReactNative.Cxx/TurboModuleProvider.cpp +11 -13
  147. package/Microsoft.ReactNative.Cxx/TurboModuleProvider.h +2 -3
  148. package/Microsoft.ReactNative.Cxx/node-api/js_native_api.h +81 -20
  149. package/Microsoft.ReactNative.Cxx/node-api/js_native_api_types.h +47 -2
  150. package/Microsoft.ReactNative.Cxx/node-api/js_runtime_api.h +13 -0
  151. package/Microsoft.ReactNative.Cxx/stubs/glog/logging.h +1 -1
  152. package/Microsoft.ReactNative.Managed/ReactContext.cs +3 -1
  153. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  154. package/PropertySheets/JSEngine.props +1 -1
  155. package/PropertySheets/React.Cpp.props +2 -1
  156. package/PropertySheets/WebView2.props +1 -1
  157. package/PropertySheets/WinUI.props +2 -2
  158. package/ReactCommon/TEMP_UntilReactCommonUpdate/jserrorhandler/JsErrorHandler.cpp +429 -0
  159. package/ReactCommon/cgmanifest.json +1 -1
  160. package/Shared/HermesRuntimeHolder.cpp +6 -0
  161. package/Shared/JSI/ChakraRuntime.cpp +4 -0
  162. package/Shared/JSI/ChakraRuntime.h +2 -0
  163. package/Shared/Modules/BlobModule.cpp +14 -16
  164. package/Shared/Modules/BlobModule.h +3 -1
  165. package/Shared/Shared.vcxitems +11 -7
  166. package/Shared/Shared.vcxitems.filters +6 -1
  167. package/Shared/TurboModuleManager.cpp +0 -15
  168. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +6 -6
  169. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +6 -6
  170. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +6 -6
  171. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +6 -6
  172. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +6 -6
  173. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +6 -6
  174. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +6 -6
  175. package/codegen/react/components/rnwcore/InputAccessory.g.h +6 -6
  176. package/codegen/react/components/rnwcore/ModalHostView.g.h +11 -7
  177. package/codegen/react/components/rnwcore/Props.cpp +2 -1
  178. package/codegen/react/components/rnwcore/Props.h +1 -0
  179. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +6 -6
  180. package/codegen/react/components/rnwcore/SafeAreaView.g.h +6 -6
  181. package/codegen/react/components/rnwcore/Switch.g.h +6 -6
  182. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +6 -6
  183. package/index.windows.js +4 -2
  184. package/package.json +3 -4
  185. package/src/private/specs/components/RCTModalHostViewNativeComponent.js +8 -0
  186. package/stubs/glog/logging.h +1 -1
  187. package/Microsoft.ReactNative/JSDispatcherWriter.h +0 -47
  188. package/Microsoft.ReactNative/SynchronousEventBeat.cpp +0 -51
  189. package/Microsoft.ReactNative/SynchronousEventBeat.h +0 -31
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include <algorithm>
9
9
  #include <array>
10
+ #include <mutex>
10
11
  #include <optional>
11
12
  #include <sstream>
12
13
  #include <string_view>
@@ -60,7 +61,7 @@ using namespace std::string_view_literals;
60
61
  } \
61
62
  } while (false)
62
63
 
63
- // Check NAPI result and and throw JS exception if it is not napi_ok.
64
+ // Check Node-API result and and throw JS exception if it is not napi_ok.
64
65
  #define CHECK_NAPI(...) \
65
66
  do { \
66
67
  napi_status temp_error_code_ = (__VA_ARGS__); \
@@ -69,7 +70,7 @@ using namespace std::string_view_literals;
69
70
  } \
70
71
  } while (false)
71
72
 
72
- // Check NAPI result and and crash if it is not napi_ok.
73
+ // Check Node-API result and and crash if it is not napi_ok.
73
74
  #define CHECK_NAPI_ELSE_CRASH(expression) \
74
75
  do { \
75
76
  napi_status temp_error_code_ = (expression); \
@@ -78,7 +79,7 @@ using namespace std::string_view_literals;
78
79
  } \
79
80
  } while (false)
80
81
 
81
- // Check NAPI result and return it when it is an error.
82
+ // Check Node-API result and return it when it is an error.
82
83
  #define NAPI_CALL(expression) \
83
84
  do { \
84
85
  napi_status temp_error_code_ = (expression); \
@@ -176,18 +177,29 @@ class StringKey {
176
177
  size_t hash_;
177
178
  };
178
179
 
180
+ struct NodeApiAttachTag {
181
+ } attachTag;
182
+
179
183
  // Implementation of N-API JSI Runtime
180
184
  class NodeApiJsiRuntime : public jsi::Runtime {
181
185
  public:
182
- NodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()> onDelete) noexcept;
186
+ NodeApiJsiRuntime(
187
+ napi_env env,
188
+ JSRuntimeApi *jsrApi,
189
+ std::function<void()> onDelete) noexcept;
183
190
  ~NodeApiJsiRuntime() override;
184
191
 
185
- jsi::Value evaluateJavaScript(const std::shared_ptr<const jsi::Buffer> &buffer, const std::string &sourceURL)
186
- override;
192
+ jsi::Value evaluateJavaScript(
193
+ const std::shared_ptr<const jsi::Buffer> &buffer,
194
+ const std::string &sourceURL) override;
187
195
  std::shared_ptr<const jsi::PreparedJavaScript> prepareJavaScript(
188
196
  const std::shared_ptr<const jsi::Buffer> &buffer,
189
197
  std::string sourceURL) override;
190
- jsi::Value evaluatePreparedJavaScript(const std::shared_ptr<const jsi::PreparedJavaScript> &js) override;
198
+ jsi::Value evaluatePreparedJavaScript(
199
+ const std::shared_ptr<const jsi::PreparedJavaScript> &js) override;
200
+ #if JSI_VERSION >= 12
201
+ void queueMicrotask(const jsi::Function &callback) override;
202
+ #endif
191
203
  #if JSI_VERSION >= 4
192
204
  bool drainMicrotasks(int maxMicrotasksHint = -1) override;
193
205
  #endif
@@ -204,8 +216,10 @@ class NodeApiJsiRuntime : public jsi::Runtime {
204
216
  PointerValue *cloneObject(const PointerValue *pointerValue) override;
205
217
  PointerValue *clonePropNameID(const PointerValue *pointerValue) override;
206
218
 
207
- jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) override;
208
- jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) override;
219
+ jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length)
220
+ override;
221
+ jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length)
222
+ override;
209
223
  jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override;
210
224
  #if JSI_VERSION >= 5
211
225
  jsi::PropNameID createPropNameIDFromSymbol(const jsi::Symbol &sym) override;
@@ -235,16 +249,28 @@ class NodeApiJsiRuntime : public jsi::Runtime {
235
249
 
236
250
  #if JSI_VERSION >= 7
237
251
  bool hasNativeState(const jsi::Object &value) override;
238
- std::shared_ptr<jsi::NativeState> getNativeState(const jsi::Object &value) override;
239
- void setNativeState(const jsi::Object &value, std::shared_ptr<jsi::NativeState> state) override;
252
+ std::shared_ptr<jsi::NativeState> getNativeState(
253
+ const jsi::Object &value) override;
254
+ void setNativeState(
255
+ const jsi::Object &value,
256
+ std::shared_ptr<jsi::NativeState> state) override;
240
257
  #endif
241
258
 
242
- jsi::Value getProperty(const jsi::Object &obj, const jsi::PropNameID &name) override;
243
- jsi::Value getProperty(const jsi::Object &obj, const jsi::String &name) override;
244
- bool hasProperty(const jsi::Object &obj, const jsi::PropNameID &name) override;
259
+ jsi::Value getProperty(const jsi::Object &obj, const jsi::PropNameID &name)
260
+ override;
261
+ jsi::Value getProperty(const jsi::Object &obj, const jsi::String &name)
262
+ override;
263
+ bool hasProperty(const jsi::Object &obj, const jsi::PropNameID &name)
264
+ override;
245
265
  bool hasProperty(const jsi::Object &obj, const jsi::String &name) override;
246
- void setPropertyValue(JSI_CONST_10 jsi::Object &obj, const jsi::PropNameID &name, const jsi::Value &value) override;
247
- void setPropertyValue(JSI_CONST_10 jsi::Object &obj, const jsi::String &name, const jsi::Value &value) override;
266
+ void setPropertyValue(
267
+ JSI_CONST_10 jsi::Object &obj,
268
+ const jsi::PropNameID &name,
269
+ const jsi::Value &value) override;
270
+ void setPropertyValue(
271
+ JSI_CONST_10 jsi::Object &obj,
272
+ const jsi::String &name,
273
+ const jsi::Value &value) override;
248
274
 
249
275
  bool isArray(const jsi::Object &obj) const override;
250
276
  bool isArrayBuffer(const jsi::Object &obj) const override;
@@ -254,24 +280,36 @@ class NodeApiJsiRuntime : public jsi::Runtime {
254
280
  jsi::Array getPropertyNames(const jsi::Object &obj) override;
255
281
 
256
282
  jsi::WeakObject createWeakObject(const jsi::Object &obj) override;
257
- jsi::Value lockWeakObject(JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObj) override;
283
+ jsi::Value lockWeakObject(
284
+ JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObj) override;
258
285
 
259
286
  jsi::Array createArray(size_t length) override;
260
287
  #if JSI_VERSION >= 9
261
- jsi::ArrayBuffer createArrayBuffer(std::shared_ptr<jsi::MutableBuffer> buffer);
288
+ jsi::ArrayBuffer createArrayBuffer(
289
+ std::shared_ptr<jsi::MutableBuffer> buffer);
262
290
  #endif
263
291
  size_t size(const jsi::Array &arr) override;
264
292
  size_t size(const jsi::ArrayBuffer &arrBuf) override;
265
293
  uint8_t *data(const jsi::ArrayBuffer &arrBuff) override;
266
294
  jsi::Value getValueAtIndex(const jsi::Array &arr, size_t index) override;
267
- void setValueAtIndexImpl(JSI_CONST_10 jsi::Array &arr, size_t index, const jsi::Value &value) override;
295
+ void setValueAtIndexImpl(
296
+ JSI_CONST_10 jsi::Array &arr,
297
+ size_t index,
298
+ const jsi::Value &value) override;
268
299
 
269
300
  jsi::Function createFunctionFromHostFunction(
270
301
  const jsi::PropNameID &name,
271
302
  unsigned int paramCount,
272
303
  jsi::HostFunctionType func) override;
273
- jsi::Value call(const jsi::Function &func, const jsi::Value &jsThis, const jsi::Value *args, size_t count) override;
274
- jsi::Value callAsConstructor(const jsi::Function &func, const jsi::Value *args, size_t count) override;
304
+ jsi::Value call(
305
+ const jsi::Function &func,
306
+ const jsi::Value &jsThis,
307
+ const jsi::Value *args,
308
+ size_t count) override;
309
+ jsi::Value callAsConstructor(
310
+ const jsi::Function &func,
311
+ const jsi::Value *args,
312
+ size_t count) override;
275
313
 
276
314
  ScopeState *pushScope() override;
277
315
  void popScope(ScopeState *) override;
@@ -286,7 +324,8 @@ class NodeApiJsiRuntime : public jsi::Runtime {
286
324
  bool instanceOf(const jsi::Object &obj, const jsi::Function &func) override;
287
325
 
288
326
  #if JSI_VERSION >= 11
289
- void setExternalMemoryPressure(const jsi::Object &obj, size_t amount) override;
327
+ void setExternalMemoryPressure(const jsi::Object &obj, size_t amount)
328
+ override;
290
329
  #endif
291
330
 
292
331
  private:
@@ -313,13 +352,15 @@ class NodeApiJsiRuntime : public jsi::Runtime {
313
352
  ~NodeApiPointerValueScope() noexcept;
314
353
 
315
354
  NodeApiPointerValueScope(const NodeApiPointerValueScope &) = delete;
316
- NodeApiPointerValueScope &operator=(const NodeApiPointerValueScope &) = delete;
355
+ NodeApiPointerValueScope &operator=(const NodeApiPointerValueScope &) =
356
+ delete;
317
357
 
318
358
  private:
319
359
  NodeApiJsiRuntime &runtime_;
320
360
  };
321
361
 
322
- // Sets the variable in the constructor and then restores its value in the destructor.
362
+ // Sets the variable in the constructor and then restores its value in the
363
+ // destructor.
323
364
  template <typename T>
324
365
  class AutoRestore {
325
366
  public:
@@ -334,7 +375,7 @@ class NodeApiJsiRuntime : public jsi::Runtime {
334
375
  T oldValue_;
335
376
  };
336
377
 
337
- enum class NodeApiPointerValueKind {
378
+ enum class NodeApiPointerValueKind : uint8_t {
338
379
  Object,
339
380
  WeakObject,
340
381
  String,
@@ -345,173 +386,335 @@ class NodeApiJsiRuntime : public jsi::Runtime {
345
386
 
346
387
  class NodeApiRefCountedPointerValue;
347
388
 
389
+ class NodeApiRefCount {
390
+ public:
391
+ static void incRefCount(std::atomic<int32_t> &value) noexcept {
392
+ int refCount = value.fetch_add(1, std::memory_order_relaxed) + 1;
393
+ CHECK_ELSE_CRASH(refCount > 1, "The ref count cannot bounce from zero.");
394
+ CHECK_ELSE_CRASH(
395
+ refCount < std::numeric_limits<int32_t>::max(),
396
+ "The ref count is too big.");
397
+ }
398
+
399
+ static bool decRefCount(std::atomic<int32_t> &value) noexcept {
400
+ int refCount = value.fetch_sub(1, std::memory_order_release) - 1;
401
+ CHECK_ELSE_CRASH(refCount >= 0, "The ref count must not be negative.");
402
+ if (refCount == 0) {
403
+ std::atomic_thread_fence(std::memory_order_acquire);
404
+ return true;
405
+ }
406
+ return false;
407
+ }
408
+
409
+ static bool isZero(std::atomic<int32_t> &value) noexcept {
410
+ return value.load(std::memory_order_relaxed) == 0;
411
+ }
412
+ };
413
+
414
+ // A smart pointer for types that implement intrusive ref count using
415
+ // methods incRefCount and decRefCount.
416
+ template <typename T>
417
+ class NodeApiRefCountedPtr final {
418
+ public:
419
+ NodeApiRefCountedPtr() noexcept = default;
420
+
421
+ explicit NodeApiRefCountedPtr(T *ptr, NodeApiAttachTag) noexcept
422
+ : ptr_(ptr) {}
423
+
424
+ NodeApiRefCountedPtr(const NodeApiRefCountedPtr &other) noexcept
425
+ : ptr_(other.ptr_) {
426
+ if (ptr_ != nullptr) {
427
+ ptr_->incRefCount();
428
+ }
429
+ }
430
+
431
+ NodeApiRefCountedPtr(NodeApiRefCountedPtr &&other)
432
+ : ptr_(std::exchange(other.ptr_, nullptr)) {}
433
+
434
+ ~NodeApiRefCountedPtr() noexcept {
435
+ if (ptr_ != nullptr) {
436
+ ptr_->decRefCount();
437
+ }
438
+ }
439
+
440
+ NodeApiRefCountedPtr &operator=(std::nullptr_t) noexcept {
441
+ if (ptr_ != nullptr) {
442
+ ptr_->decRefCount();
443
+ }
444
+ ptr_ = nullptr;
445
+ return *this;
446
+ }
447
+
448
+ NodeApiRefCountedPtr &operator=(
449
+ const NodeApiRefCountedPtr &other) noexcept {
450
+ if (this != &other) {
451
+ NodeApiRefCountedPtr temp(std::move(*this));
452
+ ptr_ = other.ptr_;
453
+ if (ptr_ != nullptr) {
454
+ ptr_->incRefCount();
455
+ }
456
+ }
457
+ return *this;
458
+ }
459
+
460
+ NodeApiRefCountedPtr &operator=(NodeApiRefCountedPtr &&other) noexcept {
461
+ if (this != &other) {
462
+ NodeApiRefCountedPtr temp(std::move(*this));
463
+ ptr_ = std::exchange(other.ptr_, nullptr);
464
+ }
465
+ return *this;
466
+ }
467
+
468
+ T *operator->() const noexcept {
469
+ return ptr_;
470
+ }
471
+
472
+ T *get() const noexcept {
473
+ return ptr_;
474
+ }
475
+
476
+ explicit operator bool() const noexcept {
477
+ return ptr_ != nullptr;
478
+ }
479
+
480
+ T *release() noexcept {
481
+ return std::exchange(ptr_, nullptr);
482
+ }
483
+
484
+ private:
485
+ T *ptr_{};
486
+ };
487
+
488
+ // Removes the `napi_value value_` field.
489
+ class NodeApiStackValueDeleter {
490
+ public:
491
+ void operator()(NodeApiRefCountedPointerValue *ptr) const noexcept;
492
+ };
493
+
494
+ // Removes the NodeApiRefCountedPointerValue instance and ignores the
495
+ // `napi_ref ref_` field.
496
+ class NodeApiRefDeleter {
497
+ public:
498
+ void operator()(NodeApiRefCountedPointerValue *ptr) const noexcept;
499
+ };
500
+
501
+ using NodeApiRefHolder = NodeApiRefCountedPtr<NodeApiRefCountedPointerValue>;
502
+ using NodeApiStackValuePtr =
503
+ std::unique_ptr<NodeApiRefCountedPointerValue, NodeApiStackValueDeleter>;
504
+ using NodeApiRefPtr =
505
+ std::unique_ptr<NodeApiRefCountedPointerValue, NodeApiRefDeleter>;
506
+
507
+ // NodeApiPendingDeletions helps to delete PointerValues in a thread safe way
508
+ // from the JS thread. According to JSI spec the PointerValue's release method
509
+ // can be called from any thread, while Node-API can only manage objects in
510
+ // the JS thread. So, when a PointerValue's ref count goes to zero after
511
+ // calling the release method, the PointerValue is added into the
512
+ // pointerValuesToDelete_ vector, and then NodeApiJsiRuntime deletes them
513
+ // later from the JS thread. Note that the napi_delete_reference can only be
514
+ // called before the napi_env is destroyed. Thus, we remove the pointer to
515
+ // napi_env as soon as NodeApiJsiRuntime destructor starts.
516
+ class NodeApiPendingDeletions {
517
+ public:
518
+ // Create new instance of NodeApiPendingDeletions.
519
+ static NodeApiRefCountedPtr<NodeApiPendingDeletions> create() noexcept {
520
+ return NodeApiRefCountedPtr<NodeApiPendingDeletions>(
521
+ new NodeApiPendingDeletions(), attachTag);
522
+ }
523
+
524
+ // Add PointerValues to delete from JS thread. The method can be called from
525
+ // any thread.
526
+ void addPointerValueToDelete(NodeApiRefPtr pointerValueToDelete) noexcept {
527
+ std::scoped_lock lock{mutex_};
528
+ pointerValuesToDeletePool_[poolSelector_].push_back(
529
+ std::move(pointerValueToDelete));
530
+ }
531
+
532
+ // Delete all PointerValues scheduled for deletion along with their napi_ref
533
+ // instances. It must be called from a JS thread.
534
+ void deletePointerValues(NodeApiJsiRuntime &runtime) noexcept {
535
+ {
536
+ // TODO: Does it affect the performance to take the lock every time?
537
+ // Should we use an atomic variable?
538
+ std::scoped_lock lock{mutex_};
539
+ if (pointerValuesToDeletePool_[poolSelector_].empty()) {
540
+ return;
541
+ }
542
+
543
+ // Switch the pool entries.
544
+ poolSelector_ = poolSelector_ ^ 1;
545
+ }
546
+
547
+ std::vector<NodeApiRefPtr> &deleteInJSThread =
548
+ pointerValuesToDeletePool_[poolSelector_ ^ 1];
549
+ for (auto &pointerValue : deleteInJSThread) {
550
+ pointerValue.release()->deleteNodeApiRef(runtime);
551
+ }
552
+ deleteInJSThread.resize(0);
553
+ }
554
+
555
+ private:
556
+ friend class NodeApiRefCountedPtr<NodeApiPendingDeletions>;
557
+
558
+ NodeApiPendingDeletions() noexcept = default;
559
+
560
+ void incRefCount() noexcept {
561
+ NodeApiRefCount::incRefCount(refCount_);
562
+ }
563
+
564
+ void decRefCount() noexcept {
565
+ if (NodeApiRefCount::decRefCount(refCount_)) {
566
+ delete this;
567
+ }
568
+ }
569
+
570
+ private:
571
+ mutable std::atomic<int32_t> refCount_{1};
572
+ std::recursive_mutex mutex_;
573
+ // One of the vectors is used from different threads under the mutex_ lock
574
+ // to add items, while another is from JS thread to remove items. Since we
575
+ // never change the capacity of the vectors, it should help avoiding memory
576
+ // allocations at some point.
577
+ std::vector<NodeApiRefPtr> pointerValuesToDeletePool_[2]{
578
+ std::vector<NodeApiRefPtr>(),
579
+ std::vector<NodeApiRefPtr>()};
580
+ // Index of the pool to access under mutex.
581
+ int32_t poolSelector_{0};
582
+ };
583
+
348
584
  // NodeApiPointerValue is used by jsi::Pointer derived classes.
349
585
  struct NodeApiPointerValue : PointerValue {
350
- virtual NodeApiRefCountedPointerValue *clone(NodeApiJsiRuntime &runtime) const = 0;
586
+ virtual NodeApiRefCountedPointerValue *clone(
587
+ NodeApiJsiRuntime &runtime) const noexcept = 0;
351
588
  virtual napi_value getValue(NodeApiJsiRuntime &runtime) noexcept = 0;
352
589
  virtual NodeApiPointerValueKind getKind() const noexcept = 0;
353
590
  };
354
591
 
355
- // NodeApiStackOnlyPointerValue helps to avoid memory allocation in some scenarios.
356
- // It is used by the JsiValueView, JsiValueViewArgs, and PropNameIDView classes
357
- // to keep temporary PointerValues on the call stack.
592
+ // NodeApiStackOnlyPointerValue helps to avoid memory allocation in some
593
+ // scenarios. It is used by the JsiValueView, JsiValueViewArgs, and
594
+ // PropNameIDView classes to keep temporary PointerValues on the call stack
595
+ // when we call functions. Note that the clone() method return a new instance
596
+ // of the NodeApiRefCountedPointerValue.
358
597
  class NodeApiStackOnlyPointerValue final : public NodeApiPointerValue {
359
598
  public:
360
- NodeApiStackOnlyPointerValue(napi_value value, NodeApiPointerValueKind pointerKind) noexcept;
599
+ NodeApiStackOnlyPointerValue(
600
+ napi_value value,
601
+ NodeApiPointerValueKind pointerKind) noexcept;
361
602
 
362
603
  void invalidate() noexcept override;
363
- NodeApiRefCountedPointerValue *clone(NodeApiJsiRuntime &runtime) const override;
604
+ NodeApiRefCountedPointerValue *clone(
605
+ NodeApiJsiRuntime &runtime) const noexcept override;
364
606
  napi_value getValue(NodeApiJsiRuntime &runtime) noexcept override;
365
607
  NodeApiPointerValueKind getKind() const noexcept override;
366
608
 
367
609
  NodeApiStackOnlyPointerValue(const NodeApiStackOnlyPointerValue &) = delete;
368
- NodeApiStackOnlyPointerValue &operator=(const NodeApiStackOnlyPointerValue &) = delete;
610
+ NodeApiStackOnlyPointerValue &operator=(
611
+ const NodeApiStackOnlyPointerValue &) = delete;
369
612
 
370
613
  private:
371
614
  napi_value value_{};
372
615
  NodeApiPointerValueKind pointerKind_{NodeApiPointerValueKind::Object};
373
616
  };
374
617
 
375
- // NodeApiRefCountedPointerValue is a ref counted implementation of PointerValue that is allocated in the heap.
376
- // It expects to have three different types of smart pointers:
377
- // - jsi::Pointer derived classes uses clone() and invalidate() methods to increment and decrement the ref count.
378
- // The invalidate() method can be called from any thread.
379
- // - NodeApiStackValueHolder points to NodeApiRefCountedPointerValue when it has associated napi_value.
380
- // - NodeApiRefHolder points to NodeApiRefCountedPointerValue when it has associated napi_ref.
618
+ // TODO: Use arena allocator for NodeApiRefCountedPointerValue.
619
+
620
+ // NodeApiRefCountedPointerValue is a ref counted implementation of
621
+ // PointerValue that is allocated in the heap.
622
+ //
623
+ // Its lifetime is controlled by the atomic `refCount_` field. Since the
624
+ // `refCount_` can be changed from any thread, we do not remove the instance
625
+ // immediately when the `refCount_` becomes zero. Instead, we add it to the
626
+ // `NodeApiJsiRuntime::pendingDeletions_` list and delete it later from the JS
627
+ // thread. If `node_value value_` field is not null, then the
628
+ // `NodeApiRefCountedPointerValue` instance is also referenced from the
629
+ // `NodeApiJsiRuntime::stackValues_` list.
381
630
  //
382
- // Using three types of smart pointers ensures that we always destroy napi_ref from the right thread.
383
- // The invalidate() method can destroy NodeApiRefCountedPointerValue from a different thread only when there are
384
- // no napi_value or napi_ref present in the class. Otherwise, the destruction will happen when we remove
385
- // either napi_value or napi_ref reference.
631
+ // The `NodeApiJsiRuntime::pendingDeletions_` is responsible for deleting
632
+ // `napi_ref ref_` and it deletes `NodeApiRefCountedPointerValue` instance if
633
+ // the `node_value value_` field is null. While
634
+ // `NodeApiJsiRuntime::stackValues_` is responsible for deleting
635
+ // `NodeApiRefCountedPointerValue` instance if `node_value value_` field is
636
+ // not null and `napi_ref ref_` is null. In case if
637
+ // `NodeApiJsiRuntime::pendingDeletions_` or `NodeApiJsiRuntime::stackValues_`
638
+ // cannot delete the instance, they set their "owned" `value_` or `ref_`
639
+ // fields to null.
386
640
  //
387
- // Some NodeApiRefCountedPointerValue are created with napi_value and may never get napi_ref.
388
- // When stack scope is closed we see if there any jsi::Pointer references. If such references still exist, then
389
- // we ensure that it has an associated napi_ref or we create one.
641
+ // Some NodeApiRefCountedPointerValue are created with napi_value and may
642
+ // never get napi_ref. When stack scope is closed we check the `refCount_`. If
643
+ // it is not zero, then we ensure that it has an associated `napi_ref` or we
644
+ // create one.
390
645
  //
391
- // In addition to the scope closure, there are two cases when we collect NodeApiRefCountedPointerValue
392
- // without jsi::Pointer references:
393
- // - When we grow the NodeApiJsiRuntime::stackValues_ vector and we reached current capacity.
394
- // - When we grow the NodeApiJsiRuntime::refs_ vector and we reached current capacity.
646
+ // All methods except for invalidate() and decRefCount() must be called from
647
+ // the JS thread.
395
648
  class NodeApiRefCountedPointerValue final : public NodeApiPointerValue {
649
+ friend class NodeApiStackValueDeleter;
650
+ friend class NodeApiRefDeleter;
651
+ friend class NodeApiRefCountedPtr<NodeApiRefCountedPointerValue>;
652
+
396
653
  public:
397
- // Creates new NodeApiRefCountedPointerValue and adds it to the NodeApiJsiRuntime::stackValues_. The ref count
398
- // usually starts with 2: one for NodeApiJsiRuntime::stackValues_ reference and another for the targeting
399
- // jsi::Pointer.
400
- static NodeApiRefCountedPointerValue *make(
654
+ // Creates new NodeApiRefCountedPointerValue and adds it to the
655
+ // NodeApiJsiRuntime::stackValues_.
656
+ static NodeApiRefHolder make(
401
657
  NodeApiJsiRuntime &runtime,
402
658
  napi_value value,
403
659
  NodeApiPointerValueKind pointerKind,
404
- int32_t initialRefCount = 2);
660
+ int32_t initialRefCount = 1);
405
661
 
406
- // Creates new NodeApiRefCountedPointerValue and adds it to the NodeApiJsiRuntime::stackValues_. Then, it creates
407
- // the napi_ref. The ref count usually starts with 2: one for NodeApiJsiRuntime::stackValues_ reference and another
408
- // for the targeting NodeApiRefHolder.
409
- static NodeApiRefCountedPointerValue *makeNodeApiRef(
662
+ // Calls `make` method and forces creation of `napi_ref`.
663
+ static NodeApiRefHolder makeNodeApiRef(
410
664
  NodeApiJsiRuntime &runtime,
411
665
  napi_value value,
412
666
  NodeApiPointerValueKind pointerKind,
413
- int32_t initialRefCount = 2);
667
+ int32_t initialRefCount = 1);
414
668
 
415
669
  void invalidate() noexcept override;
416
- NodeApiRefCountedPointerValue *clone(NodeApiJsiRuntime &runtime) const override;
670
+ NodeApiRefCountedPointerValue *clone(
671
+ NodeApiJsiRuntime &runtime) const noexcept override;
417
672
  napi_value getValue(NodeApiJsiRuntime &runtime) noexcept override;
418
673
  NodeApiPointerValueKind getKind() const noexcept override;
419
674
 
420
- // Returns true if the ref count is bigger than if we would have only references for napi_value and napi_ref.
421
- static bool usedByJsiPointer(NodeApiRefCountedPointerValue *ptr) noexcept;
422
-
423
- // Remove napi_value field.
424
- static void deleteStackValue(NodeApiRefCountedPointerValue *ptr) noexcept;
675
+ // Returns true if the refCount_ is not zero.
676
+ bool usedByJsiPointer() const noexcept;
425
677
 
426
- // Removes napi_value field and ensures existence of napi_ref field.
427
- // Returns true if napi_ref was created and ref count did not change.
428
- // Otherwise, the napi_ref was already there and the ref count was decremented.
429
- void convertToNodeApiRef(NodeApiJsiRuntime &runtime) noexcept;
678
+ // Removes `napi_value value_` field.
679
+ // In case if `refCount_` is not null, it ensures existence of the `napi_ref
680
+ // ref_` field.
681
+ void deleteStackValue(NodeApiJsiRuntime &runtime) noexcept;
430
682
 
431
- // Removes napi_ref pointer and decrements ref count. The napi_ref is not deleted.
432
- // It is useful for napi_env shutdown when napi_env deletes napi_ref and we must not do it.
433
- static void deleteNodeApiRef(NodeApiRefCountedPointerValue *ptr) noexcept;
683
+ // Removes napi_ref and deletes `NodeApiRefCountedPointerValue` if `value_`
684
+ // is null.
685
+ void deleteNodeApiRef(NodeApiJsiRuntime &runtime) noexcept;
434
686
 
435
- // Deletes napi_ref, removes napi_ref pointer, and decrements ref count.
436
- // This method must be used in all scenarios except for napi_env shutdown.
437
- static void deleteNodeApiRef(NodeApiRefCountedPointerValue *ptr, NodeApiJsiRuntime &runtime) noexcept;
438
-
439
- NodeApiRefCountedPointerValue(const NodeApiRefCountedPointerValue &) = delete;
440
- NodeApiRefCountedPointerValue &operator=(const NodeApiRefCountedPointerValue &) = delete;
687
+ NodeApiRefCountedPointerValue(const NodeApiRefCountedPointerValue &) =
688
+ delete;
689
+ NodeApiRefCountedPointerValue &operator=(
690
+ const NodeApiRefCountedPointerValue &) = delete;
441
691
 
442
692
  private:
443
693
  NodeApiRefCountedPointerValue(
694
+ NodeApiJsiRuntime &runtime,
444
695
  napi_value value,
445
696
  NodeApiPointerValueKind pointerKind,
446
697
  int32_t initialRefCount) noexcept;
447
698
 
448
699
  void incRefCount() const noexcept;
449
-
450
- // Decrements ref count. Delete this instance if ref count is zero.
451
700
  void decRefCount() const noexcept;
452
701
 
702
+ // Creates `napi_ref ref_` field for the `napi_value value_` field.
453
703
  NodeApiRefCountedPointerValue *createNodeApiRef(NodeApiJsiRuntime &runtime);
454
704
 
455
705
  private:
706
+ NodeApiRefCountedPtr<NodeApiPendingDeletions> pendingDeletions_;
456
707
  napi_value value_{};
457
708
  napi_ref ref_{};
458
- mutable std::atomic<int32_t> refCount_{};
709
+ mutable std::atomic<int32_t> refCount_{1};
459
710
  const NodeApiPointerValueKind pointerKind_{NodeApiPointerValueKind::Object};
711
+ bool canBeDeletedFromStack_{false};
460
712
 
461
713
  static constexpr char kPrimitivePropertyName[] = "X";
462
714
  };
463
715
 
464
- using NodeApiPointerValueDeleter = void(NodeApiRefCountedPointerValue *);
465
-
466
- template <NodeApiPointerValueDeleter *deleter>
467
- class NodeApiPointerValueHolder {
468
- public:
469
- NodeApiPointerValueHolder() = default;
470
- explicit NodeApiPointerValueHolder(NodeApiRefCountedPointerValue *ptr) : ptr_(ptr) {}
471
-
472
- NodeApiPointerValueHolder(NodeApiPointerValueHolder &&other) : ptr_(std::exchange(other.ptr_, nullptr)) {}
473
-
474
- NodeApiPointerValueHolder &operator=(NodeApiPointerValueHolder &&other) {
475
- if (this != &other) {
476
- NodeApiPointerValueHolder temp(std::move(*this));
477
- ptr_ = std::exchange(other.ptr_, nullptr);
478
- }
479
- return *this;
480
- }
481
-
482
- ~NodeApiPointerValueHolder() {
483
- if (NodeApiRefCountedPointerValue *ptr = std::exchange(ptr_, nullptr)) {
484
- deleter(ptr);
485
- }
486
- }
487
-
488
- NodeApiRefCountedPointerValue *operator->() const {
489
- return ptr_;
490
- }
491
-
492
- NodeApiRefCountedPointerValue *get() const {
493
- return ptr_;
494
- }
495
-
496
- NodeApiRefCountedPointerValue *release() {
497
- return std::exchange(ptr_, nullptr);
498
- }
499
-
500
- explicit operator bool() const {
501
- return ptr_ != nullptr;
502
- }
503
-
504
- NodeApiPointerValueHolder(NodeApiPointerValueHolder const &) = delete;
505
- NodeApiPointerValueHolder &operator=(NodeApiPointerValueHolder const &) = delete;
506
-
507
- private:
508
- NodeApiRefCountedPointerValue *ptr_{};
509
- };
510
-
511
- using NodeApiStackValueHolder = NodeApiPointerValueHolder<&NodeApiRefCountedPointerValue::deleteStackValue>;
512
- using NodeApiRefHolder = NodeApiPointerValueHolder<&NodeApiRefCountedPointerValue::deleteNodeApiRef>;
513
-
514
- // SmallBuffer keeps InplaceSize elements in place in the class, and uses heap memory for more elements.
716
+ // SmallBuffer keeps InplaceSize elements in place in the class, and uses heap
717
+ // memory for more elements.
515
718
  template <typename T, size_t InplaceSize>
516
719
  class SmallBuffer {
517
720
  public:
@@ -529,12 +732,13 @@ class NodeApiJsiRuntime : public jsi::Runtime {
529
732
  std::unique_ptr<T[]> heapData_{};
530
733
  };
531
734
 
532
- // The number of arguments that we keep on stack. We use heap if we have more arguments.
735
+ // The number of arguments that we keep on stack. We use heap if we have more
736
+ // arguments.
533
737
  constexpr static size_t MaxStackArgCount = 8;
534
738
 
535
- // NodeApiValueArgs helps optimize passing arguments to NAPI functions.
536
- // If number of arguments is below or equal to MaxStackArgCount, they are kept on the call stack,
537
- // otherwise arguments are allocated on the heap.
739
+ // NodeApiValueArgs helps optimize passing arguments to Node-API functions.
740
+ // If number of arguments is below or equal to MaxStackArgCount, they are kept
741
+ // on the call stack, otherwise arguments are allocated on the heap.
538
742
  class NodeApiValueArgs {
539
743
  public:
540
744
  NodeApiValueArgs(NodeApiJsiRuntime &runtime, span<const jsi::Value> args);
@@ -547,8 +751,9 @@ class NodeApiJsiRuntime : public jsi::Runtime {
547
751
  SmallBuffer<napi_value, MaxStackArgCount> args_;
548
752
  };
549
753
 
550
- // Helps to use the stack storage for a temporary conversion from napi_value to jsi::Value.
551
- // It also helps to avoid a conversion to a relatively expensive napi_ref.
754
+ // Helps to use the stack storage for a temporary conversion from napi_value
755
+ // to jsi::Value. It also helps to avoid a conversion to a relatively
756
+ // expensive napi_ref.
552
757
  class JsiValueView {
553
758
  public:
554
759
  union StoreType {
@@ -562,7 +767,8 @@ class NodeApiJsiRuntime : public jsi::Runtime {
562
767
  JsiValueView(NodeApiJsiRuntime *runtime, napi_value jsValue);
563
768
  operator const jsi::Value &() const noexcept;
564
769
 
565
- static jsi::Value initValue(NodeApiJsiRuntime *runtime, napi_value jsValue, StoreType *store);
770
+ static jsi::Value
771
+ initValue(NodeApiJsiRuntime *runtime, napi_value jsValue, StoreType *store);
566
772
 
567
773
  JsiValueView(const JsiValueView &) = delete;
568
774
  JsiValueView &operator=(const JsiValueView &) = delete;
@@ -572,12 +778,14 @@ class NodeApiJsiRuntime : public jsi::Runtime {
572
778
  jsi::Value value_{};
573
779
  };
574
780
 
575
- // Helps to use stack storage for passing arguments that must be temporarily converted
576
- // from napi_value to jsi::Value.
577
- // It helps to avoid conversion to a relatively expensive napi_ref.
781
+ // Helps to use stack storage for passing arguments that must be temporarily
782
+ // converted from napi_value to jsi::Value. It helps to avoid conversion to a
783
+ // relatively expensive napi_ref.
578
784
  class JsiValueViewArgs {
579
785
  public:
580
- JsiValueViewArgs(NodeApiJsiRuntime *runtime, span<napi_value> args) noexcept;
786
+ JsiValueViewArgs(
787
+ NodeApiJsiRuntime *runtime,
788
+ span<napi_value> args) noexcept;
581
789
  const jsi::Value *data() noexcept;
582
790
  size_t size() const noexcept;
583
791
 
@@ -590,8 +798,9 @@ class NodeApiJsiRuntime : public jsi::Runtime {
590
798
  SmallBuffer<jsi::Value, MaxStackArgCount> args_{0};
591
799
  };
592
800
 
593
- // Helps to use stack storage for a temporary conversion from napi_value to jsi::PropNameID.
594
- // It helps to avoid conversions to a relatively expensive napi_ref.
801
+ // Helps to use stack storage for a temporary conversion from napi_value to
802
+ // jsi::PropNameID. It helps to avoid conversions to a relatively expensive
803
+ // napi_ref.
595
804
  class PropNameIDView {
596
805
  public:
597
806
  PropNameIDView(NodeApiJsiRuntime *runtime, napi_value propertyId) noexcept;
@@ -609,7 +818,9 @@ class NodeApiJsiRuntime : public jsi::Runtime {
609
818
  // Wraps up the jsi::HostFunctionType along with the NodeApiJsiRuntime.
610
819
  class HostFunctionWrapper {
611
820
  public:
612
- HostFunctionWrapper(jsi::HostFunctionType &&hostFunction, NodeApiJsiRuntime &runtime);
821
+ HostFunctionWrapper(
822
+ jsi::HostFunctionType &&hostFunction,
823
+ NodeApiJsiRuntime &runtime);
613
824
 
614
825
  jsi::HostFunctionType &hostFunction() noexcept;
615
826
  NodeApiJsiRuntime &runtime() noexcept;
@@ -625,7 +836,10 @@ class NodeApiJsiRuntime : public jsi::Runtime {
625
836
  // Wraps up the jsr_prepared_script.
626
837
  class NodeApiPreparedJavaScript final : public jsi::PreparedJavaScript {
627
838
  public:
628
- NodeApiPreparedJavaScript(napi_env env, jsr_prepared_script script, std::string sourceURL)
839
+ NodeApiPreparedJavaScript(
840
+ napi_env env,
841
+ jsr_prepared_script script,
842
+ std::string sourceURL)
629
843
  : env_(env), script_(script), sourceURL_(std::move(sourceURL)) {}
630
844
 
631
845
  ~NodeApiPreparedJavaScript() override {
@@ -641,7 +855,8 @@ class NodeApiJsiRuntime : public jsi::Runtime {
641
855
  }
642
856
 
643
857
  NodeApiPreparedJavaScript(const NodeApiPreparedJavaScript &) = delete;
644
- NodeApiPreparedJavaScript &operator=(const NodeApiPreparedJavaScript &) = delete;
858
+ NodeApiPreparedJavaScript &operator=(const NodeApiPreparedJavaScript &) =
859
+ delete;
645
860
 
646
861
  private:
647
862
  napi_env env_;
@@ -662,7 +877,7 @@ class NodeApiJsiRuntime : public jsi::Runtime {
662
877
  bool setException(napi_value error) const noexcept;
663
878
  bool setException(std::string_view message) const noexcept;
664
879
 
665
- private: // Shared NAPI call helpers
880
+ private: // Shared Node-API call helpers
666
881
  napi_valuetype typeOf(napi_value value) const;
667
882
  bool strictEquals(napi_value left, napi_value right) const;
668
883
  napi_value getUndefined() const;
@@ -685,28 +900,47 @@ class NodeApiJsiRuntime : public jsi::Runtime {
685
900
  std::string propertyIdToStdString(napi_value propertyId);
686
901
  napi_value createSymbol(std::string_view symbolDescription) const;
687
902
  std::string symbolToStdString(napi_value symbolValue);
688
- napi_value callFunction(napi_value thisArg, napi_value function, span<napi_value> args = {}) const;
689
- napi_value constructObject(napi_value constructor, span<napi_value> args = {}) const;
903
+ napi_value callFunction(
904
+ napi_value thisArg,
905
+ napi_value function,
906
+ span<napi_value> args = {}) const;
907
+ napi_value constructObject(napi_value constructor, span<napi_value> args = {})
908
+ const;
690
909
  bool instanceOf(napi_value object, napi_value constructor) const;
691
910
  napi_value createNodeApiObject() const;
692
911
  bool hasProperty(napi_value object, napi_value propertyId) const;
693
912
  napi_value getProperty(napi_value object, napi_value propertyId) const;
694
- void setProperty(napi_value object, napi_value propertyId, napi_value value) const;
695
- void setProperty(napi_value object, napi_value propertyId, napi_value value, napi_property_attributes attrs) const;
913
+ void setProperty(napi_value object, napi_value propertyId, napi_value value)
914
+ const;
915
+ void setProperty(
916
+ napi_value object,
917
+ napi_value propertyId,
918
+ napi_value value,
919
+ napi_property_attributes attrs) const;
696
920
  napi_value createNodeApiArray(size_t length) const;
697
921
  bool isArray(napi_value value) const;
698
922
  size_t getArrayLength(napi_value value) const;
699
923
  napi_value getElement(napi_value arr, size_t index) const;
700
924
  void setElement(napi_value array, uint32_t index, napi_value value) const;
701
- static napi_value __cdecl jsiHostFunctionCallback(napi_env env, napi_callback_info info) noexcept;
702
- napi_value createExternalFunction(napi_value name, int32_t paramCount, napi_callback callback, void *callbackData);
703
- napi_value createExternalObject(void *data, napi_finalize finalizeCallback) const;
925
+ static napi_value __cdecl jsiHostFunctionCallback(
926
+ napi_env env,
927
+ napi_callback_info info) noexcept;
928
+ napi_value createExternalFunction(
929
+ napi_value name,
930
+ int32_t paramCount,
931
+ napi_callback callback,
932
+ void *callbackData);
933
+ napi_value createExternalObject(
934
+ void *data,
935
+ node_api_nogc_finalize finalizeCallback) const;
704
936
  template <typename T>
705
937
  napi_value createExternalObject(std::unique_ptr<T> &&data) const;
706
938
  void *getExternalData(napi_value object) const;
707
939
  const std::shared_ptr<jsi::HostObject> &getJsiHostObject(napi_value obj);
708
940
  napi_value getHostObjectProxyHandler();
709
- template <napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>), size_t argCount>
941
+ template <
942
+ napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>),
943
+ size_t argCount>
710
944
  void setProxyTrap(napi_value handler, napi_value propertyName);
711
945
  napi_value hostObjectHasTrap(span<napi_value> args);
712
946
  napi_value hostObjectGetTrap(span<napi_value> args);
@@ -720,17 +954,28 @@ class NodeApiJsiRuntime : public jsi::Runtime {
720
954
  napi_value getNodeApiValue(const jsi::Value &value) const;
721
955
  napi_value getNodeApiValue(const jsi::Pointer &ptr) const;
722
956
  napi_value getNodeApiValue(const NodeApiRefHolder &ref) const;
723
- NodeApiRefCountedPointerValue *cloneNodeApiPointerValue(const PointerValue *pointerValue);
724
- std::optional<uint32_t> toArrayIndex(std::string::const_iterator first, std::string::const_iterator last);
957
+ NodeApiRefCountedPointerValue *cloneNodeApiPointerValue(
958
+ const PointerValue *pointerValue);
959
+ std::optional<uint32_t> toArrayIndex(
960
+ std::string::const_iterator first,
961
+ std::string::const_iterator last);
725
962
 
726
- template <typename T, std::enable_if_t<std::is_same_v<jsi::Object, T>, int> = 0>
963
+ template <
964
+ typename T,
965
+ std::enable_if_t<std::is_same_v<jsi::Object, T>, int> = 0>
727
966
  T makeJsiPointer(napi_value value) const;
728
- template <typename T, std::enable_if_t<std::is_same_v<jsi::String, T>, int> = 0>
967
+ template <
968
+ typename T,
969
+ std::enable_if_t<std::is_same_v<jsi::String, T>, int> = 0>
729
970
  T makeJsiPointer(napi_value value) const;
730
- template <typename T, std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int> = 0>
971
+ template <
972
+ typename T,
973
+ std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int> = 0>
731
974
  T makeJsiPointer(napi_value value) const;
732
975
  #if JSI_VERSION >= 6
733
- template <typename T, std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int> = 0>
976
+ template <
977
+ typename T,
978
+ std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int> = 0>
734
979
  T makeJsiPointer(napi_value value) const;
735
980
  #endif
736
981
  template <
@@ -739,14 +984,14 @@ class NodeApiJsiRuntime : public jsi::Runtime {
739
984
  std::enable_if_t<std::is_base_of_v<jsi::Pointer, TTo>, int> = 0,
740
985
  std::enable_if_t<std::is_base_of_v<jsi::Pointer, TFrom>, int> = 0>
741
986
  TTo cloneAs(const TFrom &pointer) const;
742
- NodeApiRefHolder makeNodeApiRef(napi_value value, NodeApiPointerValueKind pointerKind, int32_t initialRefCount = 2);
987
+ NodeApiRefHolder makeNodeApiRef(
988
+ napi_value value,
989
+ NodeApiPointerValueKind pointerKind,
990
+ int32_t initialRefCount = 1);
743
991
 
744
- void addStackValue(NodeApiStackValueHolder &&pointerHolder);
745
- void addRef(NodeApiRefHolder &&refHolder);
992
+ void addStackValue(NodeApiStackValuePtr stackPointer);
746
993
  void pushPointerValueScope() noexcept;
747
994
  void popPointerValueScope() noexcept;
748
- void collectUnusedStackValues();
749
- void collectUnusedRefs() noexcept;
750
995
 
751
996
  napi_env getEnv() const noexcept {
752
997
  return env_;
@@ -796,13 +1041,19 @@ class NodeApiJsiRuntime : public jsi::Runtime {
796
1041
  bool hasPendingJSError_{false};
797
1042
 
798
1043
  std::vector<size_t> stackScopes_;
799
- std::vector<NodeApiStackValueHolder> stackValues_;
800
- std::vector<NodeApiRefHolder> refs_;
1044
+ std::vector<NodeApiStackValuePtr> stackValues_;
801
1045
 
802
1046
  // TODO: implement GC for propNameIDs_
803
- std::unordered_map<StringKey, NodeApiRefHolder, StringKey::Hash, StringKey::EqualTo> propNameIDs_;
1047
+ std::unordered_map<
1048
+ StringKey,
1049
+ NodeApiRefHolder,
1050
+ StringKey::Hash,
1051
+ StringKey::EqualTo>
1052
+ propNameIDs_;
804
1053
 
805
1054
  NodeApiJsiRuntime &runtime{*this};
1055
+ NodeApiRefCountedPtr<NodeApiPendingDeletions> pendingDeletions_{
1056
+ NodeApiPendingDeletions::create()};
806
1057
  };
807
1058
 
808
1059
  //=====================================================================================================================
@@ -810,19 +1061,27 @@ class NodeApiJsiRuntime : public jsi::Runtime {
810
1061
  //=====================================================================================================================
811
1062
 
812
1063
  StringKey::StringKey(std::string &&string) noexcept
813
- : string_(std::move(string)), type_(Type::String), hash_(std::hash<std::string_view>{}(string_)) {}
1064
+ : string_(std::move(string)),
1065
+ type_(Type::String),
1066
+ hash_(std::hash<std::string_view>{}(string_)) {}
814
1067
 
815
1068
  StringKey::StringKey(std::string_view view) noexcept
816
- : view_(view), type_(Type::View), hash_(std::hash<std::string_view>{}(view_)) {}
1069
+ : view_(view),
1070
+ type_(Type::View),
1071
+ hash_(std::hash<std::string_view>{}(view_)) {}
817
1072
 
818
1073
  StringKey::StringKey(const char *data, size_t length) noexcept
819
- : view_(data, length), type_(Type::View), hash_(std::hash<std::string_view>{}(view_)) {}
1074
+ : view_(data, length),
1075
+ type_(Type::View),
1076
+ hash_(std::hash<std::string_view>{}(view_)) {}
820
1077
 
821
- StringKey::StringKey(StringKey &&other) noexcept : type_(other.type_), hash_(std::exchange(other.hash_, 0)) {
1078
+ StringKey::StringKey(StringKey &&other) noexcept
1079
+ : type_(other.type_), hash_(std::exchange(other.hash_, 0)) {
822
1080
  if (type_ == Type::String) {
823
1081
  ::new (std::addressof(string_)) std::string(std::move(other.string_));
824
1082
  } else {
825
- ::new (std::addressof(view_)) std::string_view(std::exchange(other.view_, std::string_view()));
1083
+ ::new (std::addressof(view_))
1084
+ std::string_view(std::exchange(other.view_, std::string_view()));
826
1085
  }
827
1086
  }
828
1087
 
@@ -858,7 +1117,9 @@ size_t StringKey::Hash::operator()(const StringKey &key) const {
858
1117
  return key.hash();
859
1118
  }
860
1119
 
861
- bool StringKey::EqualTo::operator()(const StringKey &left, const StringKey &right) const {
1120
+ bool StringKey::EqualTo::operator()(
1121
+ const StringKey &left,
1122
+ const StringKey &right) const {
862
1123
  return left.equalTo(right);
863
1124
  }
864
1125
 
@@ -866,37 +1127,65 @@ bool StringKey::EqualTo::operator()(const StringKey &left, const StringKey &righ
866
1127
  // NodeApiJsiRuntime implementation
867
1128
  //=====================================================================================================================
868
1129
 
869
- NodeApiJsiRuntime::NodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()> onDelete) noexcept
1130
+ NodeApiJsiRuntime::NodeApiJsiRuntime(
1131
+ napi_env env,
1132
+ JSRuntimeApi *jsrApi,
1133
+ std::function<void()> onDelete) noexcept
870
1134
  : env_(env), jsrApi_(jsrApi), onDelete_(std::move(onDelete)) {
871
1135
  NodeApiScope scope{*this};
872
- propertyId_.Error = makeNodeApiRef(getPropertyIdFromName("Error"), NodeApiPointerValueKind::String);
873
- propertyId_.Object = makeNodeApiRef(getPropertyIdFromName("Object"), NodeApiPointerValueKind::String);
874
- propertyId_.Proxy = makeNodeApiRef(getPropertyIdFromName("Proxy"), NodeApiPointerValueKind::String);
875
- propertyId_.Symbol = makeNodeApiRef(getPropertyIdFromName("Symbol"), NodeApiPointerValueKind::String);
876
- propertyId_.byteLength = makeNodeApiRef(getPropertyIdFromName("byteLength"), NodeApiPointerValueKind::String);
877
- propertyId_.configurable = makeNodeApiRef(getPropertyIdFromName("configurable"), NodeApiPointerValueKind::String);
878
- propertyId_.enumerable = makeNodeApiRef(getPropertyIdFromName("enumerable"), NodeApiPointerValueKind::String);
879
- propertyId_.get = makeNodeApiRef(getPropertyIdFromName("get"), NodeApiPointerValueKind::String);
880
- propertyId_.getOwnPropertyDescriptor =
881
- makeNodeApiRef(getPropertyIdFromName("getOwnPropertyDescriptor"), NodeApiPointerValueKind::String);
882
- propertyId_.has = makeNodeApiRef(getPropertyIdFromName("has"), NodeApiPointerValueKind::String);
883
- propertyId_.hostFunctionSymbol = makeNodeApiRef(createSymbol("hostFunctionSymbol"), NodeApiPointerValueKind::Symbol);
884
- propertyId_.hostObjectSymbol = makeNodeApiRef(createSymbol("hostObjectSymbol"), NodeApiPointerValueKind::Symbol);
885
- propertyId_.length = makeNodeApiRef(getPropertyIdFromName("length"), NodeApiPointerValueKind::String);
886
- propertyId_.message = makeNodeApiRef(getPropertyIdFromName("message"), NodeApiPointerValueKind::String);
887
- propertyId_.ownKeys = makeNodeApiRef(getPropertyIdFromName("ownKeys"), NodeApiPointerValueKind::String);
888
- propertyId_.propertyIsEnumerable =
889
- makeNodeApiRef(getPropertyIdFromName("propertyIsEnumerable"), NodeApiPointerValueKind::String);
890
- propertyId_.prototype = makeNodeApiRef(getPropertyIdFromName("prototype"), NodeApiPointerValueKind::String);
891
- propertyId_.set = makeNodeApiRef(getPropertyIdFromName("set"), NodeApiPointerValueKind::String);
892
- propertyId_.stack = makeNodeApiRef(getPropertyIdFromName("stack"), NodeApiPointerValueKind::String);
893
- propertyId_.toString = makeNodeApiRef(getPropertyIdFromName("toString"), NodeApiPointerValueKind::String);
894
- propertyId_.value = makeNodeApiRef(getPropertyIdFromName("value"), NodeApiPointerValueKind::String);
895
- propertyId_.writable = makeNodeApiRef(getPropertyIdFromName("writable"), NodeApiPointerValueKind::String);
896
-
897
- cachedValue_.Global = makeNodeApiRef(getGlobal(), NodeApiPointerValueKind::Object);
1136
+ propertyId_.Error = makeNodeApiRef(
1137
+ getPropertyIdFromName("Error"), NodeApiPointerValueKind::String);
1138
+ propertyId_.Object = makeNodeApiRef(
1139
+ getPropertyIdFromName("Object"), NodeApiPointerValueKind::String);
1140
+ propertyId_.Proxy = makeNodeApiRef(
1141
+ getPropertyIdFromName("Proxy"), NodeApiPointerValueKind::String);
1142
+ propertyId_.Symbol = makeNodeApiRef(
1143
+ getPropertyIdFromName("Symbol"), NodeApiPointerValueKind::String);
1144
+ propertyId_.byteLength = makeNodeApiRef(
1145
+ getPropertyIdFromName("byteLength"), NodeApiPointerValueKind::String);
1146
+ propertyId_.configurable = makeNodeApiRef(
1147
+ getPropertyIdFromName("configurable"), NodeApiPointerValueKind::String);
1148
+ propertyId_.enumerable = makeNodeApiRef(
1149
+ getPropertyIdFromName("enumerable"), NodeApiPointerValueKind::String);
1150
+ propertyId_.get = makeNodeApiRef(
1151
+ getPropertyIdFromName("get"), NodeApiPointerValueKind::String);
1152
+ propertyId_.getOwnPropertyDescriptor = makeNodeApiRef(
1153
+ getPropertyIdFromName("getOwnPropertyDescriptor"),
1154
+ NodeApiPointerValueKind::String);
1155
+ propertyId_.has = makeNodeApiRef(
1156
+ getPropertyIdFromName("has"), NodeApiPointerValueKind::String);
1157
+ propertyId_.hostFunctionSymbol = makeNodeApiRef(
1158
+ createSymbol("hostFunctionSymbol"), NodeApiPointerValueKind::Symbol);
1159
+ propertyId_.hostObjectSymbol = makeNodeApiRef(
1160
+ createSymbol("hostObjectSymbol"), NodeApiPointerValueKind::Symbol);
1161
+ propertyId_.length = makeNodeApiRef(
1162
+ getPropertyIdFromName("length"), NodeApiPointerValueKind::String);
1163
+ propertyId_.message = makeNodeApiRef(
1164
+ getPropertyIdFromName("message"), NodeApiPointerValueKind::String);
1165
+ propertyId_.ownKeys = makeNodeApiRef(
1166
+ getPropertyIdFromName("ownKeys"), NodeApiPointerValueKind::String);
1167
+ propertyId_.propertyIsEnumerable = makeNodeApiRef(
1168
+ getPropertyIdFromName("propertyIsEnumerable"),
1169
+ NodeApiPointerValueKind::String);
1170
+ propertyId_.prototype = makeNodeApiRef(
1171
+ getPropertyIdFromName("prototype"), NodeApiPointerValueKind::String);
1172
+ propertyId_.set = makeNodeApiRef(
1173
+ getPropertyIdFromName("set"), NodeApiPointerValueKind::String);
1174
+ propertyId_.stack = makeNodeApiRef(
1175
+ getPropertyIdFromName("stack"), NodeApiPointerValueKind::String);
1176
+ propertyId_.toString = makeNodeApiRef(
1177
+ getPropertyIdFromName("toString"), NodeApiPointerValueKind::String);
1178
+ propertyId_.value = makeNodeApiRef(
1179
+ getPropertyIdFromName("value"), NodeApiPointerValueKind::String);
1180
+ propertyId_.writable = makeNodeApiRef(
1181
+ getPropertyIdFromName("writable"), NodeApiPointerValueKind::String);
1182
+
1183
+ cachedValue_.Global =
1184
+ makeNodeApiRef(getGlobal(), NodeApiPointerValueKind::Object);
898
1185
  cachedValue_.Error = makeNodeApiRef(
899
- getProperty(getNodeApiValue(cachedValue_.Global), getNodeApiValue(propertyId_.Error)),
1186
+ getProperty(
1187
+ getNodeApiValue(cachedValue_.Global),
1188
+ getNodeApiValue(propertyId_.Error)),
900
1189
  NodeApiPointerValueKind::Object);
901
1190
  }
902
1191
 
@@ -912,7 +1201,8 @@ jsi::Value NodeApiJsiRuntime::evaluateJavaScript(
912
1201
  return evaluatePreparedJavaScript(prepareJavaScript(buffer, sourceURL));
913
1202
  }
914
1203
 
915
- std::shared_ptr<const jsi::PreparedJavaScript> NodeApiJsiRuntime::prepareJavaScript(
1204
+ std::shared_ptr<const jsi::PreparedJavaScript>
1205
+ NodeApiJsiRuntime::prepareJavaScript(
916
1206
  const std::shared_ptr<const jsi::Buffer> &sourceBuffer,
917
1207
  std::string sourceURL) {
918
1208
  NodeApiScope scope{*this};
@@ -922,24 +1212,38 @@ std::shared_ptr<const jsi::PreparedJavaScript> NodeApiJsiRuntime::prepareJavaScr
922
1212
  sourceBuffer->data(),
923
1213
  sourceBuffer->size(),
924
1214
  [](void * /*data*/, void *deleterData) {
925
- delete reinterpret_cast<std::shared_ptr<const jsi::Buffer> *>(deleterData);
1215
+ delete reinterpret_cast<std::shared_ptr<const jsi::Buffer> *>(
1216
+ deleterData);
926
1217
  },
927
1218
  new std::shared_ptr<const jsi::Buffer>(sourceBuffer),
928
1219
  sourceURL.c_str(),
929
1220
  &script);
930
1221
  CHECK_NAPI(status); // Not for the call to keep better automated formatting.
931
- return std::make_shared<NodeApiPreparedJavaScript>(env_, script, std::move(sourceURL));
1222
+ return std::make_shared<NodeApiPreparedJavaScript>(
1223
+ env_, script, std::move(sourceURL));
932
1224
  }
933
1225
 
934
- jsi::Value NodeApiJsiRuntime::evaluatePreparedJavaScript(const std::shared_ptr<const jsi::PreparedJavaScript> &js) {
1226
+ jsi::Value NodeApiJsiRuntime::evaluatePreparedJavaScript(
1227
+ const std::shared_ptr<const jsi::PreparedJavaScript> &js) {
935
1228
  NodeApiScope scope{*this};
936
- auto preparedScript = static_cast<const NodeApiPreparedJavaScript *>(js.get());
937
- AutoRestore<std::string> sourceURLScope{sourceURL_, preparedScript->sourceURL()};
1229
+ auto preparedScript =
1230
+ static_cast<const NodeApiPreparedJavaScript *>(js.get());
1231
+ AutoRestore<std::string> sourceURLScope{
1232
+ sourceURL_, preparedScript->sourceURL()};
938
1233
  napi_value result{};
939
- CHECK_NAPI(jsrApi_->jsr_prepared_script_run(env_, preparedScript->getScript(), &result));
1234
+ CHECK_NAPI(jsrApi_->jsr_prepared_script_run(
1235
+ env_, preparedScript->getScript(), &result));
940
1236
  return toJsiValue(result);
941
1237
  }
942
1238
 
1239
+ #if JSI_VERSION >= 12
1240
+ void NodeApiJsiRuntime::queueMicrotask(const jsi::Function &callback) {
1241
+ NodeApiScope scope{*this};
1242
+ napi_value callbackValue = getNodeApiValue(callback);
1243
+ CHECK_NAPI(jsrApi_->jsr_queue_microtask(env_, callbackValue));
1244
+ }
1245
+ #endif
1246
+
943
1247
  #if JSI_VERSION >= 4
944
1248
  bool NodeApiJsiRuntime::drainMicrotasks(int maxMicrotasksHint) {
945
1249
  bool result{};
@@ -964,29 +1268,36 @@ bool NodeApiJsiRuntime::isInspectable() {
964
1268
  return result;
965
1269
  }
966
1270
 
967
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneSymbol(const jsi::Runtime::PointerValue *pointerValue) {
1271
+ jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneSymbol(
1272
+ const jsi::Runtime::PointerValue *pointerValue) {
968
1273
  return cloneNodeApiPointerValue(pointerValue);
969
1274
  }
970
1275
 
971
1276
  #if JSI_VERSION >= 6
972
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneBigInt(const jsi::Runtime::PointerValue *pointerValue) {
1277
+ jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneBigInt(
1278
+ const jsi::Runtime::PointerValue *pointerValue) {
973
1279
  return cloneNodeApiPointerValue(pointerValue);
974
1280
  }
975
1281
  #endif
976
1282
 
977
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneString(const jsi::Runtime::PointerValue *pointerValue) {
1283
+ jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneString(
1284
+ const jsi::Runtime::PointerValue *pointerValue) {
978
1285
  return cloneNodeApiPointerValue(pointerValue);
979
1286
  }
980
1287
 
981
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneObject(const jsi::Runtime::PointerValue *pointerValue) {
1288
+ jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneObject(
1289
+ const jsi::Runtime::PointerValue *pointerValue) {
982
1290
  return cloneNodeApiPointerValue(pointerValue);
983
1291
  }
984
1292
 
985
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::clonePropNameID(const jsi::Runtime::PointerValue *pointerValue) {
1293
+ jsi::Runtime::PointerValue *NodeApiJsiRuntime::clonePropNameID(
1294
+ const jsi::Runtime::PointerValue *pointerValue) {
986
1295
  return cloneNodeApiPointerValue(pointerValue);
987
1296
  }
988
1297
 
989
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromAscii(const char *str, size_t length) {
1298
+ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromAscii(
1299
+ const char *str,
1300
+ size_t length) {
990
1301
  NodeApiScope scope{*this};
991
1302
  StringKey keyName{str, length};
992
1303
  auto it = propNameIDs_.find(keyName);
@@ -1000,15 +1311,24 @@ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromAscii(const char *str, si
1000
1311
  CHECK_NAPI(jsrApi_->napi_set_property(env_, obj, propName, getUndefined()));
1001
1312
  napi_value props{};
1002
1313
  CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1003
- env_, obj, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &props));
1314
+ env_,
1315
+ obj,
1316
+ napi_key_own_only,
1317
+ napi_key_skip_symbols,
1318
+ napi_key_numbers_to_strings,
1319
+ &props));
1004
1320
  napi_value propNameId = getElement(props, 0);
1005
- NodeApiRefHolder propNameRef = makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 3);
1321
+ NodeApiRefHolder propNameRef =
1322
+ makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 2);
1006
1323
  jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
1007
- propNameIDs_.try_emplace(StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1324
+ propNameIDs_.try_emplace(
1325
+ StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1008
1326
  return result;
1009
1327
  }
1010
1328
 
1011
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) {
1329
+ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromUtf8(
1330
+ const uint8_t *utf8,
1331
+ size_t length) {
1012
1332
  NodeApiScope scope{*this};
1013
1333
  StringKey keyName{reinterpret_cast<const char *>(utf8), length};
1014
1334
  auto it = propNameIDs_.find(keyName);
@@ -1018,21 +1338,31 @@ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromUtf8(const uint8_t *utf8,
1018
1338
 
1019
1339
  napi_value obj = createNodeApiObject();
1020
1340
  napi_value propName{};
1021
- CHECK_NAPI(jsrApi_->napi_create_string_utf8(env_, reinterpret_cast<const char *>(utf8), length, &propName));
1341
+ CHECK_NAPI(jsrApi_->napi_create_string_utf8(
1342
+ env_, reinterpret_cast<const char *>(utf8), length, &propName));
1022
1343
  CHECK_NAPI(jsrApi_->napi_set_property(env_, obj, propName, getUndefined()));
1023
1344
  napi_value props{};
1024
1345
  CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1025
- env_, obj, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &props));
1346
+ env_,
1347
+ obj,
1348
+ napi_key_own_only,
1349
+ napi_key_skip_symbols,
1350
+ napi_key_numbers_to_strings,
1351
+ &props));
1026
1352
  napi_value propNameId = getElement(props, 0);
1027
- NodeApiRefHolder propNameRef = makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 3);
1353
+ NodeApiRefHolder propNameRef =
1354
+ makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 2);
1028
1355
  jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
1029
- propNameIDs_.try_emplace(StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1356
+ propNameIDs_.try_emplace(
1357
+ StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1030
1358
  return result;
1031
1359
  }
1032
1360
 
1033
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromString(const jsi::String &str) {
1361
+ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromString(
1362
+ const jsi::String &str) {
1034
1363
  NodeApiScope scope{*this};
1035
- const NodeApiPointerValue *pv = static_cast<const NodeApiPointerValue *>(getPointerValue(str));
1364
+ const NodeApiPointerValue *pv =
1365
+ static_cast<const NodeApiPointerValue *>(getPointerValue(str));
1036
1366
  if (pv->getKind() == NodeApiPointerValueKind::StringPropNameID) {
1037
1367
  return make<jsi::PropNameID>(pv->clone(*this));
1038
1368
  }
@@ -1049,16 +1379,24 @@ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromString(const jsi::String
1049
1379
  setProperty(obj, napiStr, getUndefined());
1050
1380
  napi_value props{};
1051
1381
  CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1052
- env_, obj, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &props));
1382
+ env_,
1383
+ obj,
1384
+ napi_key_own_only,
1385
+ napi_key_skip_symbols,
1386
+ napi_key_numbers_to_strings,
1387
+ &props));
1053
1388
  napi_value propNameId = getElement(props, 0);
1054
- NodeApiRefHolder propNameRef = makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 3);
1389
+ NodeApiRefHolder propNameRef =
1390
+ makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 2);
1055
1391
  jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
1056
- propNameIDs_.try_emplace(StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1392
+ propNameIDs_.try_emplace(
1393
+ StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1057
1394
  return result;
1058
1395
  }
1059
1396
 
1060
1397
  #if JSI_VERSION >= 5
1061
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromSymbol(const jsi::Symbol &sym) {
1398
+ jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromSymbol(
1399
+ const jsi::Symbol &sym) {
1062
1400
  // TODO: Should we ensure uniqueness of symbols?
1063
1401
  return cloneAs<jsi::PropNameID>(sym);
1064
1402
  }
@@ -1069,9 +1407,12 @@ std::string NodeApiJsiRuntime::utf8(const jsi::PropNameID &id) {
1069
1407
  return propertyIdToStdString(getNodeApiValue(id));
1070
1408
  }
1071
1409
 
1072
- bool NodeApiJsiRuntime::compare(const jsi::PropNameID &lhs, const jsi::PropNameID &rhs) {
1410
+ bool NodeApiJsiRuntime::compare(
1411
+ const jsi::PropNameID &lhs,
1412
+ const jsi::PropNameID &rhs) {
1073
1413
  NodeApiScope scope{*this};
1074
- return getPointerValue(lhs) == getPointerValue(rhs) || strictEquals(getNodeApiValue(lhs), getNodeApiValue(rhs));
1414
+ return getPointerValue(lhs) == getPointerValue(rhs) ||
1415
+ strictEquals(getNodeApiValue(lhs), getNodeApiValue(rhs));
1075
1416
  }
1076
1417
 
1077
1418
  std::string NodeApiJsiRuntime::symbolToString(const jsi::Symbol &sym) {
@@ -1099,7 +1440,8 @@ bool NodeApiJsiRuntime::bigintIsInt64(const jsi::BigInt &bigint) {
1099
1440
  napi_value value = getNodeApiValue(bigint);
1100
1441
  bool lossless{false};
1101
1442
  int64_t result{};
1102
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_int64(env_, value, &result, &lossless));
1443
+ CHECK_NAPI(
1444
+ jsrApi_->napi_get_value_bigint_int64(env_, value, &result, &lossless));
1103
1445
  return lossless;
1104
1446
  }
1105
1447
 
@@ -1108,7 +1450,8 @@ bool NodeApiJsiRuntime::bigintIsUint64(const jsi::BigInt &bigint) {
1108
1450
  napi_value value = getNodeApiValue(bigint);
1109
1451
  bool lossless{false};
1110
1452
  uint64_t result{};
1111
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
1453
+ CHECK_NAPI(
1454
+ jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
1112
1455
  return lossless;
1113
1456
  }
1114
1457
 
@@ -1117,7 +1460,8 @@ uint64_t NodeApiJsiRuntime::truncate(const jsi::BigInt &bigint) {
1117
1460
  napi_value value = getNodeApiValue(bigint);
1118
1461
  bool lossless{false};
1119
1462
  uint64_t result{};
1120
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
1463
+ CHECK_NAPI(
1464
+ jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
1121
1465
  return result;
1122
1466
  }
1123
1467
 
@@ -1126,12 +1470,17 @@ inline uint32_t constexpr maxCharsPerDigitInRadix(int32_t radix) {
1126
1470
  // char. For power of 2 radixes, it is known (exactly) that each character
1127
1471
  // covers log2(radix) bits. For non-power of 2 radixes, a lower bound is
1128
1472
  // log2(greatest power of 2 that is less than radix).
1129
- uint32_t minNumBitsPerChar = radix < 4 ? 1 : radix < 8 ? 2 : radix < 16 ? 3 : radix < 32 ? 4 : 5;
1473
+ uint32_t minNumBitsPerChar = radix < 4 ? 1
1474
+ : radix < 8 ? 2
1475
+ : radix < 16 ? 3
1476
+ : radix < 32 ? 4
1477
+ : 5;
1130
1478
 
1131
1479
  // With minNumBitsPerChar being the lower bound estimate of how many bits each
1132
1480
  // char can represent, the upper bound of how many chars "fit" in a bigint
1133
1481
  // digit is ceil(sizeofInBits(bigint digit) / minNumBitsPerChar).
1134
- uint32_t numCharsPerDigits = static_cast<uint32_t>(sizeof(uint64_t)) / (1 << minNumBitsPerChar);
1482
+ uint32_t numCharsPerDigits =
1483
+ static_cast<uint32_t>(sizeof(uint64_t)) / (1 << minNumBitsPerChar);
1135
1484
 
1136
1485
  return numCharsPerDigits;
1137
1486
  }
@@ -1151,7 +1500,9 @@ constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
1151
1500
  return ((uint64_t)High << 32) | (uint64_t)Low;
1152
1501
  }
1153
1502
 
1154
- jsi::String NodeApiJsiRuntime::bigintToString(const jsi::BigInt &bigint, int32_t radix) {
1503
+ jsi::String NodeApiJsiRuntime::bigintToString(
1504
+ const jsi::BigInt &bigint,
1505
+ int32_t radix) {
1155
1506
  NodeApiScope scope{*this};
1156
1507
  if (radix < 2 || radix > 36) {
1157
1508
  throw makeJSError("Invalid radix ", radix, " to BigInt.toString");
@@ -1159,7 +1510,8 @@ jsi::String NodeApiJsiRuntime::bigintToString(const jsi::BigInt &bigint, int32_t
1159
1510
 
1160
1511
  napi_value value = getNodeApiValue(bigint);
1161
1512
  size_t wordCount{};
1162
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(env_, value, nullptr, &wordCount, nullptr));
1513
+ CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(
1514
+ env_, value, nullptr, &wordCount, nullptr));
1163
1515
  uint64_t stackWords[8]{};
1164
1516
  std::unique_ptr<uint64_t[]> heapWords;
1165
1517
  uint64_t *words = stackWords;
@@ -1168,7 +1520,8 @@ jsi::String NodeApiJsiRuntime::bigintToString(const jsi::BigInt &bigint, int32_t
1168
1520
  words = heapWords.get();
1169
1521
  }
1170
1522
  int32_t signBit{};
1171
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(env_, value, &signBit, &wordCount, words));
1523
+ CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(
1524
+ env_, value, &signBit, &wordCount, words));
1172
1525
 
1173
1526
  if (wordCount == 0) {
1174
1527
  return createStringFromAscii("0", 1);
@@ -1243,12 +1596,16 @@ jsi::String NodeApiJsiRuntime::bigintToString(const jsi::BigInt &bigint, int32_t
1243
1596
  }
1244
1597
  #endif
1245
1598
 
1246
- jsi::String NodeApiJsiRuntime::createStringFromAscii(const char *str, size_t length) {
1599
+ jsi::String NodeApiJsiRuntime::createStringFromAscii(
1600
+ const char *str,
1601
+ size_t length) {
1247
1602
  NodeApiScope scope{*this};
1248
1603
  return makeJsiPointer<jsi::String>(createStringLatin1({str, length}));
1249
1604
  }
1250
1605
 
1251
- jsi::String NodeApiJsiRuntime::createStringFromUtf8(const uint8_t *str, size_t length) {
1606
+ jsi::String NodeApiJsiRuntime::createStringFromUtf8(
1607
+ const uint8_t *str,
1608
+ size_t length) {
1252
1609
  NodeApiScope scope{*this};
1253
1610
  return makeJsiPointer<jsi::String>(createStringUtf8(str, length));
1254
1611
  }
@@ -1263,38 +1620,51 @@ jsi::Object NodeApiJsiRuntime::createObject() {
1263
1620
  return makeJsiPointer<jsi::Object>(createNodeApiObject());
1264
1621
  }
1265
1622
 
1266
- jsi::Object NodeApiJsiRuntime::createObject(std::shared_ptr<jsi::HostObject> hostObject) {
1623
+ jsi::Object NodeApiJsiRuntime::createObject(
1624
+ std::shared_ptr<jsi::HostObject> hostObject) {
1267
1625
  NodeApiScope scope{*this};
1268
1626
  // The hostObjectHolder keeps the hostObject as external data.
1269
- // Then, the hostObjectHolder is wrapped up by a Proxy object to provide access
1270
- // to the hostObject's get, set, and getPropertyNames methods.
1271
- // There is a special symbol property ID, 'hostObjectSymbol', used to access the hostObjectWrapper from the Proxy.
1627
+ // Then, the hostObjectHolder is wrapped up by a Proxy object to provide
1628
+ // access to the hostObject's get, set, and getPropertyNames methods. There is
1629
+ // a special symbol property ID, 'hostObjectSymbol', used to access the
1630
+ // hostObjectWrapper from the Proxy.
1272
1631
  napi_value hostObjectHolder =
1273
- createExternalObject(std::make_unique<std::shared_ptr<jsi::HostObject>>(std::move(hostObject)));
1632
+ createExternalObject(std::make_unique<std::shared_ptr<jsi::HostObject>>(
1633
+ std::move(hostObject)));
1274
1634
  napi_value obj = createNodeApiObject();
1275
- setProperty(obj, getNodeApiValue(propertyId_.hostObjectSymbol), hostObjectHolder);
1635
+ setProperty(
1636
+ obj, getNodeApiValue(propertyId_.hostObjectSymbol), hostObjectHolder);
1276
1637
  if (!cachedValue_.ProxyConstructor) {
1277
1638
  cachedValue_.ProxyConstructor = makeNodeApiRef(
1278
- getProperty(getNodeApiValue(cachedValue_.Global), getNodeApiValue(propertyId_.Proxy)),
1639
+ getProperty(
1640
+ getNodeApiValue(cachedValue_.Global),
1641
+ getNodeApiValue(propertyId_.Proxy)),
1279
1642
  NodeApiPointerValueKind::Object);
1280
1643
  }
1281
1644
  napi_value args[] = {obj, getHostObjectProxyHandler()};
1282
- napi_value proxy = constructObject(getNodeApiValue(cachedValue_.ProxyConstructor), args);
1645
+ napi_value proxy =
1646
+ constructObject(getNodeApiValue(cachedValue_.ProxyConstructor), args);
1283
1647
  return makeJsiPointer<jsi::Object>(proxy);
1284
1648
  }
1285
1649
 
1286
- std::shared_ptr<jsi::HostObject> NodeApiJsiRuntime::getHostObject(const jsi::Object &obj) {
1650
+ std::shared_ptr<jsi::HostObject> NodeApiJsiRuntime::getHostObject(
1651
+ const jsi::Object &obj) {
1287
1652
  NodeApiScope scope{*this};
1288
1653
  return getJsiHostObject(getNodeApiValue(obj));
1289
1654
  }
1290
1655
 
1291
- jsi::HostFunctionType &NodeApiJsiRuntime::getHostFunction(const jsi::Function &func) {
1656
+ jsi::HostFunctionType &NodeApiJsiRuntime::getHostFunction(
1657
+ const jsi::Function &func) {
1292
1658
  NodeApiScope scope{*this};
1293
- napi_value hostFunctionHolder = getProperty(getNodeApiValue(func), getNodeApiValue((propertyId_.hostFunctionSymbol)));
1659
+ napi_value hostFunctionHolder = getProperty(
1660
+ getNodeApiValue(func), getNodeApiValue((propertyId_.hostFunctionSymbol)));
1294
1661
  if (typeOf(hostFunctionHolder) == napi_valuetype::napi_external) {
1295
- return static_cast<HostFunctionWrapper *>(getExternalData(hostFunctionHolder))->hostFunction();
1662
+ return static_cast<HostFunctionWrapper *>(
1663
+ getExternalData(hostFunctionHolder))
1664
+ ->hostFunction();
1296
1665
  } else {
1297
- throw jsi::JSINativeException("getHostFunction() can only be called with HostFunction.");
1666
+ throw jsi::JSINativeException(
1667
+ "getHostFunction() can only be called with HostFunction.");
1298
1668
  }
1299
1669
  }
1300
1670
 
@@ -1302,11 +1672,13 @@ jsi::HostFunctionType &NodeApiJsiRuntime::getHostFunction(const jsi::Function &f
1302
1672
  bool NodeApiJsiRuntime::hasNativeState(const jsi::Object &obj) {
1303
1673
  NodeApiScope scope{*this};
1304
1674
  void *nativeState{};
1305
- napi_status status = jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState);
1675
+ napi_status status =
1676
+ jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState);
1306
1677
  return status == napi_ok && nativeState != nullptr;
1307
1678
  }
1308
1679
 
1309
- std::shared_ptr<jsi::NativeState> NodeApiJsiRuntime::getNativeState(const jsi::Object &obj) {
1680
+ std::shared_ptr<jsi::NativeState> NodeApiJsiRuntime::getNativeState(
1681
+ const jsi::Object &obj) {
1310
1682
  NodeApiScope scope{*this};
1311
1683
  void *nativeState{};
1312
1684
  CHECK_NAPI(jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState));
@@ -1317,14 +1689,17 @@ std::shared_ptr<jsi::NativeState> NodeApiJsiRuntime::getNativeState(const jsi::O
1317
1689
  }
1318
1690
  }
1319
1691
 
1320
- void NodeApiJsiRuntime::setNativeState(const jsi::Object &obj, std::shared_ptr<jsi::NativeState> state) {
1692
+ void NodeApiJsiRuntime::setNativeState(
1693
+ const jsi::Object &obj,
1694
+ std::shared_ptr<jsi::NativeState> state) {
1321
1695
  NodeApiScope scope{*this};
1322
1696
  if (hasNativeState(obj)) {
1323
1697
  void *nativeState{};
1324
- CHECK_NAPI(jsrApi_->napi_remove_wrap(env_, getNodeApiValue(obj), &nativeState));
1698
+ CHECK_NAPI(
1699
+ jsrApi_->napi_remove_wrap(env_, getNodeApiValue(obj), &nativeState));
1325
1700
  if (nativeState != nullptr) {
1326
- std::shared_ptr<jsi::NativeState> oldState{
1327
- std::move(*reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(nativeState))};
1701
+ std::shared_ptr<jsi::NativeState> oldState{std::move(
1702
+ *reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(nativeState))};
1328
1703
  }
1329
1704
  }
1330
1705
 
@@ -1333,9 +1708,9 @@ void NodeApiJsiRuntime::setNativeState(const jsi::Object &obj, std::shared_ptr<j
1333
1708
  env_,
1334
1709
  getNodeApiValue(obj),
1335
1710
  new std::shared_ptr<jsi::NativeState>(std::move(state)),
1336
- [](napi_env /*env*/, void *data, void * /*finalize_hint*/) {
1337
- std::shared_ptr<jsi::NativeState> oldState{
1338
- std::move(*reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(data))};
1711
+ [](node_api_nogc_env /*env*/, void *data, void * /*finalize_hint*/) {
1712
+ std::shared_ptr<jsi::NativeState> oldState{std::move(
1713
+ *reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(data))};
1339
1714
  },
1340
1715
  nullptr,
1341
1716
  nullptr));
@@ -1343,22 +1718,30 @@ void NodeApiJsiRuntime::setNativeState(const jsi::Object &obj, std::shared_ptr<j
1343
1718
  }
1344
1719
  #endif
1345
1720
 
1346
- jsi::Value NodeApiJsiRuntime::getProperty(const jsi::Object &obj, const jsi::PropNameID &name) {
1721
+ jsi::Value NodeApiJsiRuntime::getProperty(
1722
+ const jsi::Object &obj,
1723
+ const jsi::PropNameID &name) {
1347
1724
  NodeApiScope scope{*this};
1348
1725
  return toJsiValue(getProperty(getNodeApiValue(obj), getNodeApiValue(name)));
1349
1726
  }
1350
1727
 
1351
- jsi::Value NodeApiJsiRuntime::getProperty(const jsi::Object &obj, const jsi::String &name) {
1728
+ jsi::Value NodeApiJsiRuntime::getProperty(
1729
+ const jsi::Object &obj,
1730
+ const jsi::String &name) {
1352
1731
  NodeApiScope scope{*this};
1353
1732
  return toJsiValue(getProperty(getNodeApiValue(obj), getNodeApiValue(name)));
1354
1733
  }
1355
1734
 
1356
- bool NodeApiJsiRuntime::hasProperty(const jsi::Object &obj, const jsi::PropNameID &name) {
1735
+ bool NodeApiJsiRuntime::hasProperty(
1736
+ const jsi::Object &obj,
1737
+ const jsi::PropNameID &name) {
1357
1738
  NodeApiScope scope{*this};
1358
1739
  return hasProperty(getNodeApiValue(obj), getNodeApiValue(name));
1359
1740
  }
1360
1741
 
1361
- bool NodeApiJsiRuntime::hasProperty(const jsi::Object &obj, const jsi::String &name) {
1742
+ bool NodeApiJsiRuntime::hasProperty(
1743
+ const jsi::Object &obj,
1744
+ const jsi::String &name) {
1362
1745
  NodeApiScope scope{*this};
1363
1746
  return hasProperty(getNodeApiValue(obj), getNodeApiValue(name));
1364
1747
  }
@@ -1368,7 +1751,8 @@ void NodeApiJsiRuntime::setPropertyValue(
1368
1751
  const jsi::PropNameID &name,
1369
1752
  const jsi::Value &value) {
1370
1753
  NodeApiScope scope{*this};
1371
- setProperty(getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
1754
+ setProperty(
1755
+ getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
1372
1756
  }
1373
1757
 
1374
1758
  void NodeApiJsiRuntime::setPropertyValue(
@@ -1376,7 +1760,8 @@ void NodeApiJsiRuntime::setPropertyValue(
1376
1760
  const jsi::String &name,
1377
1761
  const jsi::Value &value) {
1378
1762
  NodeApiScope scope{*this};
1379
- setProperty(getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
1763
+ setProperty(
1764
+ getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
1380
1765
  }
1381
1766
 
1382
1767
  bool NodeApiJsiRuntime::isArray(const jsi::Object &obj) const {
@@ -1398,7 +1783,8 @@ bool NodeApiJsiRuntime::isFunction(const jsi::Object &obj) const {
1398
1783
 
1399
1784
  bool NodeApiJsiRuntime::isHostObject(const jsi::Object &obj) const {
1400
1785
  NodeApiScope scope{*this};
1401
- napi_value hostObjectHolder = getProperty(getNodeApiValue(obj), getNodeApiValue(propertyId_.hostObjectSymbol));
1786
+ napi_value hostObjectHolder = getProperty(
1787
+ getNodeApiValue(obj), getNodeApiValue(propertyId_.hostObjectSymbol));
1402
1788
  if (typeOf(hostObjectHolder) == napi_valuetype::napi_external) {
1403
1789
  return getExternalData(hostObjectHolder) != nullptr;
1404
1790
  } else {
@@ -1408,7 +1794,8 @@ bool NodeApiJsiRuntime::isHostObject(const jsi::Object &obj) const {
1408
1794
 
1409
1795
  bool NodeApiJsiRuntime::isHostFunction(const jsi::Function &func) const {
1410
1796
  NodeApiScope scope{*this};
1411
- napi_value hostFunctionHolder = getProperty(getNodeApiValue(func), getNodeApiValue(propertyId_.hostFunctionSymbol));
1797
+ napi_value hostFunctionHolder = getProperty(
1798
+ getNodeApiValue(func), getNodeApiValue(propertyId_.hostFunctionSymbol));
1412
1799
  if (typeOf(hostFunctionHolder) == napi_valuetype::napi_external) {
1413
1800
  return getExternalData(hostFunctionHolder) != nullptr;
1414
1801
  } else {
@@ -1432,10 +1819,14 @@ jsi::Array NodeApiJsiRuntime::getPropertyNames(const jsi::Object &obj) {
1432
1819
  jsi::WeakObject NodeApiJsiRuntime::createWeakObject(const jsi::Object &obj) {
1433
1820
  NodeApiScope scope{*this};
1434
1821
  return make<jsi::WeakObject>(NodeApiRefCountedPointerValue::make(
1435
- *const_cast<NodeApiJsiRuntime *>(this), getNodeApiValue(obj), NodeApiPointerValueKind::WeakObject));
1822
+ *const_cast<NodeApiJsiRuntime *>(this),
1823
+ getNodeApiValue(obj),
1824
+ NodeApiPointerValueKind::WeakObject)
1825
+ .release());
1436
1826
  }
1437
1827
 
1438
- jsi::Value NodeApiJsiRuntime::lockWeakObject(JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObject) {
1828
+ jsi::Value NodeApiJsiRuntime::lockWeakObject(
1829
+ JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObject) {
1439
1830
  NodeApiScope scope{*this};
1440
1831
  napi_value value = getNodeApiValue(weakObject);
1441
1832
  if (value) {
@@ -1451,7 +1842,8 @@ jsi::Array NodeApiJsiRuntime::createArray(size_t length) {
1451
1842
  }
1452
1843
 
1453
1844
  #if JSI_VERSION >= 9
1454
- jsi::ArrayBuffer NodeApiJsiRuntime::createArrayBuffer(std::shared_ptr<jsi::MutableBuffer> buffer) {
1845
+ jsi::ArrayBuffer NodeApiJsiRuntime::createArrayBuffer(
1846
+ std::shared_ptr<jsi::MutableBuffer> buffer) {
1455
1847
  NodeApiScope scope{*this};
1456
1848
  napi_value result{};
1457
1849
  void *data = buffer->data();
@@ -1460,9 +1852,10 @@ jsi::ArrayBuffer NodeApiJsiRuntime::createArrayBuffer(std::shared_ptr<jsi::Mutab
1460
1852
  env_,
1461
1853
  data,
1462
1854
  size,
1463
- [](napi_env /*env*/, void * /*data*/, void *finalizeHint) {
1855
+ [](node_api_nogc_env /*env*/, void * /*data*/, void *finalizeHint) {
1464
1856
  std::shared_ptr<jsi::MutableBuffer> buffer{
1465
- std::move(*reinterpret_cast<std::shared_ptr<jsi::MutableBuffer> *>(finalizeHint))};
1857
+ std::move(*reinterpret_cast<std::shared_ptr<jsi::MutableBuffer> *>(
1858
+ finalizeHint))};
1466
1859
  },
1467
1860
  new std::shared_ptr<jsi::MutableBuffer>{std::move(buffer)},
1468
1861
  &result));
@@ -1478,26 +1871,38 @@ size_t NodeApiJsiRuntime::size(const jsi::Array &arr) {
1478
1871
  size_t NodeApiJsiRuntime::size(const jsi::ArrayBuffer &arrBuf) {
1479
1872
  NodeApiScope scope{*this};
1480
1873
  size_t result{};
1481
- CHECK_NAPI(jsrApi_->napi_get_arraybuffer_info(env_, getNodeApiValue(arrBuf), nullptr, &result));
1874
+ CHECK_NAPI(jsrApi_->napi_get_arraybuffer_info(
1875
+ env_, getNodeApiValue(arrBuf), nullptr, &result));
1482
1876
  return result;
1483
1877
  }
1484
1878
 
1485
1879
  uint8_t *NodeApiJsiRuntime::data(const jsi::ArrayBuffer &arrBuf) {
1486
1880
  NodeApiScope scope{*this};
1487
1881
  uint8_t *result{};
1488
- CHECK_NAPI(
1489
- jsrApi_->napi_get_arraybuffer_info(env_, getNodeApiValue(arrBuf), reinterpret_cast<void **>(&result), nullptr));
1882
+ CHECK_NAPI(jsrApi_->napi_get_arraybuffer_info(
1883
+ env_,
1884
+ getNodeApiValue(arrBuf),
1885
+ reinterpret_cast<void **>(&result),
1886
+ nullptr));
1490
1887
  return result;
1491
1888
  }
1492
1889
 
1493
- jsi::Value NodeApiJsiRuntime::getValueAtIndex(const jsi::Array &arr, size_t index) {
1890
+ jsi::Value NodeApiJsiRuntime::getValueAtIndex(
1891
+ const jsi::Array &arr,
1892
+ size_t index) {
1494
1893
  NodeApiScope scope{*this};
1495
1894
  return toJsiValue(getElement(getNodeApiValue(arr), index));
1496
1895
  }
1497
1896
 
1498
- void NodeApiJsiRuntime::setValueAtIndexImpl(JSI_CONST_10 jsi::Array &arr, size_t index, const jsi::Value &value) {
1897
+ void NodeApiJsiRuntime::setValueAtIndexImpl(
1898
+ JSI_CONST_10 jsi::Array &arr,
1899
+ size_t index,
1900
+ const jsi::Value &value) {
1499
1901
  NodeApiScope scope{*this};
1500
- setElement(getNodeApiValue(arr), static_cast<uint32_t>(index), getNodeApiValue(value));
1902
+ setElement(
1903
+ getNodeApiValue(arr),
1904
+ static_cast<uint32_t>(index),
1905
+ getNodeApiValue(value));
1501
1906
  }
1502
1907
 
1503
1908
  jsi::Function NodeApiJsiRuntime::createFunctionFromHostFunction(
@@ -1505,11 +1910,16 @@ jsi::Function NodeApiJsiRuntime::createFunctionFromHostFunction(
1505
1910
  unsigned int paramCount,
1506
1911
  jsi::HostFunctionType func) {
1507
1912
  NodeApiScope scope{*this};
1508
- auto hostFunctionWrapper = std::make_unique<HostFunctionWrapper>(std::move(func), *this);
1913
+ auto hostFunctionWrapper =
1914
+ std::make_unique<HostFunctionWrapper>(std::move(func), *this);
1509
1915
  napi_value function = createExternalFunction(
1510
- getNodeApiValue(name), static_cast<int32_t>(paramCount), jsiHostFunctionCallback, hostFunctionWrapper.get());
1916
+ getNodeApiValue(name),
1917
+ static_cast<int32_t>(paramCount),
1918
+ jsiHostFunctionCallback,
1919
+ hostFunctionWrapper.get());
1511
1920
 
1512
- const napi_value hostFunctionHolder = createExternalObject(std::move(hostFunctionWrapper));
1921
+ const napi_value hostFunctionHolder =
1922
+ createExternalObject(std::move(hostFunctionWrapper));
1513
1923
  setProperty(
1514
1924
  function,
1515
1925
  getNodeApiValue(propertyId_.hostFunctionSymbol),
@@ -1518,21 +1928,29 @@ jsi::Function NodeApiJsiRuntime::createFunctionFromHostFunction(
1518
1928
  return makeJsiPointer<jsi::Object>(function).getFunction(*this);
1519
1929
  }
1520
1930
 
1521
- jsi::Value
1522
- NodeApiJsiRuntime::call(const jsi::Function &func, const jsi::Value &jsThis, const jsi::Value *args, size_t count) {
1931
+ jsi::Value NodeApiJsiRuntime::call(
1932
+ const jsi::Function &func,
1933
+ const jsi::Value &jsThis,
1934
+ const jsi::Value *args,
1935
+ size_t count) {
1523
1936
  NodeApiScope scope{*this};
1524
1937
  return toJsiValue(callFunction(
1525
- getNodeApiValue(jsThis), getNodeApiValue(func), NodeApiValueArgs(*this, span<const jsi::Value>(args, count))));
1938
+ getNodeApiValue(jsThis),
1939
+ getNodeApiValue(func),
1940
+ NodeApiValueArgs(*this, span<const jsi::Value>(args, count))));
1526
1941
  }
1527
1942
 
1528
- jsi::Value NodeApiJsiRuntime::callAsConstructor(const jsi::Function &func, const jsi::Value *args, size_t count) {
1943
+ jsi::Value NodeApiJsiRuntime::callAsConstructor(
1944
+ const jsi::Function &func,
1945
+ const jsi::Value *args,
1946
+ size_t count) {
1529
1947
  NodeApiScope scope{*this};
1530
- return toJsiValue(
1531
- constructObject(getNodeApiValue(func), NodeApiValueArgs(*this, span<jsi::Value const>(args, count))));
1948
+ return toJsiValue(constructObject(
1949
+ getNodeApiValue(func),
1950
+ NodeApiValueArgs(*this, span<jsi::Value const>(args, count))));
1532
1951
  }
1533
1952
 
1534
1953
  jsi::Runtime::ScopeState *NodeApiJsiRuntime::pushScope() {
1535
- NodeApiEnvScope scope{getEnv()};
1536
1954
  napi_handle_scope result{};
1537
1955
  CHECK_NAPI(jsrApi_->napi_open_handle_scope(env_, &result));
1538
1956
  pushPointerValueScope();
@@ -1540,40 +1958,48 @@ jsi::Runtime::ScopeState *NodeApiJsiRuntime::pushScope() {
1540
1958
  }
1541
1959
 
1542
1960
  void NodeApiJsiRuntime::popScope(jsi::Runtime::ScopeState *state) {
1543
- NodeApiEnvScope scope{getEnv()};
1544
1961
  popPointerValueScope();
1545
- CHECK_NAPI(jsrApi_->napi_close_handle_scope(env_, reinterpret_cast<napi_handle_scope>(state)));
1962
+ CHECK_NAPI(jsrApi_->napi_close_handle_scope(
1963
+ env_, reinterpret_cast<napi_handle_scope>(state)));
1546
1964
  }
1547
1965
 
1548
- bool NodeApiJsiRuntime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const {
1966
+ bool NodeApiJsiRuntime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b)
1967
+ const {
1549
1968
  NodeApiScope scope{*this};
1550
1969
  return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1551
1970
  }
1552
1971
 
1553
1972
  #if JSI_VERSION >= 6
1554
- bool NodeApiJsiRuntime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const {
1973
+ bool NodeApiJsiRuntime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b)
1974
+ const {
1555
1975
  NodeApiScope scope{*this};
1556
1976
  return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1557
1977
  }
1558
1978
  #endif
1559
1979
 
1560
- bool NodeApiJsiRuntime::strictEquals(const jsi::String &a, const jsi::String &b) const {
1980
+ bool NodeApiJsiRuntime::strictEquals(const jsi::String &a, const jsi::String &b)
1981
+ const {
1561
1982
  NodeApiScope scope{*this};
1562
1983
  return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1563
1984
  }
1564
1985
 
1565
- bool NodeApiJsiRuntime::strictEquals(const jsi::Object &a, const jsi::Object &b) const {
1986
+ bool NodeApiJsiRuntime::strictEquals(const jsi::Object &a, const jsi::Object &b)
1987
+ const {
1566
1988
  NodeApiScope scope{*this};
1567
1989
  return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1568
1990
  }
1569
1991
 
1570
- bool NodeApiJsiRuntime::instanceOf(const jsi::Object &obj, const jsi::Function &func) {
1992
+ bool NodeApiJsiRuntime::instanceOf(
1993
+ const jsi::Object &obj,
1994
+ const jsi::Function &func) {
1571
1995
  NodeApiScope scope{*this};
1572
1996
  return instanceOf(getNodeApiValue(obj), getNodeApiValue(func));
1573
1997
  }
1574
1998
 
1575
1999
  #if JSI_VERSION >= 11
1576
- void NodeApiJsiRuntime::setExternalMemoryPressure(const jsi::Object &/*obj*/, size_t /*amount*/) {
2000
+ void NodeApiJsiRuntime::setExternalMemoryPressure(
2001
+ const jsi::Object & /*obj*/,
2002
+ size_t /*amount*/) {
1577
2003
  // TODO: implement
1578
2004
  }
1579
2005
  #endif
@@ -1582,13 +2008,20 @@ void NodeApiJsiRuntime::setExternalMemoryPressure(const jsi::Object &/*obj*/, si
1582
2008
  // NodeApiJsiRuntime::NodeApiScope implementation
1583
2009
  //=====================================================================================================================
1584
2010
 
1585
- NodeApiJsiRuntime::NodeApiScope::NodeApiScope(const NodeApiJsiRuntime &runtime) noexcept
2011
+ NodeApiJsiRuntime::NodeApiScope::NodeApiScope(
2012
+ const NodeApiJsiRuntime &runtime) noexcept
1586
2013
  : NodeApiScope(const_cast<NodeApiJsiRuntime &>(runtime)) {}
1587
2014
 
1588
- NodeApiJsiRuntime::NodeApiScope::NodeApiScope(NodeApiJsiRuntime &runtime) noexcept
1589
- : runtime_(runtime), envScope_(runtime_.getEnv()), scopeState_(runtime_.pushScope()) {}
2015
+ NodeApiJsiRuntime::NodeApiScope::NodeApiScope(
2016
+ NodeApiJsiRuntime &runtime) noexcept
2017
+ : runtime_(runtime),
2018
+ envScope_(runtime_.getEnv()),
2019
+ scopeState_(runtime_.pushScope()) {
2020
+ runtime_.pushPointerValueScope();
2021
+ }
1590
2022
 
1591
2023
  NodeApiJsiRuntime::NodeApiScope::~NodeApiScope() noexcept {
2024
+ runtime_.popPointerValueScope();
1592
2025
  runtime_.popScope(scopeState_);
1593
2026
  }
1594
2027
 
@@ -1596,12 +2029,14 @@ NodeApiJsiRuntime::NodeApiScope::~NodeApiScope() noexcept {
1596
2029
  // NodeApiJsiRuntime::NodeApiPointerValueScope implementation
1597
2030
  //=====================================================================================================================
1598
2031
 
1599
- NodeApiJsiRuntime::NodeApiPointerValueScope::NodeApiPointerValueScope(NodeApiJsiRuntime &runtime) noexcept
2032
+ NodeApiJsiRuntime::NodeApiPointerValueScope::NodeApiPointerValueScope(
2033
+ NodeApiJsiRuntime &runtime) noexcept
1600
2034
  : runtime_(runtime) {
1601
2035
  runtime_.pushPointerValueScope();
1602
2036
  }
1603
2037
 
1604
- NodeApiJsiRuntime::NodeApiPointerValueScope::~NodeApiPointerValueScope() noexcept {
2038
+ NodeApiJsiRuntime::NodeApiPointerValueScope::
2039
+ ~NodeApiPointerValueScope() noexcept {
1605
2040
  runtime_.popPointerValueScope();
1606
2041
  }
1607
2042
 
@@ -1627,19 +2062,23 @@ NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::NodeApiStackOnlyPointerValue(
1627
2062
  NodeApiPointerValueKind pointerKind) noexcept
1628
2063
  : value_(value), pointerKind_(pointerKind) {}
1629
2064
 
1630
- // Intentionally do nothing.
2065
+ // Intentionally do nothing since the value is allocated on the stack.
1631
2066
  void NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::invalidate() noexcept {}
1632
2067
 
1633
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::clone(
1634
- NodeApiJsiRuntime &runtime) const {
1635
- return NodeApiRefCountedPointerValue::make(runtime, value_, pointerKind_);
2068
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2069
+ NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::clone(
2070
+ NodeApiJsiRuntime &runtime) const noexcept {
2071
+ return NodeApiRefCountedPointerValue::make(runtime, value_, pointerKind_)
2072
+ .release();
1636
2073
  }
1637
2074
 
1638
- napi_value NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getValue(NodeApiJsiRuntime & /*runtime*/) noexcept {
2075
+ napi_value NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getValue(
2076
+ NodeApiJsiRuntime & /*runtime*/) noexcept {
1639
2077
  return value_;
1640
2078
  }
1641
2079
 
1642
- NodeApiJsiRuntime::NodeApiPointerValueKind NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getKind() const noexcept {
2080
+ NodeApiJsiRuntime::NodeApiPointerValueKind
2081
+ NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getKind() const noexcept {
1643
2082
  return pointerKind_;
1644
2083
  }
1645
2084
 
@@ -1648,41 +2087,53 @@ NodeApiJsiRuntime::NodeApiPointerValueKind NodeApiJsiRuntime::NodeApiStackOnlyPo
1648
2087
  //=====================================================================================================================
1649
2088
 
1650
2089
  NodeApiJsiRuntime::NodeApiRefCountedPointerValue::NodeApiRefCountedPointerValue(
2090
+ NodeApiJsiRuntime &runtime,
1651
2091
  napi_value value,
1652
2092
  NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
1653
2093
  int32_t initialRefCount) noexcept
1654
- : value_(value), pointerKind_(pointerKind), refCount_(initialRefCount) {}
2094
+ : pendingDeletions_(runtime.pendingDeletions_),
2095
+ value_(value),
2096
+ refCount_(initialRefCount),
2097
+ pointerKind_(pointerKind) {}
1655
2098
 
1656
- /*static*/ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefCountedPointerValue::make(
2099
+ /*static*/ NodeApiJsiRuntime::NodeApiRefHolder
2100
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue::make(
1657
2101
  NodeApiJsiRuntime &runtime,
1658
2102
  napi_value value,
1659
2103
  NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
1660
2104
  int32_t initialRefCount) {
1661
- NodeApiRefCountedPointerValue *result = new NodeApiRefCountedPointerValue(value, pointerKind, initialRefCount);
1662
- runtime.addStackValue(NodeApiStackValueHolder(result));
2105
+ NodeApiRefHolder result{
2106
+ new NodeApiRefCountedPointerValue(
2107
+ runtime, value, pointerKind, initialRefCount),
2108
+ attachTag};
2109
+ runtime.addStackValue(NodeApiStackValuePtr{result.get()});
1663
2110
  return result;
1664
2111
  }
1665
2112
 
1666
- /*static*/ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2113
+ /*static*/ NodeApiJsiRuntime::NodeApiRefHolder
1667
2114
  NodeApiJsiRuntime::NodeApiRefCountedPointerValue::makeNodeApiRef(
1668
2115
  NodeApiJsiRuntime &runtime,
1669
2116
  napi_value value,
1670
2117
  NodeApiPointerValueKind pointerKind,
1671
2118
  int32_t initialRefCount) {
1672
- return make(runtime, value, pointerKind, initialRefCount)->createNodeApiRef(runtime);
2119
+ NodeApiRefHolder result{make(runtime, value, pointerKind, initialRefCount)};
2120
+ result->createNodeApiRef(runtime);
2121
+ return result;
1673
2122
  }
1674
2123
 
1675
2124
  void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::invalidate() noexcept {
1676
2125
  decRefCount();
1677
2126
  }
1678
2127
 
1679
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefCountedPointerValue::clone(
1680
- NodeApiJsiRuntime & /*runtime*/) const {
2128
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2129
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue::clone(
2130
+ NodeApiJsiRuntime & /*runtime*/) const noexcept {
1681
2131
  incRefCount();
1682
2132
  return const_cast<NodeApiRefCountedPointerValue *>(this);
1683
2133
  }
1684
2134
 
1685
- napi_value NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getValue(NodeApiJsiRuntime &runtime) noexcept {
2135
+ napi_value NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getValue(
2136
+ NodeApiJsiRuntime &runtime) noexcept {
1686
2137
  if (value_ != nullptr) {
1687
2138
  return value_;
1688
2139
  }
@@ -1692,104 +2143,123 @@ napi_value NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getValue(NodeApiJsi
1692
2143
  }
1693
2144
 
1694
2145
  JSRuntimeApi *jsrApi = JSRuntimeApi::current();
1695
- if (pointerKind_ == NodeApiPointerValueKind::Object || pointerKind_ == NodeApiPointerValueKind::WeakObject) {
1696
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &value_));
2146
+ if (pointerKind_ == NodeApiPointerValueKind::Object ||
2147
+ pointerKind_ == NodeApiPointerValueKind::WeakObject) {
2148
+ CHECK_NAPI_ELSE_CRASH(
2149
+ jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &value_));
1697
2150
  } else {
1698
2151
  napi_value obj{};
1699
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &obj));
1700
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_named_property(runtime.getEnv(), obj, kPrimitivePropertyName, &value_));
2152
+ CHECK_NAPI_ELSE_CRASH(
2153
+ jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &obj));
2154
+ // TODO: Should we use an interned property key?
2155
+ CHECK_NAPI_ELSE_CRASH(jsrApi->napi_get_named_property(
2156
+ runtime.getEnv(), obj, kPrimitivePropertyName, &value_));
1701
2157
  }
1702
2158
 
1703
2159
  if (value_ != nullptr) {
1704
- runtime.addStackValue(NodeApiStackValueHolder(this));
1705
- incRefCount();
2160
+ runtime.addStackValue(NodeApiStackValuePtr(this));
1706
2161
  }
1707
2162
 
1708
2163
  return value_;
1709
2164
  }
1710
2165
 
1711
- NodeApiJsiRuntime::NodeApiPointerValueKind NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getKind() const noexcept {
2166
+ NodeApiJsiRuntime::NodeApiPointerValueKind
2167
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getKind() const noexcept {
1712
2168
  return pointerKind_;
1713
2169
  }
1714
2170
 
1715
- /*static*/ bool NodeApiJsiRuntime::NodeApiRefCountedPointerValue::usedByJsiPointer(
1716
- NodeApiRefCountedPointerValue *ptr) noexcept {
1717
- if (ptr == nullptr)
1718
- return false;
1719
- const int32_t internalRefCount = (ptr->value_ != nullptr ? 1 : 0) + (ptr->ref_ != nullptr ? 1 : 0);
1720
- const int32_t refCount = ptr->refCount_.load(std::memory_order_acquire);
1721
- return refCount > internalRefCount;
1722
- }
1723
-
1724
- /*static*/ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteStackValue(
1725
- NodeApiRefCountedPointerValue *ptr) noexcept {
1726
- if (ptr != nullptr && ptr->value_ != nullptr) {
1727
- ptr->value_ = nullptr;
1728
- ptr->decRefCount();
1729
- }
2171
+ bool NodeApiJsiRuntime::NodeApiRefCountedPointerValue::usedByJsiPointer()
2172
+ const noexcept {
2173
+ return !NodeApiRefCount::isZero(refCount_);
1730
2174
  }
1731
2175
 
1732
- void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::convertToNodeApiRef(NodeApiJsiRuntime &runtime) noexcept {
1733
- if (value_ == nullptr) {
2176
+ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteStackValue(
2177
+ NodeApiJsiRuntime &runtime) noexcept {
2178
+ CHECK_ELSE_CRASH(value_, "value_ must not be null");
2179
+ if (canBeDeletedFromStack_) {
2180
+ delete this;
1734
2181
  return;
1735
2182
  }
1736
2183
 
1737
- if (ref_ == nullptr && usedByJsiPointer(this)) {
2184
+ if (usedByJsiPointer() && ref_ == nullptr) {
1738
2185
  createNodeApiRef(runtime);
1739
- runtime.addRef(NodeApiRefHolder(this));
1740
- value_ = nullptr;
1741
- return;
1742
2186
  }
1743
2187
 
1744
2188
  value_ = nullptr;
1745
- decRefCount();
1746
- return;
1747
2189
  }
1748
2190
 
1749
- /*static*/ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteNodeApiRef(
1750
- NodeApiRefCountedPointerValue *ptr) noexcept {
1751
- if (ptr != nullptr && ptr->ref_ != nullptr) {
1752
- ptr->ref_ = nullptr;
1753
- ptr->decRefCount();
2191
+ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteNodeApiRef(
2192
+ NodeApiJsiRuntime &runtime) noexcept {
2193
+ if (ref_ != nullptr) {
2194
+ CHECK_NAPI_ELSE_CRASH(
2195
+ JSRuntimeApi::current()->napi_delete_reference(runtime.getEnv(), ref_));
2196
+ ref_ = nullptr;
2197
+ }
2198
+
2199
+ if (value_ != nullptr) {
2200
+ canBeDeletedFromStack_ = true;
2201
+ } else {
2202
+ delete this;
1754
2203
  }
1755
2204
  }
1756
2205
 
1757
- /*static*/ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::deleteNodeApiRef(
1758
- NodeApiRefCountedPointerValue *ptr,
1759
- NodeApiJsiRuntime &runtime) noexcept {
1760
- if (ptr != nullptr && ptr->ref_ != nullptr) {
1761
- CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_delete_reference(runtime.getEnv(), ptr->ref_));
1762
- ptr->ref_ = nullptr;
1763
- ptr->decRefCount();
2206
+ void NodeApiJsiRuntime::NodeApiStackValueDeleter::operator()(
2207
+ NodeApiRefCountedPointerValue *ptr) const noexcept {
2208
+ if (ptr == nullptr) {
2209
+ return;
2210
+ }
2211
+
2212
+ ptr->value_ = nullptr;
2213
+ if (ptr->canBeDeletedFromStack_) {
2214
+ delete ptr;
1764
2215
  }
1765
2216
  }
1766
2217
 
1767
- void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::incRefCount() const noexcept {
1768
- refCount_.fetch_add(1, std::memory_order_relaxed);
2218
+ void NodeApiJsiRuntime::NodeApiRefDeleter::operator()(
2219
+ NodeApiRefCountedPointerValue *ptr) const noexcept {
2220
+ if (ptr == nullptr) {
2221
+ return;
2222
+ }
2223
+
2224
+ if (ptr->value_ != nullptr) {
2225
+ ptr->canBeDeletedFromStack_ = true;
2226
+ } else {
2227
+ delete ptr;
2228
+ }
1769
2229
  }
1770
2230
 
1771
- void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::decRefCount() const noexcept {
1772
- int32_t count = refCount_.fetch_sub(1, std::memory_order_release) - 1;
1773
- if (count == 0) {
1774
- std::atomic_thread_fence(std::memory_order_acquire);
1775
- delete this;
2231
+ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::incRefCount()
2232
+ const noexcept {
2233
+ NodeApiRefCount::incRefCount(refCount_);
2234
+ }
2235
+
2236
+ void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::decRefCount()
2237
+ const noexcept {
2238
+ if (NodeApiRefCount::decRefCount(refCount_)) {
2239
+ pendingDeletions_->addPointerValueToDelete(
2240
+ NodeApiRefPtr(const_cast<NodeApiRefCountedPointerValue *>(this)));
1776
2241
  }
1777
2242
  }
1778
2243
 
1779
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefCountedPointerValue::createNodeApiRef(
2244
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2245
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue::createNodeApiRef(
1780
2246
  NodeApiJsiRuntime &runtime) {
1781
2247
  JSRuntimeApi *jsrApi = JSRuntimeApi::current();
1782
2248
  CHECK_ELSE_CRASH(value_ != nullptr, "value_ must not be null");
1783
2249
  CHECK_ELSE_CRASH(ref_ == nullptr, "ref_ must be null");
1784
2250
  if (pointerKind_ == NodeApiPointerValueKind::Object) {
1785
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_reference(runtime.getEnv(), value_, 1, &ref_));
2251
+ CHECK_NAPI_ELSE_CRASH(
2252
+ jsrApi->napi_create_reference(runtime.getEnv(), value_, 1, &ref_));
1786
2253
  } else if (pointerKind_ != NodeApiPointerValueKind::WeakObject) {
1787
2254
  napi_value obj{};
1788
2255
  CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_object(runtime.getEnv(), &obj));
1789
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_set_named_property(runtime.getEnv(), obj, kPrimitivePropertyName, value_));
1790
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_reference(runtime.getEnv(), obj, 1, &ref_));
2256
+ CHECK_NAPI_ELSE_CRASH(jsrApi->napi_set_named_property(
2257
+ runtime.getEnv(), obj, kPrimitivePropertyName, value_));
2258
+ CHECK_NAPI_ELSE_CRASH(
2259
+ jsrApi->napi_create_reference(runtime.getEnv(), obj, 1, &ref_));
1791
2260
  } else {
1792
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_reference(runtime.getEnv(), value_, 0, &ref_));
2261
+ CHECK_NAPI_ELSE_CRASH(
2262
+ jsrApi->napi_create_reference(runtime.getEnv(), value_, 0, &ref_));
1793
2263
  }
1794
2264
  return this;
1795
2265
  }
@@ -1799,8 +2269,10 @@ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::NodeApiRefC
1799
2269
  //=====================================================================================================================
1800
2270
 
1801
2271
  template <typename T, size_t InplaceSize>
1802
- NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::SmallBuffer(size_t size) noexcept
1803
- : size_{size}, heapData_{size_ > InplaceSize ? std::make_unique<T[]>(size_) : nullptr} {}
2272
+ NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::SmallBuffer(
2273
+ size_t size) noexcept
2274
+ : size_{size},
2275
+ heapData_{size_ > InplaceSize ? std::make_unique<T[]>(size_) : nullptr} {}
1804
2276
 
1805
2277
  template <typename T, size_t InplaceSize>
1806
2278
  T *NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::data() noexcept {
@@ -1816,7 +2288,9 @@ size_t NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::size() const noexcept {
1816
2288
  // NodeApiJsiRuntime::NodeApiValueArgs implementation
1817
2289
  //=====================================================================================================================
1818
2290
 
1819
- NodeApiJsiRuntime::NodeApiValueArgs::NodeApiValueArgs(NodeApiJsiRuntime &runtime, span<const jsi::Value> args)
2291
+ NodeApiJsiRuntime::NodeApiValueArgs::NodeApiValueArgs(
2292
+ NodeApiJsiRuntime &runtime,
2293
+ span<const jsi::Value> args)
1820
2294
  : args_{args.size()} {
1821
2295
  napi_value *jsArgs = args_.data();
1822
2296
  for (size_t i = 0; i < args.size(); ++i) {
@@ -1832,15 +2306,19 @@ NodeApiJsiRuntime::NodeApiValueArgs::operator span<napi_value>() {
1832
2306
  // NodeApiJsiRuntime::JsiValueView implementation
1833
2307
  //=====================================================================================================================
1834
2308
 
1835
- NodeApiJsiRuntime::JsiValueView::JsiValueView(NodeApiJsiRuntime *runtime, napi_value jsValue)
2309
+ NodeApiJsiRuntime::JsiValueView::JsiValueView(
2310
+ NodeApiJsiRuntime *runtime,
2311
+ napi_value jsValue)
1836
2312
  : value_{initValue(runtime, jsValue, std::addressof(pointerStore_))} {}
1837
2313
 
1838
2314
  NodeApiJsiRuntime::JsiValueView::operator const jsi::Value &() const noexcept {
1839
2315
  return value_;
1840
2316
  }
1841
2317
 
1842
- /*static*/ jsi::Value
1843
- NodeApiJsiRuntime::JsiValueView::initValue(NodeApiJsiRuntime *runtime, napi_value value, StoreType *store) {
2318
+ /*static*/ jsi::Value NodeApiJsiRuntime::JsiValueView::initValue(
2319
+ NodeApiJsiRuntime *runtime,
2320
+ napi_value value,
2321
+ StoreType *store) {
1844
2322
  switch (runtime->typeOf(value)) {
1845
2323
  case napi_valuetype::napi_undefined:
1846
2324
  return jsi::Value::undefined();
@@ -1851,16 +2329,20 @@ NodeApiJsiRuntime::JsiValueView::initValue(NodeApiJsiRuntime *runtime, napi_valu
1851
2329
  case napi_valuetype::napi_number:
1852
2330
  return jsi::Value{runtime->getValueDouble(value)};
1853
2331
  case napi_valuetype::napi_string:
1854
- return make<jsi::String>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::String));
2332
+ return make<jsi::String>(new (store) NodeApiStackOnlyPointerValue(
2333
+ value, NodeApiPointerValueKind::String));
1855
2334
  case napi_valuetype::napi_symbol:
1856
- return make<jsi::Symbol>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::Symbol));
2335
+ return make<jsi::Symbol>(new (store) NodeApiStackOnlyPointerValue(
2336
+ value, NodeApiPointerValueKind::Symbol));
1857
2337
  case napi_valuetype::napi_object:
1858
2338
  case napi_valuetype::napi_function:
1859
2339
  case napi_valuetype::napi_external:
1860
- return make<jsi::Object>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::Object));
2340
+ return make<jsi::Object>(new (store) NodeApiStackOnlyPointerValue(
2341
+ value, NodeApiPointerValueKind::Object));
1861
2342
  #if JSI_VERSION >= 8
1862
2343
  case napi_valuetype::napi_bigint:
1863
- return make<jsi::BigInt>(new (store) NodeApiStackOnlyPointerValue(value, NodeApiPointerValueKind::BigInt));
2344
+ return make<jsi::BigInt>(new (store) NodeApiStackOnlyPointerValue(
2345
+ value, NodeApiPointerValueKind::BigInt));
1864
2346
  #endif
1865
2347
  default:
1866
2348
  throw jsi::JSINativeException("Unexpected value type");
@@ -1871,12 +2353,15 @@ NodeApiJsiRuntime::JsiValueView::initValue(NodeApiJsiRuntime *runtime, napi_valu
1871
2353
  // NodeApiJsiRuntime::JsiValueViewArgs implementation
1872
2354
  //=====================================================================================================================
1873
2355
 
1874
- NodeApiJsiRuntime::JsiValueViewArgs::JsiValueViewArgs(NodeApiJsiRuntime *runtime, span<napi_value> args) noexcept
2356
+ NodeApiJsiRuntime::JsiValueViewArgs::JsiValueViewArgs(
2357
+ NodeApiJsiRuntime *runtime,
2358
+ span<napi_value> args) noexcept
1875
2359
  : pointerStore_{args.size()}, args_{args.size()} {
1876
2360
  JsiValueView::StoreType *pointerStore = pointerStore_.data();
1877
2361
  jsi::Value *jsiArgs = args_.data();
1878
2362
  for (size_t i = 0; i < args_.size(); ++i) {
1879
- jsiArgs[i] = JsiValueView::initValue(runtime, args[i], std::addressof(pointerStore[i]));
2363
+ jsiArgs[i] = JsiValueView::initValue(
2364
+ runtime, args[i], std::addressof(pointerStore[i]));
1880
2365
  }
1881
2366
  }
1882
2367
 
@@ -1893,11 +2378,16 @@ size_t NodeApiJsiRuntime::JsiValueViewArgs::size() const noexcept {
1893
2378
  //=====================================================================================================================
1894
2379
 
1895
2380
  // TODO: account for symbol
1896
- NodeApiJsiRuntime::PropNameIDView::PropNameIDView(NodeApiJsiRuntime * /*runtime*/, napi_value propertyId) noexcept
1897
- : propertyId_{make<jsi::PropNameID>(new(std::addressof(
1898
- pointerStore_)) NodeApiStackOnlyPointerValue(propertyId, NodeApiPointerValueKind::StringPropNameID))} {}
1899
-
1900
- NodeApiJsiRuntime::PropNameIDView::operator jsi::PropNameID const &() const noexcept {
2381
+ NodeApiJsiRuntime::PropNameIDView::PropNameIDView(
2382
+ NodeApiJsiRuntime * /*runtime*/,
2383
+ napi_value propertyId) noexcept
2384
+ : propertyId_{make<jsi::PropNameID>(
2385
+ new(std::addressof(pointerStore_)) NodeApiStackOnlyPointerValue(
2386
+ propertyId,
2387
+ NodeApiPointerValueKind::StringPropNameID))} {}
2388
+
2389
+ NodeApiJsiRuntime::PropNameIDView::operator jsi::PropNameID const &()
2390
+ const noexcept {
1901
2391
  return propertyId_;
1902
2392
  }
1903
2393
 
@@ -1905,10 +2395,13 @@ NodeApiJsiRuntime::PropNameIDView::operator jsi::PropNameID const &() const noex
1905
2395
  // NodeApiJsiRuntime::HostFunctionWrapper implementation
1906
2396
  //=====================================================================================================================
1907
2397
 
1908
- NodeApiJsiRuntime::HostFunctionWrapper::HostFunctionWrapper(jsi::HostFunctionType &&type, NodeApiJsiRuntime &runtime)
2398
+ NodeApiJsiRuntime::HostFunctionWrapper::HostFunctionWrapper(
2399
+ jsi::HostFunctionType &&type,
2400
+ NodeApiJsiRuntime &runtime)
1909
2401
  : hostFunction_{std::move(type)}, runtime_{runtime} {}
1910
2402
 
1911
- jsi::HostFunctionType &NodeApiJsiRuntime::HostFunctionWrapper::hostFunction() noexcept {
2403
+ jsi::HostFunctionType &
2404
+ NodeApiJsiRuntime::HostFunctionWrapper::hostFunction() noexcept {
1912
2405
  return hostFunction_;
1913
2406
  }
1914
2407
 
@@ -1928,24 +2421,35 @@ jsi::JSError NodeApiJsiRuntime::makeJSError(Args &&...args) {
1928
2421
  }
1929
2422
 
1930
2423
  // Throws jsi::JSError or jsi::JSINativeException from Node-API error.
1931
- [[noreturn]] void NodeApiJsiRuntime::throwJSException(napi_status status) const {
2424
+ [[noreturn]] void NodeApiJsiRuntime::throwJSException(
2425
+ napi_status status) const {
1932
2426
  napi_value jsError{};
1933
- CHECK_NAPI_ELSE_CRASH(jsrApi_->napi_get_and_clear_last_exception(env_, &jsError));
2427
+ CHECK_NAPI_ELSE_CRASH(
2428
+ jsrApi_->napi_get_and_clear_last_exception(env_, &jsError));
2429
+ napi_valuetype jsErrorType;
2430
+ CHECK_NAPI_ELSE_CRASH(jsrApi_->napi_typeof(env_, jsError, &jsErrorType));
1934
2431
 
1935
2432
  if (!hasPendingJSError_ &&
1936
- (status == napi_pending_exception || instanceOf(jsError, getNodeApiValue(cachedValue_.Error)))) {
1937
- AutoRestore<bool> setValue(const_cast<NodeApiJsiRuntime *>(this)->hasPendingJSError_, true);
1938
- rewriteErrorMessage(jsError);
1939
- throw jsi::JSError(*const_cast<NodeApiJsiRuntime *>(this), toJsiValue(jsError));
2433
+ (status == napi_pending_exception || jsErrorType != napi_undefined)) {
2434
+ AutoRestore<bool> setValue(
2435
+ const_cast<NodeApiJsiRuntime *>(this)->hasPendingJSError_, true);
2436
+ if (jsErrorType == napi_object &&
2437
+ instanceOf(jsError, getNodeApiValue(cachedValue_.Error))) {
2438
+ rewriteErrorMessage(jsError);
2439
+ }
2440
+ throw jsi::JSError(
2441
+ *const_cast<NodeApiJsiRuntime *>(this), toJsiValue(jsError));
1940
2442
  } else {
1941
2443
  std::ostringstream errorStream;
1942
- errorStream << "A call to Node-API returned error code 0x" << std::hex << status << '.';
2444
+ errorStream << "A call to Node-API returned error code 0x" << std::hex
2445
+ << status << '.';
1943
2446
  throw jsi::JSINativeException(errorStream.str().c_str());
1944
2447
  }
1945
2448
  }
1946
2449
 
1947
2450
  // Throws jsi::JSINativeException with a message.
1948
- [[noreturn]] void NodeApiJsiRuntime::throwNativeException(char const *errorMessage) const {
2451
+ [[noreturn]] void NodeApiJsiRuntime::throwNativeException(
2452
+ char const *errorMessage) const {
1949
2453
  throw jsi::JSINativeException(errorMessage);
1950
2454
  }
1951
2455
 
@@ -1954,9 +2458,11 @@ void NodeApiJsiRuntime::rewriteErrorMessage(napi_value jsError) const {
1954
2458
  // The code below must work correctly even if the 'message' getter throws.
1955
2459
  // In case when it throws, we ignore that exception.
1956
2460
  napi_value message{};
1957
- napi_status status = jsrApi_->napi_get_property(env_, jsError, getNodeApiValue(propertyId_.message), &message);
2461
+ napi_status status = jsrApi_->napi_get_property(
2462
+ env_, jsError, getNodeApiValue(propertyId_.message), &message);
1958
2463
  if (status != napi_ok) {
1959
- // If the 'message' property getter throws, then we clear the exception and ignore it.
2464
+ // If the 'message' property getter throws, then we clear the exception and
2465
+ // ignore it.
1960
2466
  napi_value ignoreJSError{};
1961
2467
  jsrApi_->napi_get_and_clear_last_exception(env_, &ignoreJSError);
1962
2468
  } else if (typeOf(message) == napi_string) {
@@ -1972,9 +2478,11 @@ void NodeApiJsiRuntime::rewriteErrorMessage(napi_value jsError) const {
1972
2478
  // Make sure that the call stack has the current URL
1973
2479
  if (!sourceURL_.empty()) {
1974
2480
  napi_value stack{};
1975
- status = jsrApi_->napi_get_property(env_, jsError, getNodeApiValue(propertyId_.stack), &stack);
2481
+ status = jsrApi_->napi_get_property(
2482
+ env_, jsError, getNodeApiValue(propertyId_.stack), &stack);
1976
2483
  if (status != napi_ok) {
1977
- // If the 'stack' property getter throws, then we clear the exception and ignore it.
2484
+ // If the 'stack' property getter throws, then we clear the exception and
2485
+ // ignore it.
1978
2486
  napi_value ignoreJSError{};
1979
2487
  jsrApi_->napi_get_and_clear_last_exception(env_, &ignoreJSError);
1980
2488
  } else if (typeOf(message) == napi_string) {
@@ -1982,7 +2490,10 @@ void NodeApiJsiRuntime::rewriteErrorMessage(napi_value jsError) const {
1982
2490
  std::string stackStr = stringToStdString(stack);
1983
2491
  if (stackStr.find(sourceURL_) == std::string::npos) {
1984
2492
  stackStr += sourceURL_ + '\n' + stackStr;
1985
- setProperty(jsError, getNodeApiValue(propertyId_.stack), createStringUtf8(stackStr.c_str()));
2493
+ setProperty(
2494
+ jsError,
2495
+ getNodeApiValue(propertyId_.stack),
2496
+ createStringUtf8(stackStr.c_str()));
1986
2497
  }
1987
2498
  }
1988
2499
  }
@@ -1990,21 +2501,26 @@ void NodeApiJsiRuntime::rewriteErrorMessage(napi_value jsError) const {
1990
2501
 
1991
2502
  // Evaluates lambda and augments exception messages with the method's name.
1992
2503
  template <typename TLambda>
1993
- auto NodeApiJsiRuntime::runInMethodContext(char const *methodName, TLambda lambda) {
2504
+ auto NodeApiJsiRuntime::runInMethodContext(
2505
+ char const *methodName,
2506
+ TLambda lambda) {
1994
2507
  try {
1995
2508
  return lambda();
1996
2509
  } catch (jsi::JSError const &) {
1997
2510
  throw; // do not augment the JSError exceptions.
1998
2511
  } catch (std::exception const &ex) {
1999
- throwNativeException((std::string{"Exception in "} + methodName + ": " + ex.what()).c_str());
2512
+ throwNativeException(
2513
+ (std::string{"Exception in "} + methodName + ": " + ex.what()).c_str());
2000
2514
  } catch (...) {
2001
- throwNativeException((std::string{"Exception in "} + methodName + ": <unknown>").c_str());
2515
+ throwNativeException(
2516
+ (std::string{"Exception in "} + methodName + ": <unknown>").c_str());
2002
2517
  }
2003
2518
  }
2004
2519
 
2005
- // Evaluates lambda and converts all exceptions to NAPI errors.
2520
+ // Evaluates lambda and converts all exceptions to Node-API errors.
2006
2521
  template <typename TLambda>
2007
- napi_value NodeApiJsiRuntime::handleCallbackExceptions(TLambda lambda) const noexcept {
2522
+ napi_value NodeApiJsiRuntime::handleCallbackExceptions(
2523
+ TLambda lambda) const noexcept {
2008
2524
  try {
2009
2525
  try {
2010
2526
  return lambda();
@@ -2021,16 +2537,17 @@ napi_value NodeApiJsiRuntime::handleCallbackExceptions(TLambda lambda) const noe
2021
2537
  return getUndefined();
2022
2538
  }
2023
2539
 
2024
- // Throws JavaScript exception using NAPI.
2540
+ // Throws JavaScript exception using Node-API.
2025
2541
  bool NodeApiJsiRuntime::setException(napi_value error) const noexcept {
2026
2542
  // This method must not throw. We return false in case of error.
2027
2543
  return jsrApi_->napi_throw(env_, error) == napi_status::napi_ok;
2028
2544
  }
2029
2545
 
2030
- // Throws JavaScript error exception with the provided message using NAPI.
2546
+ // Throws JavaScript error exception with the provided message using Node-API.
2031
2547
  bool NodeApiJsiRuntime::setException(std::string_view message) const noexcept {
2032
2548
  // This method must not throw. We return false in case of error.
2033
- return jsrApi_->napi_throw_error(env_, "Unknown", message.data()) == napi_status::napi_ok;
2549
+ return jsrApi_->napi_throw_error(env_, "Unknown", message.data()) ==
2550
+ napi_status::napi_ok;
2034
2551
  }
2035
2552
 
2036
2553
  // Gets type of the napi_value.
@@ -2110,12 +2627,13 @@ double NodeApiJsiRuntime::getValueDouble(napi_value value) const {
2110
2627
  return result;
2111
2628
  }
2112
2629
 
2113
- // Creates a napi_value string from the extended ASCII symbols that correspond to the Latin1 encoding.
2114
- // Each character is a byte-sized value from 0 to 255.
2630
+ // Creates a napi_value string from the extended ASCII symbols that correspond
2631
+ // to the Latin1 encoding. Each character is a byte-sized value from 0 to 255.
2115
2632
  napi_value NodeApiJsiRuntime::createStringLatin1(std::string_view value) const {
2116
2633
  CHECK_ELSE_THROW(value.data(), "Cannot convert a nullptr to a JS string.");
2117
2634
  napi_value result{};
2118
- CHECK_NAPI(jsrApi_->napi_create_string_latin1(env_, value.data(), value.size(), &result));
2635
+ CHECK_NAPI(jsrApi_->napi_create_string_latin1(
2636
+ env_, value.data(), value.size(), &result));
2119
2637
  return result;
2120
2638
  }
2121
2639
 
@@ -2123,12 +2641,16 @@ napi_value NodeApiJsiRuntime::createStringLatin1(std::string_view value) const {
2123
2641
  napi_value NodeApiJsiRuntime::createStringUtf8(std::string_view value) const {
2124
2642
  CHECK_ELSE_THROW(value.data(), "Cannot convert a nullptr to a JS string.");
2125
2643
  napi_value result{};
2126
- CHECK_NAPI(jsrApi_->napi_create_string_utf8(env_, value.data(), value.size(), &result));
2644
+ CHECK_NAPI(jsrApi_->napi_create_string_utf8(
2645
+ env_, value.data(), value.size(), &result));
2127
2646
  return result;
2128
2647
  }
2129
2648
 
2130
- // Creates a napi_value string from a UTF-8 string. Use data and length instead of string_view.
2131
- napi_value NodeApiJsiRuntime::createStringUtf8(const uint8_t *data, size_t length) const {
2649
+ // Creates a napi_value string from a UTF-8 string. Use data and length instead
2650
+ // of string_view.
2651
+ napi_value NodeApiJsiRuntime::createStringUtf8(
2652
+ const uint8_t *data,
2653
+ size_t length) const {
2132
2654
  return createStringUtf8({reinterpret_cast<const char *>(data), length});
2133
2655
  }
2134
2656
 
@@ -2139,23 +2661,29 @@ std::string NodeApiJsiRuntime::stringToStdString(napi_value stringValue) const {
2139
2661
  typeOf(stringValue) == napi_valuetype::napi_string,
2140
2662
  "Cannot convert a non JS string Node-API Value to a std::string.");
2141
2663
  size_t strLength{};
2142
- CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(env_, stringValue, nullptr, 0, &strLength));
2664
+ CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(
2665
+ env_, stringValue, nullptr, 0, &strLength));
2143
2666
  result.assign(strLength, '\0');
2144
2667
  size_t copiedLength{};
2145
- CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(env_, stringValue, &result[0], result.length() + 1, &copiedLength));
2668
+ CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(
2669
+ env_, stringValue, &result[0], result.length() + 1, &copiedLength));
2146
2670
  CHECK_ELSE_THROW(result.length() == copiedLength, "Unexpected string length");
2147
2671
  return result;
2148
2672
  }
2149
2673
 
2150
2674
  // Gets or creates a unique string value from an UTF-8 string_view.
2151
- napi_value NodeApiJsiRuntime::getPropertyIdFromName(std::string_view value) const {
2675
+ napi_value NodeApiJsiRuntime::getPropertyIdFromName(
2676
+ std::string_view value) const {
2152
2677
  napi_value result{};
2153
- CHECK_NAPI(jsrApi_->napi_create_string_utf8(env_, value.data(), value.size(), &result));
2678
+ CHECK_NAPI(jsrApi_->napi_create_string_utf8(
2679
+ env_, value.data(), value.size(), &result));
2154
2680
  return result;
2155
2681
  }
2156
2682
 
2157
2683
  // Gets or creates a unique string value from an UTF-8 data/length range.
2158
- napi_value NodeApiJsiRuntime::getPropertyIdFromName(const uint8_t *data, size_t length) const {
2684
+ napi_value NodeApiJsiRuntime::getPropertyIdFromName(
2685
+ const uint8_t *data,
2686
+ size_t length) const {
2159
2687
  return getPropertyIdFromName({reinterpret_cast<const char *>(data), length});
2160
2688
  }
2161
2689
 
@@ -2179,7 +2707,8 @@ std::string NodeApiJsiRuntime::propertyIdToStdString(napi_value propertyId) {
2179
2707
  }
2180
2708
 
2181
2709
  // Creates a JavaScript symbol napi_value.
2182
- napi_value NodeApiJsiRuntime::createSymbol(std::string_view symbolDescription) const {
2710
+ napi_value NodeApiJsiRuntime::createSymbol(
2711
+ std::string_view symbolDescription) const {
2183
2712
  napi_value result{};
2184
2713
  napi_value description = createStringUtf8(symbolDescription);
2185
2714
  CHECK_NAPI(jsrApi_->napi_create_symbol(env_, description, &result));
@@ -2189,31 +2718,44 @@ napi_value NodeApiJsiRuntime::createSymbol(std::string_view symbolDescription) c
2189
2718
  // Calls Symbol.toString() and returns it as std::string.
2190
2719
  std::string NodeApiJsiRuntime::symbolToStdString(napi_value symbolValue) {
2191
2720
  if (!cachedValue_.SymbolToString) {
2192
- napi_value symbolCtor = getProperty(getNodeApiValue(cachedValue_.Global), getNodeApiValue(propertyId_.Symbol));
2193
- napi_value symbolPrototype = getProperty(symbolCtor, getNodeApiValue(propertyId_.prototype));
2721
+ napi_value symbolCtor = getProperty(
2722
+ getNodeApiValue(cachedValue_.Global),
2723
+ getNodeApiValue(propertyId_.Symbol));
2724
+ napi_value symbolPrototype =
2725
+ getProperty(symbolCtor, getNodeApiValue(propertyId_.prototype));
2194
2726
  cachedValue_.SymbolToString = makeNodeApiRef(
2195
- getProperty(symbolPrototype, getNodeApiValue(propertyId_.toString)), NodeApiPointerValueKind::Object);
2727
+ getProperty(symbolPrototype, getNodeApiValue(propertyId_.toString)),
2728
+ NodeApiPointerValueKind::Object);
2196
2729
  }
2197
- napi_value jsString = callFunction(symbolValue, getNodeApiValue(cachedValue_.SymbolToString), {});
2730
+ napi_value jsString = callFunction(
2731
+ symbolValue, getNodeApiValue(cachedValue_.SymbolToString), {});
2198
2732
  return stringToStdString(jsString);
2199
2733
  }
2200
2734
 
2201
2735
  // Calls a JavaScript function.
2202
- napi_value NodeApiJsiRuntime::callFunction(napi_value thisArg, napi_value function, span<napi_value> args) const {
2736
+ napi_value NodeApiJsiRuntime::callFunction(
2737
+ napi_value thisArg,
2738
+ napi_value function,
2739
+ span<napi_value> args) const {
2203
2740
  napi_value result{};
2204
- CHECK_NAPI(jsrApi_->napi_call_function(env_, thisArg, function, args.size(), args.data(), &result));
2741
+ CHECK_NAPI(jsrApi_->napi_call_function(
2742
+ env_, thisArg, function, args.size(), args.data(), &result));
2205
2743
  return result;
2206
2744
  }
2207
2745
 
2208
2746
  // Constructs a new JavaScript Object using a constructor function.
2209
- napi_value NodeApiJsiRuntime::constructObject(napi_value constructor, span<napi_value> args) const {
2747
+ napi_value NodeApiJsiRuntime::constructObject(
2748
+ napi_value constructor,
2749
+ span<napi_value> args) const {
2210
2750
  napi_value result{};
2211
- CHECK_NAPI(jsrApi_->napi_new_instance(env_, constructor, args.size(), args.data(), &result));
2751
+ CHECK_NAPI(jsrApi_->napi_new_instance(
2752
+ env_, constructor, args.size(), args.data(), &result));
2212
2753
  return result;
2213
2754
  }
2214
2755
 
2215
2756
  // Returns true if object was constructed using the provided constructor.
2216
- bool NodeApiJsiRuntime::instanceOf(napi_value object, napi_value constructor) const {
2757
+ bool NodeApiJsiRuntime::instanceOf(napi_value object, napi_value constructor)
2758
+ const {
2217
2759
  bool result{false};
2218
2760
  CHECK_NAPI(jsrApi_->napi_instanceof(env_, object, constructor, &result));
2219
2761
  return result;
@@ -2227,25 +2769,32 @@ napi_value NodeApiJsiRuntime::createNodeApiObject() const {
2227
2769
  }
2228
2770
 
2229
2771
  // Returns true if the object has a property with the provided property ID.
2230
- bool NodeApiJsiRuntime::hasProperty(napi_value object, napi_value propertyId) const {
2772
+ bool NodeApiJsiRuntime::hasProperty(napi_value object, napi_value propertyId)
2773
+ const {
2231
2774
  bool result{};
2232
2775
  CHECK_NAPI(jsrApi_->napi_has_property(env_, object, propertyId, &result));
2233
2776
  return result;
2234
2777
  }
2235
2778
 
2236
2779
  // Gets object property value.
2237
- napi_value NodeApiJsiRuntime::getProperty(napi_value object, napi_value propertyId) const {
2780
+ napi_value NodeApiJsiRuntime::getProperty(
2781
+ napi_value object,
2782
+ napi_value propertyId) const {
2238
2783
  napi_value result{};
2239
2784
  CHECK_NAPI(jsrApi_->napi_get_property(env_, object, propertyId, &result));
2240
2785
  return result;
2241
2786
  }
2242
2787
 
2243
2788
  // Sets object property value.
2244
- void NodeApiJsiRuntime::setProperty(napi_value object, napi_value propertyId, napi_value value) const {
2789
+ void NodeApiJsiRuntime::setProperty(
2790
+ napi_value object,
2791
+ napi_value propertyId,
2792
+ napi_value value) const {
2245
2793
  CHECK_NAPI(jsrApi_->napi_set_property(env_, object, propertyId, value));
2246
2794
  }
2247
2795
 
2248
- // Sets object property value with the provided property accessibility attributes.
2796
+ // Sets object property value with the provided property accessibility
2797
+ // attributes.
2249
2798
  void NodeApiJsiRuntime::setProperty(
2250
2799
  napi_value object,
2251
2800
  napi_value propertyId,
@@ -2279,41 +2828,55 @@ size_t NodeApiJsiRuntime::getArrayLength(napi_value value) const {
2279
2828
 
2280
2829
  napi_value NodeApiJsiRuntime::getElement(napi_value arr, size_t index) const {
2281
2830
  napi_value result{};
2282
- CHECK_NAPI(jsrApi_->napi_get_element(env_, arr, static_cast<int32_t>(index), &result));
2831
+ CHECK_NAPI(jsrApi_->napi_get_element(
2832
+ env_, arr, static_cast<int32_t>(index), &result));
2283
2833
  return result;
2284
2834
  }
2285
2835
 
2286
2836
  // Sets array element.
2287
- void NodeApiJsiRuntime::setElement(napi_value array, uint32_t index, napi_value value) const {
2837
+ void NodeApiJsiRuntime::setElement(
2838
+ napi_value array,
2839
+ uint32_t index,
2840
+ napi_value value) const {
2288
2841
  CHECK_NAPI(jsrApi_->napi_set_element(env_, array, index, value));
2289
2842
  }
2290
2843
 
2291
- // The NAPI external function callback used for the JSI host function implementation.
2844
+ // The Node-API external function callback used for the JSI host function
2845
+ // implementation.
2292
2846
  /*static*/ napi_value __cdecl NodeApiJsiRuntime::jsiHostFunctionCallback(
2293
2847
  napi_env env,
2294
2848
  napi_callback_info info) noexcept {
2295
2849
  HostFunctionWrapper *hostFuncWrapper{};
2296
2850
  size_t argc{};
2297
2851
  CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
2298
- env, info, &argc, nullptr, nullptr, reinterpret_cast<void **>(&hostFuncWrapper)));
2852
+ env,
2853
+ info,
2854
+ &argc,
2855
+ nullptr,
2856
+ nullptr,
2857
+ reinterpret_cast<void **>(&hostFuncWrapper)));
2299
2858
  CHECK_ELSE_CRASH(hostFuncWrapper, "Cannot find the host function");
2300
2859
  NodeApiJsiRuntime &runtime = hostFuncWrapper->runtime();
2301
2860
  NodeApiPointerValueScope scope{runtime};
2302
2861
 
2303
- return runtime.handleCallbackExceptions([&env, &info, &argc, &runtime, &hostFuncWrapper]() {
2304
- SmallBuffer<napi_value, MaxStackArgCount> napiArgs(argc);
2305
- napi_value thisArg{};
2306
- CHECK_NAPI_ELSE_CRASH(
2307
- JSRuntimeApi::current()->napi_get_cb_info(env, info, &argc, napiArgs.data(), &thisArg, nullptr));
2308
- CHECK_ELSE_CRASH(napiArgs.size() == argc, "Wrong argument count");
2309
- const JsiValueView jsiThisArg{&runtime, thisArg};
2310
- JsiValueViewArgs jsiArgs(&runtime, span<napi_value>(napiArgs.data(), napiArgs.size()));
2311
-
2312
- const jsi::HostFunctionType &hostFunc = hostFuncWrapper->hostFunction();
2313
- return runtime.runInMethodContext("HostFunction", [&hostFunc, &runtime, &jsiThisArg, &jsiArgs]() {
2314
- return runtime.getNodeApiValue(hostFunc(runtime, jsiThisArg, jsiArgs.data(), jsiArgs.size()));
2315
- });
2316
- });
2862
+ return runtime.handleCallbackExceptions(
2863
+ [&env, &info, &argc, &runtime, &hostFuncWrapper]() {
2864
+ SmallBuffer<napi_value, MaxStackArgCount> napiArgs(argc);
2865
+ napi_value thisArg{};
2866
+ CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
2867
+ env, info, &argc, napiArgs.data(), &thisArg, nullptr));
2868
+ CHECK_ELSE_CRASH(napiArgs.size() == argc, "Wrong argument count");
2869
+ const JsiValueView jsiThisArg{&runtime, thisArg};
2870
+ JsiValueViewArgs jsiArgs(
2871
+ &runtime, span<napi_value>(napiArgs.data(), napiArgs.size()));
2872
+
2873
+ const jsi::HostFunctionType &hostFunc = hostFuncWrapper->hostFunction();
2874
+ return runtime.runInMethodContext(
2875
+ "HostFunction", [&hostFunc, &runtime, &jsiThisArg, &jsiArgs]() {
2876
+ return runtime.getNodeApiValue(hostFunc(
2877
+ runtime, jsiThisArg, jsiArgs.data(), jsiArgs.size()));
2878
+ });
2879
+ });
2317
2880
  }
2318
2881
 
2319
2882
  // Creates an external function.
@@ -2324,25 +2887,39 @@ napi_value NodeApiJsiRuntime::createExternalFunction(
2324
2887
  void *callbackData) {
2325
2888
  std::string funcName = stringToStdString(name);
2326
2889
  napi_value function{};
2327
- CHECK_NAPI(
2328
- jsrApi_->napi_create_function(env_, funcName.data(), funcName.length(), callback, callbackData, &function));
2890
+ CHECK_NAPI(jsrApi_->napi_create_function(
2891
+ env_,
2892
+ funcName.data(),
2893
+ funcName.length(),
2894
+ callback,
2895
+ callbackData,
2896
+ &function));
2329
2897
  setProperty(
2330
- function, getNodeApiValue(propertyId_.length), createInt32(paramCount), napi_property_attributes::napi_default);
2898
+ function,
2899
+ getNodeApiValue(propertyId_.length),
2900
+ createInt32(paramCount),
2901
+ napi_property_attributes::napi_default);
2331
2902
 
2332
2903
  return function;
2333
2904
  }
2334
2905
 
2335
2906
  // Creates an object that wraps up external data.
2336
- napi_value NodeApiJsiRuntime::createExternalObject(void *data, napi_finalize finalizeCallback) const {
2907
+ napi_value NodeApiJsiRuntime::createExternalObject(
2908
+ void *data,
2909
+ node_api_nogc_finalize finalizeCallback) const {
2337
2910
  napi_value result{};
2338
- CHECK_NAPI(jsrApi_->napi_create_external(env_, data, finalizeCallback, nullptr, &result));
2911
+ CHECK_NAPI(jsrApi_->napi_create_external(
2912
+ env_, data, finalizeCallback, nullptr, &result));
2339
2913
  return result;
2340
2914
  }
2341
2915
 
2342
2916
  // Wraps up std::unique_ptr as an external object.
2343
2917
  template <typename T>
2344
- napi_value NodeApiJsiRuntime::createExternalObject(std::unique_ptr<T> &&data) const {
2345
- napi_finalize finalize = [](napi_env /*env*/, void *dataToDestroy, void * /*finalizerHint*/) {
2918
+ napi_value NodeApiJsiRuntime::createExternalObject(
2919
+ std::unique_ptr<T> &&data) const {
2920
+ node_api_nogc_finalize finalize = [](node_api_nogc_env /*env*/,
2921
+ void *dataToDestroy,
2922
+ void * /*finalizerHint*/) {
2346
2923
  // We wrap dataToDestroy in a unique_ptr to avoid calling delete explicitly.
2347
2924
  std::unique_ptr<T> dataDeleter{static_cast<T *>(dataToDestroy)};
2348
2925
  };
@@ -2363,8 +2940,10 @@ void *NodeApiJsiRuntime::getExternalData(napi_value object) const {
2363
2940
  }
2364
2941
 
2365
2942
  // Gets JSI host object wrapped into a napi_value object.
2366
- const std::shared_ptr<jsi::HostObject> &NodeApiJsiRuntime::getJsiHostObject(napi_value obj) {
2367
- const napi_value hostObjectHolder = getProperty(obj, getNodeApiValue(propertyId_.hostObjectSymbol));
2943
+ const std::shared_ptr<jsi::HostObject> &NodeApiJsiRuntime::getJsiHostObject(
2944
+ napi_value obj) {
2945
+ const napi_value hostObjectHolder =
2946
+ getProperty(obj, getNodeApiValue(propertyId_.hostObjectSymbol));
2368
2947
 
2369
2948
  if (typeOf(hostObjectHolder) == napi_valuetype::napi_external) {
2370
2949
  if (void *data = getExternalData(hostObjectHolder)) {
@@ -2379,34 +2958,53 @@ const std::shared_ptr<jsi::HostObject> &NodeApiJsiRuntime::getJsiHostObject(napi
2379
2958
  napi_value NodeApiJsiRuntime::getHostObjectProxyHandler() {
2380
2959
  if (!cachedValue_.HostObjectProxyHandler) {
2381
2960
  const napi_value handler = createNodeApiObject();
2382
- setProxyTrap<&NodeApiJsiRuntime::hostObjectHasTrap, 2>(handler, getNodeApiValue(propertyId_.has));
2383
- setProxyTrap<&NodeApiJsiRuntime::hostObjectGetTrap, 3>(handler, getNodeApiValue(propertyId_.get));
2384
- setProxyTrap<&NodeApiJsiRuntime::hostObjectSetTrap, 4>(handler, getNodeApiValue(propertyId_.set));
2385
- setProxyTrap<&NodeApiJsiRuntime::hostObjectOwnKeysTrap, 1>(handler, getNodeApiValue(propertyId_.ownKeys));
2961
+ setProxyTrap<&NodeApiJsiRuntime::hostObjectHasTrap, 2>(
2962
+ handler, getNodeApiValue(propertyId_.has));
2963
+ setProxyTrap<&NodeApiJsiRuntime::hostObjectGetTrap, 3>(
2964
+ handler, getNodeApiValue(propertyId_.get));
2965
+ setProxyTrap<&NodeApiJsiRuntime::hostObjectSetTrap, 4>(
2966
+ handler, getNodeApiValue(propertyId_.set));
2967
+ setProxyTrap<&NodeApiJsiRuntime::hostObjectOwnKeysTrap, 1>(
2968
+ handler, getNodeApiValue(propertyId_.ownKeys));
2386
2969
  setProxyTrap<&NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap, 2>(
2387
2970
  handler, getNodeApiValue(propertyId_.getOwnPropertyDescriptor));
2388
- cachedValue_.HostObjectProxyHandler = makeNodeApiRef(handler, NodeApiPointerValueKind::Object);
2971
+ cachedValue_.HostObjectProxyHandler =
2972
+ makeNodeApiRef(handler, NodeApiPointerValueKind::Object);
2389
2973
  }
2390
2974
 
2391
2975
  return getNodeApiValue(cachedValue_.HostObjectProxyHandler);
2392
2976
  }
2393
2977
 
2394
2978
  // Sets Proxy trap method as a pointer to NodeApiJsiRuntime instance method.
2395
- template <napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>), size_t argCount>
2396
- void NodeApiJsiRuntime::setProxyTrap(napi_value handler, napi_value propertyName) {
2979
+ template <
2980
+ napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>),
2981
+ size_t argCount>
2982
+ void NodeApiJsiRuntime::setProxyTrap(
2983
+ napi_value handler,
2984
+ napi_value propertyName) {
2397
2985
  napi_callback proxyTrap = [](napi_env env, napi_callback_info info) noexcept {
2398
2986
  NodeApiJsiRuntime *runtime{};
2399
2987
  napi_value args[argCount]{};
2400
2988
  size_t actualArgCount{argCount};
2401
2989
  CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
2402
- env, info, &actualArgCount, args, nullptr, reinterpret_cast<void **>(&runtime)));
2403
- CHECK_ELSE_CRASH(actualArgCount == argCount, "proxy trap requires argCount arguments.");
2990
+ env,
2991
+ info,
2992
+ &actualArgCount,
2993
+ args,
2994
+ nullptr,
2995
+ reinterpret_cast<void **>(&runtime)));
2996
+ CHECK_ELSE_CRASH(
2997
+ actualArgCount == argCount, "proxy trap requires argCount arguments.");
2404
2998
  NodeApiPointerValueScope scope{*runtime};
2405
- return runtime->handleCallbackExceptions(
2406
- [&runtime, &args]() { return (runtime->*trapMethod)(span<napi_value>(args, argCount)); });
2999
+ return runtime->handleCallbackExceptions([&runtime, &args]() {
3000
+ return (runtime->*trapMethod)(span<napi_value>(args, argCount));
3001
+ });
2407
3002
  };
2408
3003
 
2409
- setProperty(handler, propertyName, createExternalFunction(propertyName, argCount, proxyTrap, this));
3004
+ setProperty(
3005
+ handler,
3006
+ propertyName,
3007
+ createExternalFunction(propertyName, argCount, proxyTrap, this));
2410
3008
  }
2411
3009
 
2412
3010
  // The host object Proxy 'has' trap implementation.
@@ -2415,15 +3013,17 @@ napi_value NodeApiJsiRuntime::hostObjectHasTrap(span<napi_value> args) {
2415
3013
  // args[1] - the name of the property to check.
2416
3014
  napi_value propertyName = args[1];
2417
3015
  const auto &hostObject = getJsiHostObject(args[0]);
2418
- return runInMethodContext("HostObject::has", [&hostObject, &propertyName, this]() {
2419
- // std::vector<jsi::PropNameID> ownKeys = hostObject->getPropertyNames(*this);
2420
- // for (jsi::PropNameID &ownKey : ownKeys) {
2421
- // if (strictEquals(propertyName, getNodeApiValue(ownKey))) {
2422
- return getBoolean(true);
2423
- // }
2424
- // }
2425
- // return getBoolean(false);
2426
- });
3016
+ return runInMethodContext(
3017
+ "HostObject::has", [&hostObject, &propertyName, this]() {
3018
+ // std::vector<jsi::PropNameID> ownKeys =
3019
+ // hostObject->getPropertyNames(*this); for (jsi::PropNameID &ownKey :
3020
+ // ownKeys) {
3021
+ // if (strictEquals(propertyName, getNodeApiValue(ownKey))) {
3022
+ return getBoolean(true);
3023
+ // }
3024
+ // }
3025
+ // return getBoolean(false);
3026
+ });
2427
3027
  }
2428
3028
 
2429
3029
  // The host object Proxy 'get' trap implementation.
@@ -2434,15 +3034,17 @@ napi_value NodeApiJsiRuntime::hostObjectGetTrap(span<napi_value> args) {
2434
3034
  napi_value target = args[0];
2435
3035
  napi_value propertyName = args[1];
2436
3036
  bool isTargetOwnProp{};
2437
- CHECK_NAPI(jsrApi_->napi_has_own_property(env_, target, propertyName, &isTargetOwnProp));
3037
+ CHECK_NAPI(jsrApi_->napi_has_own_property(
3038
+ env_, target, propertyName, &isTargetOwnProp));
2438
3039
  if (isTargetOwnProp) {
2439
3040
  return getProperty(target, propertyName);
2440
3041
  }
2441
3042
  const auto &hostObject = getJsiHostObject(args[0]);
2442
3043
  PropNameIDView propertyId{this, propertyName};
2443
- return runInMethodContext("HostObject::get", [&hostObject, &propertyId, this]() {
2444
- return getNodeApiValue(hostObject->get(*this, propertyId));
2445
- });
3044
+ return runInMethodContext(
3045
+ "HostObject::get", [&hostObject, &propertyId, this]() {
3046
+ return getNodeApiValue(hostObject->get(*this, propertyId));
3047
+ });
2446
3048
  }
2447
3049
 
2448
3050
  // The host object Proxy 'set' trap implementation.
@@ -2455,7 +3057,9 @@ napi_value NodeApiJsiRuntime::hostObjectSetTrap(span<napi_value> args) {
2455
3057
  PropNameIDView propertyId{this, args[1]};
2456
3058
  JsiValueView value{this, args[2]};
2457
3059
  runInMethodContext(
2458
- "HostObject::set", [&hostObject, &propertyId, &value, this]() { hostObject->set(*this, propertyId, value); });
3060
+ "HostObject::set", [&hostObject, &propertyId, &value, this]() {
3061
+ hostObject->set(*this, propertyId, value);
3062
+ });
2459
3063
  return getUndefined();
2460
3064
  }
2461
3065
 
@@ -2466,13 +3070,19 @@ napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
2466
3070
 
2467
3071
  napi_value targetOwnKeys{};
2468
3072
  CHECK_NAPI(jsrApi_->napi_get_all_property_names(
2469
- env_, target, napi_key_own_only, napi_key_all_properties, napi_key_numbers_to_strings, &targetOwnKeys));
3073
+ env_,
3074
+ target,
3075
+ napi_key_own_only,
3076
+ napi_key_all_properties,
3077
+ napi_key_numbers_to_strings,
3078
+ &targetOwnKeys));
2470
3079
  CHECK_ELSE_THROW(isArray(targetOwnKeys), "Expected an array");
2471
3080
  size_t targetOwnKeysLength = getArrayLength(targetOwnKeys);
2472
3081
 
2473
3082
  const auto &hostObject = getJsiHostObject(target);
2474
3083
  std::vector<jsi::PropNameID> hostOwnKeys = runInMethodContext(
2475
- "HostObject::getPropertyNames", [&hostObject, this]() { return hostObject->getPropertyNames(*this); });
3084
+ "HostObject::getPropertyNames",
3085
+ [&hostObject, this]() { return hostObject->getPropertyNames(*this); });
2476
3086
 
2477
3087
  std::vector<jsi::PropNameID> ownKeys;
2478
3088
  std::unordered_set<const PointerValue *> uniqueOwnKeys;
@@ -2482,23 +3092,26 @@ napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
2482
3092
 
2483
3093
  // Read all target own keys.
2484
3094
  if (targetOwnKeysLength > 1) {
2485
- auto addPropNameId = [this, &uniqueOwnKeys, &ownKeys](jsi::PropNameID &&propNameId) {
2486
- const PointerValue *pv = getPointerValue(propNameId);
2487
- auto inserted = uniqueOwnKeys.insert(pv);
2488
- CHECK_ELSE_THROW(inserted.second, "Target has non-unique keys");
2489
- ownKeys.push_back(std::move(propNameId));
2490
- };
3095
+ auto addPropNameId =
3096
+ [this, &uniqueOwnKeys, &ownKeys](jsi::PropNameID &&propNameId) {
3097
+ const PointerValue *pv = getPointerValue(propNameId);
3098
+ auto inserted = uniqueOwnKeys.insert(pv);
3099
+ CHECK_ELSE_THROW(inserted.second, "Target has non-unique keys");
3100
+ ownKeys.push_back(std::move(propNameId));
3101
+ };
2491
3102
  for (size_t i = 0; i < targetOwnKeysLength; ++i) {
2492
3103
  napi_value key = getElement(targetOwnKeys, i);
2493
3104
  napi_valuetype keyType = typeOf(key);
2494
3105
  if (keyType == napi_string) {
2495
- addPropNameId(createPropNameIDFromString(makeJsiPointer<jsi::String>(key)));
3106
+ addPropNameId(
3107
+ createPropNameIDFromString(makeJsiPointer<jsi::String>(key)));
2496
3108
  #if JSI_VERSION >= 8
2497
3109
  } else if (keyType == napi_symbol) {
2498
3110
  if (strictEquals(key, getNodeApiValue(propertyId_.hostObjectSymbol))) {
2499
3111
  continue;
2500
3112
  }
2501
- addPropNameId(createPropNameIDFromSymbol(makeJsiPointer<jsi::Symbol>(key)));
3113
+ addPropNameId(
3114
+ createPropNameIDFromSymbol(makeJsiPointer<jsi::Symbol>(key)));
2502
3115
  #endif
2503
3116
  } else {
2504
3117
  throwNativeException("Unexpected key type");
@@ -2528,7 +3141,8 @@ napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
2528
3141
  napi_valuetype valueType = typeOf(napiKey);
2529
3142
  if (valueType == napi_string) {
2530
3143
  std::string keyStr = stringToStdString(napiKey);
2531
- std::optional<uint32_t> indexKey = toArrayIndex(keyStr.begin(), keyStr.end());
3144
+ std::optional<uint32_t> indexKey =
3145
+ toArrayIndex(keyStr.begin(), keyStr.end());
2532
3146
  if (indexKey.has_value()) {
2533
3147
  indexKeys.push_back(Index{indexKey.value(), napiKey});
2534
3148
  continue;
@@ -2537,9 +3151,12 @@ napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
2537
3151
  nonIndexKeys.push_back(napiKey);
2538
3152
  }
2539
3153
 
2540
- std::sort(indexKeys.begin(), indexKeys.end(), [](const Index &left, const Index &right) {
2541
- return left.index < right.index;
2542
- });
3154
+ std::sort(
3155
+ indexKeys.begin(),
3156
+ indexKeys.end(),
3157
+ [](const Index &left, const Index &right) {
3158
+ return left.index < right.index;
3159
+ });
2543
3160
 
2544
3161
  napi_value ownKeyArray = createNodeApiArray(0);
2545
3162
  uint32_t index = 0;
@@ -2554,27 +3171,42 @@ napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
2554
3171
  }
2555
3172
 
2556
3173
  // The host object Proxy 'getOwnPropertyDescriptor' trap implementation.
2557
- napi_value NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap(span<napi_value> args) {
3174
+ napi_value NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap(
3175
+ span<napi_value> args) {
2558
3176
  // args[0] - the Proxy target object.
2559
3177
  // args[1] - the property
2560
3178
  const auto &hostObject = getJsiHostObject(args[0]);
2561
3179
  PropNameIDView propertyId{this, args[1]};
2562
3180
 
2563
- return runInMethodContext("HostObject::getOwnPropertyDescriptor", [&hostObject, &propertyId, this]() {
2564
- auto getPropDescriptor = [](napi_value name, napi_value value) {
2565
- return napi_property_descriptor{
2566
- nullptr, name, nullptr, nullptr, nullptr, value, napi_default_jsproperty, nullptr};
2567
- };
2568
- napi_value trueValue = getBoolean(true);
2569
- napi_property_descriptor properties[]{
2570
- getPropDescriptor(getNodeApiValue(propertyId_.value), getNodeApiValue(hostObject->get(*this, propertyId))),
2571
- getPropDescriptor(getNodeApiValue(propertyId_.writable), trueValue),
2572
- getPropDescriptor(getNodeApiValue(propertyId_.enumerable), trueValue),
2573
- getPropDescriptor(getNodeApiValue(propertyId_.configurable), trueValue)};
2574
- napi_value descriptor = createNodeApiObject();
2575
- CHECK_NAPI(jsrApi_->napi_define_properties(env_, descriptor, std::size(properties), properties));
2576
- return descriptor;
2577
- });
3181
+ return runInMethodContext(
3182
+ "HostObject::getOwnPropertyDescriptor",
3183
+ [&hostObject, &propertyId, this]() {
3184
+ auto getPropDescriptor = [](napi_value name, napi_value value) {
3185
+ return napi_property_descriptor{
3186
+ nullptr,
3187
+ name,
3188
+ nullptr,
3189
+ nullptr,
3190
+ nullptr,
3191
+ value,
3192
+ napi_default_jsproperty,
3193
+ nullptr};
3194
+ };
3195
+ napi_value trueValue = getBoolean(true);
3196
+ napi_property_descriptor properties[]{
3197
+ getPropDescriptor(
3198
+ getNodeApiValue(propertyId_.value),
3199
+ getNodeApiValue(hostObject->get(*this, propertyId))),
3200
+ getPropDescriptor(getNodeApiValue(propertyId_.writable), trueValue),
3201
+ getPropDescriptor(
3202
+ getNodeApiValue(propertyId_.enumerable), trueValue),
3203
+ getPropDescriptor(
3204
+ getNodeApiValue(propertyId_.configurable), trueValue)};
3205
+ napi_value descriptor = createNodeApiObject();
3206
+ CHECK_NAPI(jsrApi_->napi_define_properties(
3207
+ env_, descriptor, std::size(properties), properties));
3208
+ return descriptor;
3209
+ });
2578
3210
  }
2579
3211
 
2580
3212
  // Converts jsi::Bufer to span.
@@ -2620,14 +3252,18 @@ napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Value &value) const {
2620
3252
  } else if (value.isNumber()) {
2621
3253
  return createDouble(value.getNumber());
2622
3254
  } else if (value.isSymbol()) {
2623
- return getNodeApiValue(value.getSymbol(*const_cast<NodeApiJsiRuntime *>(this)));
3255
+ return getNodeApiValue(
3256
+ value.getSymbol(*const_cast<NodeApiJsiRuntime *>(this)));
2624
3257
  } else if (value.isString()) {
2625
- return getNodeApiValue(value.getString(*const_cast<NodeApiJsiRuntime *>(this)));
3258
+ return getNodeApiValue(
3259
+ value.getString(*const_cast<NodeApiJsiRuntime *>(this)));
2626
3260
  } else if (value.isObject()) {
2627
- return getNodeApiValue(value.getObject(*const_cast<NodeApiJsiRuntime *>(this)));
3261
+ return getNodeApiValue(
3262
+ value.getObject(*const_cast<NodeApiJsiRuntime *>(this)));
2628
3263
  #if JSI_VERSION >= 8
2629
3264
  } else if (value.isBigInt()) {
2630
- return getNodeApiValue(value.getBigInt(*const_cast<NodeApiJsiRuntime *>(this)));
3265
+ return getNodeApiValue(
3266
+ value.getBigInt(*const_cast<NodeApiJsiRuntime *>(this)));
2631
3267
  #endif
2632
3268
  } else {
2633
3269
  throw jsi::JSINativeException("Unexpected jsi::Value type");
@@ -2635,16 +3271,18 @@ napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Value &value) const {
2635
3271
  }
2636
3272
 
2637
3273
  napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Pointer &ptr) const {
2638
- return const_cast<NodeApiPointerValue *>(static_cast<const NodeApiPointerValue *>(getPointerValue(ptr)))
3274
+ return const_cast<NodeApiPointerValue *>(
3275
+ static_cast<const NodeApiPointerValue *>(getPointerValue(ptr)))
2639
3276
  ->getValue(*const_cast<NodeApiJsiRuntime *>(this));
2640
3277
  }
2641
3278
 
2642
- napi_value NodeApiJsiRuntime::getNodeApiValue(const NodeApiRefHolder &ref) const {
3279
+ napi_value NodeApiJsiRuntime::getNodeApiValue(
3280
+ const NodeApiRefHolder &ref) const {
2643
3281
  return ref->getValue(*const_cast<NodeApiJsiRuntime *>(this));
2644
3282
  }
2645
3283
 
2646
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *NodeApiJsiRuntime::cloneNodeApiPointerValue(
2647
- const PointerValue *pointerValue) {
3284
+ NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
3285
+ NodeApiJsiRuntime::cloneNodeApiPointerValue(const PointerValue *pointerValue) {
2648
3286
  return static_cast<const NodeApiPointerValue *>(pointerValue)->clone(*this);
2649
3287
  }
2650
3288
 
@@ -2688,26 +3326,38 @@ std::optional<uint32_t> NodeApiJsiRuntime::toArrayIndex(
2688
3326
  template <typename T, std::enable_if_t<std::is_same_v<jsi::Object, T>, int>>
2689
3327
  T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
2690
3328
  return make<T>(NodeApiRefCountedPointerValue::make(
2691
- *const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::Object));
3329
+ *const_cast<NodeApiJsiRuntime *>(this),
3330
+ value,
3331
+ NodeApiPointerValueKind::Object)
3332
+ .release());
2692
3333
  }
2693
3334
 
2694
3335
  template <typename T, std::enable_if_t<std::is_same_v<jsi::String, T>, int>>
2695
3336
  T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
2696
3337
  return make<T>(NodeApiRefCountedPointerValue::make(
2697
- *const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::String));
3338
+ *const_cast<NodeApiJsiRuntime *>(this),
3339
+ value,
3340
+ NodeApiPointerValueKind::String)
3341
+ .release());
2698
3342
  }
2699
3343
 
2700
3344
  template <typename T, std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int>>
2701
3345
  T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
2702
3346
  return make<T>(NodeApiRefCountedPointerValue::make(
2703
- *const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::Symbol));
3347
+ *const_cast<NodeApiJsiRuntime *>(this),
3348
+ value,
3349
+ NodeApiPointerValueKind::Symbol)
3350
+ .release());
2704
3351
  }
2705
3352
 
2706
3353
  #if JSI_VERSION >= 6
2707
3354
  template <typename T, std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int>>
2708
3355
  T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
2709
3356
  return make<T>(NodeApiRefCountedPointerValue::make(
2710
- *const_cast<NodeApiJsiRuntime *>(this), value, NodeApiPointerValueKind::BigInt));
3357
+ *const_cast<NodeApiJsiRuntime *>(this),
3358
+ value,
3359
+ NodeApiPointerValueKind::BigInt)
3360
+ .release());
2711
3361
  }
2712
3362
  #endif
2713
3363
 
@@ -2717,29 +3367,21 @@ template <
2717
3367
  std::enable_if_t<std::is_base_of_v<jsi::Pointer, TTo>, int>,
2718
3368
  std::enable_if_t<std::is_base_of_v<jsi::Pointer, TFrom>, int>>
2719
3369
  TTo NodeApiJsiRuntime::cloneAs(const TFrom &pointer) const {
2720
- return make<TTo>(static_cast<const NodeApiRefCountedPointerValue *>(getPointerValue(pointer))
3370
+ return make<TTo>(static_cast<const NodeApiRefCountedPointerValue *>(
3371
+ getPointerValue(pointer))
2721
3372
  ->clone(*const_cast<NodeApiJsiRuntime *>(this)));
2722
3373
  }
2723
3374
 
2724
3375
  NodeApiJsiRuntime::NodeApiRefHolder NodeApiJsiRuntime::makeNodeApiRef(
2725
3376
  napi_value value,
2726
- NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
3377
+ NodeApiPointerValueKind pointerKind,
2727
3378
  int32_t initialRefCount) {
2728
- return NodeApiRefHolder(NodeApiRefCountedPointerValue::makeNodeApiRef(*this, value, pointerKind, initialRefCount));
3379
+ return NodeApiRefCountedPointerValue::make(
3380
+ *this, value, pointerKind, initialRefCount);
2729
3381
  }
2730
3382
 
2731
- void NodeApiJsiRuntime::addStackValue(NodeApiStackValueHolder &&pointerHolder) {
2732
- if (stackValues_.size() == stackValues_.capacity()) {
2733
- collectUnusedStackValues();
2734
- }
2735
- stackValues_.push_back(std::move(pointerHolder));
2736
- }
2737
-
2738
- void NodeApiJsiRuntime::addRef(NodeApiRefHolder &&refHolder) {
2739
- if (refs_.size() == refs_.capacity()) {
2740
- collectUnusedRefs();
2741
- }
2742
- refs_.push_back(std::move(refHolder));
3383
+ void NodeApiJsiRuntime::addStackValue(NodeApiStackValuePtr stackPointer) {
3384
+ stackValues_.push_back(std::move(stackPointer));
2743
3385
  }
2744
3386
 
2745
3387
  void NodeApiJsiRuntime::pushPointerValueScope() noexcept {
@@ -2748,45 +3390,24 @@ void NodeApiJsiRuntime::pushPointerValueScope() noexcept {
2748
3390
 
2749
3391
  void NodeApiJsiRuntime::popPointerValueScope() noexcept {
2750
3392
  CHECK_ELSE_CRASH(!stackScopes_.empty(), "There are no scopes to pop");
2751
-
2752
3393
  size_t newStackSize = stackScopes_.back();
2753
3394
  auto beginIterator = stackValues_.begin() + newStackSize;
2754
3395
  stackScopes_.pop_back();
2755
- std::for_each(beginIterator, stackValues_.end(), [this](NodeApiStackValueHolder &holder) {
2756
- holder.release()->convertToNodeApiRef(*this);
2757
- });
3396
+ std::for_each(
3397
+ beginIterator, stackValues_.end(), [this](NodeApiStackValuePtr &ptr) {
3398
+ ptr.release()->deleteStackValue(*this);
3399
+ });
2758
3400
  stackValues_.resize(newStackSize);
2759
- }
2760
3401
 
2761
- void NodeApiJsiRuntime::collectUnusedStackValues() {
2762
- auto usedByJsiPointer = [](NodeApiStackValueHolder &holder) {
2763
- return NodeApiRefCountedPointerValue::usedByJsiPointer(holder.get());
2764
- };
2765
- auto beginIterator = stackValues_.begin();
2766
- for (size_t &scope : stackScopes_) {
2767
- auto endIterator = stackValues_.begin() + scope;
2768
- beginIterator = std::partition(beginIterator, endIterator, usedByJsiPointer);
2769
- scope -= endIterator - beginIterator;
2770
- }
2771
- beginIterator = std::partition(beginIterator, stackValues_.end(), usedByJsiPointer);
2772
- stackValues_.resize(beginIterator - stackValues_.begin());
2773
- }
2774
-
2775
- void NodeApiJsiRuntime::collectUnusedRefs() noexcept {
2776
- auto usedByJsiPointer = [](NodeApiRefHolder &holder) {
2777
- return NodeApiRefCountedPointerValue::usedByJsiPointer(holder.get());
2778
- };
2779
- auto beginIterator = std::partition(refs_.begin(), refs_.end(), usedByJsiPointer);
2780
- std::for_each(beginIterator, refs_.end(), [this](NodeApiRefHolder &holder) {
2781
- NodeApiRefCountedPointerValue::deleteNodeApiRef(holder.release(), *this);
2782
- });
2783
- refs_.resize(beginIterator - refs_.begin());
3402
+ pendingDeletions_->deletePointerValues(*this);
2784
3403
  }
2785
3404
 
2786
3405
  } // namespace
2787
3406
 
2788
- std::unique_ptr<jsi::Runtime>
2789
- makeNodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()> onDelete) noexcept {
3407
+ std::unique_ptr<jsi::Runtime> makeNodeApiJsiRuntime(
3408
+ napi_env env,
3409
+ JSRuntimeApi *jsrApi,
3410
+ std::function<void()> onDelete) noexcept {
2790
3411
  return std::make_unique<NodeApiJsiRuntime>(env, jsrApi, std::move(onDelete));
2791
3412
  }
2792
3413
 
@@ -2794,47 +3415,67 @@ makeNodeApiJsiRuntime(napi_env env, JSRuntimeApi *jsrApi, std::function<void()>
2794
3415
 
2795
3416
  EXTERN_C_START
2796
3417
 
2797
- // Default implementation of jsr_get_description if it is not provided by JS engine.
2798
- // It returns "NodeApiJsiRuntime" string.
2799
- napi_status NAPI_CDECL default_jsr_get_description(napi_env /*env*/, const char **result) {
3418
+ // Default implementation of jsr_get_description if it is not provided by JS
3419
+ // engine. It returns "NodeApiJsiRuntime" string.
3420
+ napi_status NAPI_CDECL
3421
+ default_jsr_get_description(napi_env /*env*/, const char **result) {
2800
3422
  if (result != nullptr) {
2801
3423
  *result = "NodeApiJsiRuntime";
2802
3424
  }
2803
3425
  return napi_ok;
2804
3426
  }
2805
3427
 
2806
- // Default implementation of jsr_drain_microtasks if it is not provided by JS engine.
2807
- // It does nothing
2808
- napi_status NAPI_CDECL default_jsr_drain_microtasks(napi_env /*env*/, int32_t /*max_count_hint*/, bool *result) {
3428
+ // Default implementation of jsr_queue_microtask if it is not provided by JS
3429
+ // engine. It does nothing.
3430
+ napi_status NAPI_CDECL
3431
+ default_jsr_queue_microtask(napi_env /*env*/, napi_value /*callback*/) {
3432
+ return napi_generic_failure;
3433
+ }
3434
+
3435
+ // Default implementation of jsr_drain_microtasks if it is not provided by JS
3436
+ // engine. It does nothing.
3437
+ napi_status NAPI_CDECL default_jsr_drain_microtasks(
3438
+ napi_env /*env*/,
3439
+ int32_t /*max_count_hint*/,
3440
+ bool *result) {
2809
3441
  if (result != nullptr) {
2810
3442
  *result = true; // All tasks are drained
2811
3443
  }
2812
3444
  return napi_ok;
2813
3445
  }
2814
3446
 
2815
- // Default implementation of jsr_is_inspectable if it is not provided by JS engine.
2816
- // It always returns false.
2817
- napi_status NAPI_CDECL default_jsr_is_inspectable(napi_env /*env*/, bool *result) {
3447
+ // Default implementation of jsr_is_inspectable if it is not provided by JS
3448
+ // engine. It always returns false.
3449
+ napi_status NAPI_CDECL
3450
+ default_jsr_is_inspectable(napi_env /*env*/, bool *result) {
2818
3451
  if (result != nullptr) {
2819
3452
  *result = false;
2820
3453
  }
2821
3454
  return napi_ok;
2822
3455
  }
2823
3456
 
2824
- // Default implementation of jsr_open_napi_env_scope if it is not provided by JS engine.
2825
- napi_status NAPI_CDECL default_jsr_open_napi_env_scope(napi_env /*env*/, jsr_napi_env_scope * /*scope*/) {
3457
+ // Default implementation of jsr_open_napi_env_scope if it is not provided by JS
3458
+ // engine.
3459
+ napi_status NAPI_CDECL default_jsr_open_napi_env_scope(
3460
+ napi_env /*env*/,
3461
+ jsr_napi_env_scope * /*scope*/) {
2826
3462
  return napi_ok;
2827
3463
  }
2828
3464
 
2829
- // Default implementation of jsr_close_napi_env_scope if it is not provided by JS engine.
2830
- napi_status NAPI_CDECL default_jsr_close_napi_env_scope(napi_env /*env*/, jsr_napi_env_scope /*scope*/) {
3465
+ // Default implementation of jsr_close_napi_env_scope if it is not provided by
3466
+ // JS engine.
3467
+ napi_status NAPI_CDECL default_jsr_close_napi_env_scope(
3468
+ napi_env /*env*/,
3469
+ jsr_napi_env_scope /*scope*/) {
2831
3470
  return napi_ok;
2832
3471
  }
2833
3472
 
2834
- // TODO: Ensure that we either load all three functions or use their default versions and never mix and match.
3473
+ // TODO: Ensure that we either load all three functions or use their default
3474
+ // versions and never mix and match.
2835
3475
 
2836
- // Default implementation of jsr_create_prepared_script if it is not provided by JS engine.
2837
- // It return napi_ref as a jsr_prepared_script that wraps up an object with a "script" property string.
3476
+ // Default implementation of jsr_create_prepared_script if it is not provided by
3477
+ // JS engine. It return napi_ref as a jsr_prepared_script that wraps up an
3478
+ // object with a "script" property string.
2838
3479
  napi_status NAPI_CDECL default_jsr_create_prepared_script(
2839
3480
  napi_env env,
2840
3481
  const uint8_t *script_data,
@@ -2843,34 +3484,46 @@ napi_status NAPI_CDECL default_jsr_create_prepared_script(
2843
3484
  void *deleter_data,
2844
3485
  const char * /*source_url*/,
2845
3486
  jsr_prepared_script *result) {
2846
- Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi = Microsoft::NodeApiJsi::JSRuntimeApi::current();
3487
+ Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi =
3488
+ Microsoft::NodeApiJsi::JSRuntimeApi::current();
2847
3489
  napi_value script{}, obj{};
2848
- // Do not use NAPI_CALL - we must finalize the buffer right after we attempted the string creation.
2849
- napi_status status =
2850
- jsrApi->napi_create_string_utf8(env, reinterpret_cast<const char *>(script_data), script_length, &script);
3490
+ // Do not use NAPI_CALL - we must finalize the buffer right after we attempted
3491
+ // the string creation.
3492
+ napi_status status = jsrApi->napi_create_string_utf8(
3493
+ env, reinterpret_cast<const char *>(script_data), script_length, &script);
2851
3494
  if (script_delete_cb != nullptr) {
2852
3495
  script_delete_cb(const_cast<uint8_t *>(script_data), deleter_data);
2853
3496
  }
2854
3497
  NAPI_CALL(status);
2855
3498
  NAPI_CALL(jsrApi->napi_create_object(env, &obj));
2856
3499
  NAPI_CALL(jsrApi->napi_set_named_property(env, obj, "script", script));
2857
- return jsrApi->napi_create_reference(env, obj, 1, reinterpret_cast<napi_ref *>(result));
3500
+ return jsrApi->napi_create_reference(
3501
+ env, obj, 1, reinterpret_cast<napi_ref *>(result));
2858
3502
  }
2859
3503
 
2860
- // Default implementation of jsr_delete_prepared_script if it is not provided by JS engine.
2861
- // It deletes prepared_script as a napi_ref.
2862
- napi_status NAPI_CDECL default_jsr_delete_prepared_script(napi_env env, jsr_prepared_script prepared_script) {
2863
- Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi = Microsoft::NodeApiJsi::JSRuntimeApi::current();
2864
- return jsrApi->napi_delete_reference(env, reinterpret_cast<napi_ref>(prepared_script));
3504
+ // Default implementation of jsr_delete_prepared_script if it is not provided by
3505
+ // JS engine. It deletes prepared_script as a napi_ref.
3506
+ napi_status NAPI_CDECL default_jsr_delete_prepared_script(
3507
+ napi_env env,
3508
+ jsr_prepared_script prepared_script) {
3509
+ Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi =
3510
+ Microsoft::NodeApiJsi::JSRuntimeApi::current();
3511
+ return jsrApi->napi_delete_reference(
3512
+ env, reinterpret_cast<napi_ref>(prepared_script));
2865
3513
  }
2866
3514
 
2867
- // Default implementation of jsr_prepared_script_run if it is not provided by JS engine.
2868
- // It interprets prepared_script as a napi_ref to an object with a "script" property string.
2869
- napi_status NAPI_CDECL
2870
- default_jsr_prepared_script_run(napi_env env, jsr_prepared_script prepared_script, napi_value *result) {
2871
- Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi = Microsoft::NodeApiJsi::JSRuntimeApi::current();
3515
+ // Default implementation of jsr_prepared_script_run if it is not provided by JS
3516
+ // engine. It interprets prepared_script as a napi_ref to an object with a
3517
+ // "script" property string.
3518
+ napi_status NAPI_CDECL default_jsr_prepared_script_run(
3519
+ napi_env env,
3520
+ jsr_prepared_script prepared_script,
3521
+ napi_value *result) {
3522
+ Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi =
3523
+ Microsoft::NodeApiJsi::JSRuntimeApi::current();
2872
3524
  napi_value obj{}, script{};
2873
- NAPI_CALL(jsrApi->napi_get_reference_value(env, reinterpret_cast<napi_ref>(prepared_script), &obj));
3525
+ NAPI_CALL(jsrApi->napi_get_reference_value(
3526
+ env, reinterpret_cast<napi_ref>(prepared_script), &obj));
2874
3527
  NAPI_CALL(jsrApi->napi_get_named_property(env, obj, "script", &script));
2875
3528
  return jsrApi->napi_run_script(env, script, result);
2876
3529
  }