react-native-windows 0.80.1 → 0.80.5

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 (83) hide show
  1. package/Directory.Build.props +1 -1
  2. package/Microsoft.ReactNative/Fabric/Composition/DebuggerUIIsland.cpp +169 -0
  3. package/Microsoft.ReactNative/Fabric/Composition/DebuggerUIIsland.h +42 -0
  4. package/Microsoft.ReactNative/Fabric/Composition/DebuggingOverlayComponentView.cpp +1 -1
  5. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +60 -33
  6. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +68 -1
  7. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +9 -0
  8. package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.cpp +5 -3
  9. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +6 -1
  10. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +14 -1
  11. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.cpp +75 -24
  12. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.h +4 -25
  13. package/Microsoft.ReactNative/JsiApi.cpp +1 -1
  14. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -0
  15. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +3 -0
  16. package/Microsoft.ReactNative/ReactHost/DebuggerNotifications.h +54 -0
  17. package/Microsoft.ReactNative/ReactHost/React.h +11 -4
  18. package/Microsoft.ReactNative/ReactHost/ReactHost.cpp +195 -29
  19. package/Microsoft.ReactNative/ReactHost/ReactHost.h +22 -4
  20. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +24 -5
  21. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -1
  22. package/Microsoft.ReactNative/ReactRootView.cpp +108 -0
  23. package/Microsoft.ReactNative/ReactRootView.h +6 -0
  24. package/Microsoft.ReactNative/Views/DevMenu.cpp +1 -1
  25. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +1 -1
  26. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  27. package/PropertySheets/JSEngine.props +1 -1
  28. package/PropertySheets/React.Cpp.props +2 -2
  29. package/ReactCommon/ReactCommon.vcxproj +18 -1
  30. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.cpp +1 -1
  31. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/test/testlib.cpp +4 -4
  32. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.cpp +23 -9
  33. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.h +16 -0
  34. package/ReactCommon/cgmanifest.json +1 -1
  35. package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +2 -0
  36. package/Shared/DevServerHelper.h +13 -3
  37. package/Shared/DevSettings.h +7 -0
  38. package/Shared/DevSupportManager.cpp +79 -20
  39. package/Shared/DevSupportManager.h +7 -19
  40. package/Shared/Hermes/HermesRuntimeAgentDelegate.cpp +99 -0
  41. package/Shared/Hermes/HermesRuntimeAgentDelegate.h +81 -0
  42. package/Shared/Hermes/HermesRuntimeTargetDelegate.cpp +263 -0
  43. package/Shared/Hermes/HermesRuntimeTargetDelegate.h +77 -0
  44. package/Shared/HermesRuntimeHolder.cpp +29 -111
  45. package/Shared/HermesRuntimeHolder.h +214 -32
  46. package/Shared/IDevSupportManager.h +5 -2
  47. package/Shared/Inspector/ReactInspectorPackagerConnectionDelegate.cpp +108 -0
  48. package/Shared/Inspector/ReactInspectorPackagerConnectionDelegate.h +19 -0
  49. package/Shared/Inspector/ReactInspectorThread.h +18 -0
  50. package/Shared/JSI/RuntimeHolder.h +5 -2
  51. package/Shared/OInstance.cpp +44 -27
  52. package/Shared/Shared.vcxitems +27 -17
  53. package/Shared/Shared.vcxitems.filters +33 -15
  54. package/package.json +4 -4
  55. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.cpp +0 -79
  56. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.h +0 -51
  57. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.inc +0 -50
  58. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.cpp +0 -41
  59. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.h +0 -127
  60. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.inc +0 -125
  61. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_posix.cpp +0 -16
  62. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_win.cpp +0 -23
  63. package/Microsoft.ReactNative.Cxx/JSI/decorator.h +0 -1054
  64. package/Microsoft.ReactNative.Cxx/JSI/instrumentation.h +0 -145
  65. package/Microsoft.ReactNative.Cxx/JSI/jsi-inl.h +0 -372
  66. package/Microsoft.ReactNative.Cxx/JSI/jsi.cpp +0 -797
  67. package/Microsoft.ReactNative.Cxx/JSI/jsi.h +0 -1799
  68. package/Microsoft.ReactNative.Cxx/JSI/threadsafe.h +0 -79
  69. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.cpp +0 -3531
  70. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.h +0 -38
  71. package/Microsoft.ReactNative.Cxx/node-api/js_native_api.h +0 -614
  72. package/Microsoft.ReactNative.Cxx/node-api/js_native_api_types.h +0 -212
  73. package/Microsoft.ReactNative.Cxx/node-api/js_runtime_api.h +0 -199
  74. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.cpp +0 -78
  75. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.h +0 -196
  76. package/ReactCommon/TEMP_UntilReactCommonUpdate/jserrorhandler/JsErrorHandler.cpp +0 -429
  77. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsitooling/react/runtime/JSRuntimeFactory.cpp +0 -45
  78. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsitooling/react/runtime/JSRuntimeFactory.h +0 -91
  79. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/ReactInstance.cpp +0 -670
  80. package/Shared/InspectorPackagerConnection.cpp +0 -232
  81. package/Shared/InspectorPackagerConnection.h +0 -61
  82. /package/Shared/{HermesSamplingProfiler.cpp → Hermes/HermesSamplingProfiler.cpp} +0 -0
  83. /package/Shared/{HermesSamplingProfiler.h → Hermes/HermesSamplingProfiler.h} +0 -0
@@ -1,3531 +0,0 @@
1
- // Copyright (c) Microsoft Corporation.
2
- // Licensed under the MIT License.
3
-
4
- #define NAPI_EXPERIMENTAL
5
-
6
- #include "NodeApiJsiRuntime.h"
7
-
8
- #include <algorithm>
9
- #include <array>
10
- #include <mutex>
11
- #include <optional>
12
- #include <sstream>
13
- #include <string_view>
14
- #include <unordered_map>
15
- #include <unordered_set>
16
-
17
- // JSI version defines set of features available in the API.
18
- // Each significant API change must be under a new version.
19
- // These macros must be defined in jsi.h, but define them here too
20
- // in case if this code is used with unmodified jsi.h.
21
- #ifndef JSI_VERSION
22
- #define JSI_VERSION 10
23
- #endif
24
-
25
- #ifndef JSI_NO_CONST_3
26
- #if JSI_VERSION >= 3
27
- #define JSI_NO_CONST_3
28
- #else
29
- #define JSI_NO_CONST_3 const
30
- #endif
31
- #endif
32
-
33
- #ifndef JSI_CONST_10
34
- #if JSI_VERSION >= 10
35
- #define JSI_CONST_10 const
36
- #else
37
- #define JSI_CONST_10
38
- #endif
39
- #endif
40
-
41
- using namespace facebook;
42
- using namespace std::string_view_literals;
43
-
44
- // We use macros to report errors.
45
- // Macros provide more flexibility to show assert and provide failure context.
46
-
47
- // Check condition and crash process if it fails.
48
- #define CHECK_ELSE_CRASH(condition, message) \
49
- do { \
50
- if (!(condition)) { \
51
- assert(false && "Failed: " #condition && (message)); \
52
- *((int *)0) = 1; \
53
- } \
54
- } while (false)
55
-
56
- // Check condition and throw native exception if it fails.
57
- #define CHECK_ELSE_THROW(condition, message) \
58
- do { \
59
- if (!(condition)) { \
60
- throwNativeException(message); \
61
- } \
62
- } while (false)
63
-
64
- // Check Node-API result and and throw JS exception if it is not napi_ok.
65
- #define CHECK_NAPI(...) \
66
- do { \
67
- napi_status temp_error_code_ = (__VA_ARGS__); \
68
- if (temp_error_code_ != napi_status::napi_ok) { \
69
- runtime.throwJSException(temp_error_code_); \
70
- } \
71
- } while (false)
72
-
73
- // Check Node-API result and and crash if it is not napi_ok.
74
- #define CHECK_NAPI_ELSE_CRASH(expression) \
75
- do { \
76
- napi_status temp_error_code_ = (expression); \
77
- if (temp_error_code_ != napi_status::napi_ok) { \
78
- CHECK_ELSE_CRASH(false, "Failed: " #expression); \
79
- } \
80
- } while (false)
81
-
82
- // Check Node-API result and return it when it is an error.
83
- #define NAPI_CALL(expression) \
84
- do { \
85
- napi_status temp_error_code_ = (expression); \
86
- if (temp_error_code_ != napi_status::napi_ok) { \
87
- return temp_error_code_; \
88
- } \
89
- } while (false)
90
-
91
- #ifdef __cpp_lib_span
92
- #include <span>
93
- #endif // __cpp_lib_span
94
-
95
- namespace Microsoft::NodeApiJsi {
96
-
97
- namespace {
98
-
99
- #ifdef __cpp_lib_span
100
- using std::span;
101
- #else
102
- /**
103
- * @brief A span of values that can be used to pass arguments to a function.
104
- *
105
- * This should be replaced with std::span once C++20 is supported.
106
- */
107
- template <typename T>
108
- class span {
109
- public:
110
- constexpr span() noexcept : data_{nullptr}, size_{0} {}
111
- constexpr span(T *data, size_t size) noexcept : data_{data}, size_{size} {}
112
- template <std::size_t N>
113
- constexpr span(T (&arr)[N]) noexcept : data_{arr}, size_{N} {}
114
-
115
- [[nodiscard]] constexpr T *data() const noexcept {
116
- return data_;
117
- }
118
-
119
- [[nodiscard]] constexpr size_t size() const noexcept {
120
- return size_;
121
- }
122
-
123
- [[nodiscard]] constexpr T *begin() const noexcept {
124
- return data_;
125
- }
126
-
127
- [[nodiscard]] constexpr T *end() const noexcept {
128
- return *(data_ + size_);
129
- }
130
-
131
- const T &operator[](size_t index) const noexcept {
132
- return *(data_ + index);
133
- }
134
-
135
- private:
136
- T *data_;
137
- size_t size_;
138
- };
139
- #endif // __cpp_lib_span
140
-
141
- // To be used as a key in a unordered_map.
142
- class StringKey {
143
- public:
144
- explicit StringKey(std::string &&string) noexcept;
145
- explicit StringKey(std::string_view view) noexcept;
146
- explicit StringKey(const char *data, size_t length) noexcept;
147
- StringKey(StringKey &&other) noexcept;
148
- StringKey &operator=(StringKey &&other) noexcept;
149
- StringKey(const StringKey &other) = delete;
150
- StringKey &operator=(const StringKey &other) = delete;
151
- ~StringKey();
152
-
153
- std::string_view getStringView() const;
154
- bool equalTo(const StringKey &other) const;
155
- size_t hash() const;
156
-
157
- struct Hash {
158
- size_t operator()(const StringKey &key) const;
159
- };
160
-
161
- struct EqualTo {
162
- bool operator()(const StringKey &left, const StringKey &right) const;
163
- };
164
-
165
- private:
166
- enum class Type {
167
- String,
168
- View,
169
- };
170
-
171
- private:
172
- union {
173
- std::string string_;
174
- std::string_view view_;
175
- };
176
- Type type_{Type::String};
177
- size_t hash_;
178
- };
179
-
180
- struct NodeApiAttachTag {
181
- } attachTag;
182
-
183
- // Implementation of N-API JSI Runtime
184
- class NodeApiJsiRuntime : public jsi::Runtime {
185
- public:
186
- NodeApiJsiRuntime(
187
- napi_env env,
188
- JSRuntimeApi *jsrApi,
189
- std::function<void()> onDelete) noexcept;
190
- ~NodeApiJsiRuntime() override;
191
-
192
- jsi::Value evaluateJavaScript(
193
- const std::shared_ptr<const jsi::Buffer> &buffer,
194
- const std::string &sourceURL) override;
195
- std::shared_ptr<const jsi::PreparedJavaScript> prepareJavaScript(
196
- const std::shared_ptr<const jsi::Buffer> &buffer,
197
- std::string sourceURL) 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
203
- #if JSI_VERSION >= 4
204
- bool drainMicrotasks(int maxMicrotasksHint = -1) override;
205
- #endif
206
- jsi::Object global() override;
207
- std::string description() override;
208
- bool isInspectable() override;
209
-
210
- protected:
211
- PointerValue *cloneSymbol(const PointerValue *pointerValue) override;
212
- #if JSI_VERSION >= 6
213
- PointerValue *cloneBigInt(const PointerValue *pointerValue) override;
214
- #endif
215
- PointerValue *cloneString(const PointerValue *pointerValue) override;
216
- PointerValue *cloneObject(const PointerValue *pointerValue) override;
217
- PointerValue *clonePropNameID(const PointerValue *pointerValue) override;
218
-
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;
223
- jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override;
224
- #if JSI_VERSION >= 5
225
- jsi::PropNameID createPropNameIDFromSymbol(const jsi::Symbol &sym) override;
226
- #endif
227
- std::string utf8(const jsi::PropNameID &id) override;
228
- bool compare(const jsi::PropNameID &lhs, const jsi::PropNameID &rhs) override;
229
-
230
- std::string symbolToString(const jsi::Symbol &s) override;
231
-
232
- #if JSI_VERSION >= 8
233
- jsi::BigInt createBigIntFromInt64(int64_t value) override;
234
- jsi::BigInt createBigIntFromUint64(uint64_t value) override;
235
- bool bigintIsInt64(const jsi::BigInt &value) override;
236
- bool bigintIsUint64(const jsi::BigInt &value) override;
237
- uint64_t truncate(const jsi::BigInt &value) override;
238
- jsi::String bigintToString(const jsi::BigInt &value, int radix) override;
239
- #endif
240
-
241
- jsi::String createStringFromAscii(const char *str, size_t length) override;
242
- jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override;
243
- std::string utf8(const jsi::String &str) override;
244
-
245
- jsi::Object createObject() override;
246
- jsi::Object createObject(std::shared_ptr<jsi::HostObject> ho) override;
247
- std::shared_ptr<jsi::HostObject> getHostObject(const jsi::Object &) override;
248
- jsi::HostFunctionType &getHostFunction(const jsi::Function &) override;
249
-
250
- #if JSI_VERSION >= 7
251
- bool hasNativeState(const jsi::Object &value) 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;
257
- #endif
258
-
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;
265
- bool hasProperty(const jsi::Object &obj, const jsi::String &name) 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;
274
-
275
- bool isArray(const jsi::Object &obj) const override;
276
- bool isArrayBuffer(const jsi::Object &obj) const override;
277
- bool isFunction(const jsi::Object &obj) const override;
278
- bool isHostObject(const jsi::Object &obj) const override;
279
- bool isHostFunction(const jsi::Function &func) const override;
280
- jsi::Array getPropertyNames(const jsi::Object &obj) override;
281
-
282
- jsi::WeakObject createWeakObject(const jsi::Object &obj) override;
283
- jsi::Value lockWeakObject(
284
- JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObj) override;
285
-
286
- jsi::Array createArray(size_t length) override;
287
- #if JSI_VERSION >= 9
288
- jsi::ArrayBuffer createArrayBuffer(
289
- std::shared_ptr<jsi::MutableBuffer> buffer);
290
- #endif
291
- size_t size(const jsi::Array &arr) override;
292
- size_t size(const jsi::ArrayBuffer &arrBuf) override;
293
- uint8_t *data(const jsi::ArrayBuffer &arrBuff) override;
294
- jsi::Value getValueAtIndex(const jsi::Array &arr, size_t index) override;
295
- void setValueAtIndexImpl(
296
- JSI_CONST_10 jsi::Array &arr,
297
- size_t index,
298
- const jsi::Value &value) override;
299
-
300
- jsi::Function createFunctionFromHostFunction(
301
- const jsi::PropNameID &name,
302
- unsigned int paramCount,
303
- jsi::HostFunctionType func) 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;
313
-
314
- ScopeState *pushScope() override;
315
- void popScope(ScopeState *) override;
316
-
317
- bool strictEquals(const jsi::Symbol &a, const jsi::Symbol &b) const override;
318
- #if JSI_VERSION >= 6
319
- bool strictEquals(const jsi::BigInt &a, const jsi::BigInt &b) const override;
320
- #endif
321
- bool strictEquals(const jsi::String &a, const jsi::String &b) const override;
322
- bool strictEquals(const jsi::Object &a, const jsi::Object &b) const override;
323
-
324
- bool instanceOf(const jsi::Object &obj, const jsi::Function &func) override;
325
-
326
- #if JSI_VERSION >= 11
327
- void setExternalMemoryPressure(const jsi::Object &obj, size_t amount)
328
- override;
329
- #endif
330
-
331
- private:
332
- // RAII class to open and close the environment scope.
333
- class NodeApiScope {
334
- public:
335
- NodeApiScope(const NodeApiJsiRuntime &runtime) noexcept;
336
- NodeApiScope(NodeApiJsiRuntime &runtime) noexcept;
337
- ~NodeApiScope() noexcept;
338
-
339
- NodeApiScope(const NodeApiScope &) = delete;
340
- NodeApiScope &operator=(const NodeApiScope &) = delete;
341
-
342
- private:
343
- NodeApiJsiRuntime &runtime_;
344
- NodeApiEnvScope envScope_;
345
- ScopeState *scopeState_{};
346
- };
347
-
348
- // RAII class to open and close the environment scope.
349
- class NodeApiPointerValueScope {
350
- public:
351
- NodeApiPointerValueScope(NodeApiJsiRuntime &runtime) noexcept;
352
- ~NodeApiPointerValueScope() noexcept;
353
-
354
- NodeApiPointerValueScope(const NodeApiPointerValueScope &) = delete;
355
- NodeApiPointerValueScope &operator=(const NodeApiPointerValueScope &) =
356
- delete;
357
-
358
- private:
359
- NodeApiJsiRuntime &runtime_;
360
- };
361
-
362
- // Sets the variable in the constructor and then restores its value in the
363
- // destructor.
364
- template <typename T>
365
- class AutoRestore {
366
- public:
367
- AutoRestore(T &varRef, T value);
368
- ~AutoRestore();
369
-
370
- AutoRestore(const AutoRestore &) = delete;
371
- AutoRestore &operator=(const AutoRestore &) = delete;
372
-
373
- private:
374
- T &varRef_;
375
- T oldValue_;
376
- };
377
-
378
- enum class NodeApiPointerValueKind : uint8_t {
379
- Object,
380
- WeakObject,
381
- String,
382
- StringPropNameID,
383
- Symbol,
384
- BigInt,
385
- };
386
-
387
- class NodeApiRefCountedPointerValue;
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
-
584
- // NodeApiPointerValue is used by jsi::Pointer derived classes.
585
- struct NodeApiPointerValue : PointerValue {
586
- virtual NodeApiRefCountedPointerValue *clone(
587
- NodeApiJsiRuntime &runtime) const noexcept = 0;
588
- virtual napi_value getValue(NodeApiJsiRuntime &runtime) noexcept = 0;
589
- virtual NodeApiPointerValueKind getKind() const noexcept = 0;
590
- };
591
-
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.
597
- class NodeApiStackOnlyPointerValue final : public NodeApiPointerValue {
598
- public:
599
- NodeApiStackOnlyPointerValue(
600
- napi_value value,
601
- NodeApiPointerValueKind pointerKind) noexcept;
602
-
603
- void invalidate() noexcept override;
604
- NodeApiRefCountedPointerValue *clone(
605
- NodeApiJsiRuntime &runtime) const noexcept override;
606
- napi_value getValue(NodeApiJsiRuntime &runtime) noexcept override;
607
- NodeApiPointerValueKind getKind() const noexcept override;
608
-
609
- NodeApiStackOnlyPointerValue(const NodeApiStackOnlyPointerValue &) = delete;
610
- NodeApiStackOnlyPointerValue &operator=(
611
- const NodeApiStackOnlyPointerValue &) = delete;
612
-
613
- private:
614
- napi_value value_{};
615
- NodeApiPointerValueKind pointerKind_{NodeApiPointerValueKind::Object};
616
- };
617
-
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.
630
- //
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.
640
- //
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.
645
- //
646
- // All methods except for invalidate() and decRefCount() must be called from
647
- // the JS thread.
648
- class NodeApiRefCountedPointerValue final : public NodeApiPointerValue {
649
- friend class NodeApiStackValueDeleter;
650
- friend class NodeApiRefDeleter;
651
- friend class NodeApiRefCountedPtr<NodeApiRefCountedPointerValue>;
652
-
653
- public:
654
- // Creates new NodeApiRefCountedPointerValue and adds it to the
655
- // NodeApiJsiRuntime::stackValues_.
656
- static NodeApiRefHolder make(
657
- NodeApiJsiRuntime &runtime,
658
- napi_value value,
659
- NodeApiPointerValueKind pointerKind,
660
- int32_t initialRefCount = 1);
661
-
662
- // Calls `make` method and forces creation of `napi_ref`.
663
- static NodeApiRefHolder makeNodeApiRef(
664
- NodeApiJsiRuntime &runtime,
665
- napi_value value,
666
- NodeApiPointerValueKind pointerKind,
667
- int32_t initialRefCount = 1);
668
-
669
- void invalidate() noexcept override;
670
- NodeApiRefCountedPointerValue *clone(
671
- NodeApiJsiRuntime &runtime) const noexcept override;
672
- napi_value getValue(NodeApiJsiRuntime &runtime) noexcept override;
673
- NodeApiPointerValueKind getKind() const noexcept override;
674
-
675
- // Returns true if the refCount_ is not zero.
676
- bool usedByJsiPointer() const noexcept;
677
-
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;
682
-
683
- // Removes napi_ref and deletes `NodeApiRefCountedPointerValue` if `value_`
684
- // is null.
685
- void deleteNodeApiRef(NodeApiJsiRuntime &runtime) noexcept;
686
-
687
- NodeApiRefCountedPointerValue(const NodeApiRefCountedPointerValue &) =
688
- delete;
689
- NodeApiRefCountedPointerValue &operator=(
690
- const NodeApiRefCountedPointerValue &) = delete;
691
-
692
- private:
693
- NodeApiRefCountedPointerValue(
694
- NodeApiJsiRuntime &runtime,
695
- napi_value value,
696
- NodeApiPointerValueKind pointerKind,
697
- int32_t initialRefCount) noexcept;
698
-
699
- void incRefCount() const noexcept;
700
- void decRefCount() const noexcept;
701
-
702
- // Creates `napi_ref ref_` field for the `napi_value value_` field.
703
- NodeApiRefCountedPointerValue *createNodeApiRef(NodeApiJsiRuntime &runtime);
704
-
705
- private:
706
- NodeApiRefCountedPtr<NodeApiPendingDeletions> pendingDeletions_;
707
- napi_value value_{};
708
- napi_ref ref_{};
709
- mutable std::atomic<int32_t> refCount_{1};
710
- const NodeApiPointerValueKind pointerKind_{NodeApiPointerValueKind::Object};
711
- bool canBeDeletedFromStack_{false};
712
-
713
- static constexpr char kPrimitivePropertyName[] = "X";
714
- };
715
-
716
- // SmallBuffer keeps InplaceSize elements in place in the class, and uses heap
717
- // memory for more elements.
718
- template <typename T, size_t InplaceSize>
719
- class SmallBuffer {
720
- public:
721
- SmallBuffer(size_t size) noexcept;
722
-
723
- T *data() noexcept;
724
- size_t size() const noexcept;
725
-
726
- SmallBuffer(const SmallBuffer &) = delete;
727
- SmallBuffer &operator=(const SmallBuffer &) = delete;
728
-
729
- private:
730
- size_t size_{};
731
- std::array<T, InplaceSize> stackData_{};
732
- std::unique_ptr<T[]> heapData_{};
733
- };
734
-
735
- // The number of arguments that we keep on stack. We use heap if we have more
736
- // arguments.
737
- constexpr static size_t MaxStackArgCount = 8;
738
-
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.
742
- class NodeApiValueArgs {
743
- public:
744
- NodeApiValueArgs(NodeApiJsiRuntime &runtime, span<const jsi::Value> args);
745
- operator span<napi_value>();
746
-
747
- NodeApiValueArgs(const NodeApiValueArgs &) = delete;
748
- NodeApiValueArgs &operator=(const NodeApiValueArgs &) = delete;
749
-
750
- private:
751
- SmallBuffer<napi_value, MaxStackArgCount> args_;
752
- };
753
-
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.
757
- class JsiValueView {
758
- public:
759
- union StoreType {
760
- NodeApiStackOnlyPointerValue value_;
761
- std::array<std::byte, sizeof(NodeApiStackOnlyPointerValue)> bytes_;
762
- StoreType() {}
763
- ~StoreType() {}
764
- };
765
-
766
- public:
767
- JsiValueView(NodeApiJsiRuntime *runtime, napi_value jsValue);
768
- operator const jsi::Value &() const noexcept;
769
-
770
- static jsi::Value
771
- initValue(NodeApiJsiRuntime *runtime, napi_value jsValue, StoreType *store);
772
-
773
- JsiValueView(const JsiValueView &) = delete;
774
- JsiValueView &operator=(const JsiValueView &) = delete;
775
-
776
- private:
777
- StoreType pointerStore_;
778
- jsi::Value value_{};
779
- };
780
-
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.
784
- class JsiValueViewArgs {
785
- public:
786
- JsiValueViewArgs(
787
- NodeApiJsiRuntime *runtime,
788
- span<napi_value> args) noexcept;
789
- const jsi::Value *data() noexcept;
790
- size_t size() const noexcept;
791
-
792
- JsiValueViewArgs(const JsiValueViewArgs &);
793
- JsiValueViewArgs &operator=(const JsiValueViewArgs &);
794
-
795
- private:
796
- using StoreType = JsiValueView::StoreType;
797
- SmallBuffer<StoreType, MaxStackArgCount> pointerStore_{0};
798
- SmallBuffer<jsi::Value, MaxStackArgCount> args_{0};
799
- };
800
-
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.
804
- class PropNameIDView {
805
- public:
806
- PropNameIDView(NodeApiJsiRuntime *runtime, napi_value propertyId) noexcept;
807
- operator const jsi::PropNameID &() const noexcept;
808
-
809
- PropNameIDView(const PropNameIDView &);
810
- PropNameIDView &operator=(const PropNameIDView &);
811
-
812
- private:
813
- using StoreType = JsiValueView::StoreType;
814
- StoreType pointerStore_{};
815
- jsi::PropNameID const propertyId_;
816
- };
817
-
818
- // Wraps up the jsi::HostFunctionType along with the NodeApiJsiRuntime.
819
- class HostFunctionWrapper {
820
- public:
821
- HostFunctionWrapper(
822
- jsi::HostFunctionType &&hostFunction,
823
- NodeApiJsiRuntime &runtime);
824
-
825
- jsi::HostFunctionType &hostFunction() noexcept;
826
- NodeApiJsiRuntime &runtime() noexcept;
827
-
828
- HostFunctionWrapper(const HostFunctionWrapper &) = delete;
829
- HostFunctionWrapper &operator=(const HostFunctionWrapper &) = delete;
830
-
831
- private:
832
- jsi::HostFunctionType hostFunction_;
833
- NodeApiJsiRuntime &runtime_;
834
- };
835
-
836
- // Wraps up the jsr_prepared_script.
837
- class NodeApiPreparedJavaScript final : public jsi::PreparedJavaScript {
838
- public:
839
- NodeApiPreparedJavaScript(
840
- napi_env env,
841
- jsr_prepared_script script,
842
- std::string sourceURL)
843
- : env_(env), script_(script), sourceURL_(std::move(sourceURL)) {}
844
-
845
- ~NodeApiPreparedJavaScript() override {
846
- JSRuntimeApi::current()->jsr_delete_prepared_script(env_, script_);
847
- }
848
-
849
- jsr_prepared_script getScript() const {
850
- return script_;
851
- }
852
-
853
- const std::string &sourceURL() const {
854
- return sourceURL_;
855
- }
856
-
857
- NodeApiPreparedJavaScript(const NodeApiPreparedJavaScript &) = delete;
858
- NodeApiPreparedJavaScript &operator=(const NodeApiPreparedJavaScript &) =
859
- delete;
860
-
861
- private:
862
- napi_env env_;
863
- jsr_prepared_script script_;
864
- std::string sourceURL_;
865
- };
866
-
867
- private: // Error-handling utility methods
868
- template <typename... Args>
869
- jsi::JSError makeJSError(Args &&...args);
870
- [[noreturn]] void throwJSException(napi_status errorCode) const;
871
- [[noreturn]] void throwNativeException(char const *errorMessage) const;
872
- void rewriteErrorMessage(napi_value jsError) const;
873
- template <typename TLambda>
874
- auto runInMethodContext(char const *methodName, TLambda lambda);
875
- template <typename TLambda>
876
- napi_value handleCallbackExceptions(TLambda lambda) const noexcept;
877
- bool setException(napi_value error) const noexcept;
878
- bool setException(std::string_view message) const noexcept;
879
-
880
- private: // Shared Node-API call helpers
881
- napi_valuetype typeOf(napi_value value) const;
882
- bool strictEquals(napi_value left, napi_value right) const;
883
- napi_value getUndefined() const;
884
- napi_value getNull() const;
885
- napi_value getGlobal() const;
886
- napi_value getBoolean(bool value) const;
887
- bool getValueBool(napi_value value) const;
888
- napi_value createInt32(int32_t value) const;
889
- napi_value createUInt32(uint32_t value) const;
890
- napi_value createDouble(double value) const;
891
- double getValueDouble(napi_value value) const;
892
- napi_value createStringLatin1(std::string_view value) const;
893
- napi_value createStringUtf8(std::string_view value) const;
894
- napi_value createStringUtf8(const uint8_t *data, size_t length) const;
895
- std::string stringToStdString(napi_value stringValue) const;
896
- napi_value getPropertyIdFromName(std::string_view value) const;
897
- napi_value getPropertyIdFromName(const uint8_t *data, size_t length) const;
898
- napi_value getPropertyIdFromName(napi_value str) const;
899
- napi_value getPropertyIdFromSymbol(napi_value sym) const;
900
- std::string propertyIdToStdString(napi_value propertyId);
901
- napi_value createSymbol(std::string_view symbolDescription) const;
902
- std::string symbolToStdString(napi_value symbolValue);
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;
909
- bool instanceOf(napi_value object, napi_value constructor) const;
910
- napi_value createNodeApiObject() const;
911
- bool hasProperty(napi_value object, napi_value propertyId) const;
912
- napi_value getProperty(napi_value object, napi_value propertyId) 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;
920
- napi_value createNodeApiArray(size_t length) const;
921
- bool isArray(napi_value value) const;
922
- size_t getArrayLength(napi_value value) const;
923
- napi_value getElement(napi_value arr, size_t index) const;
924
- void setElement(napi_value array, uint32_t index, napi_value value) 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;
936
- template <typename T>
937
- napi_value createExternalObject(std::unique_ptr<T> &&data) const;
938
- void *getExternalData(napi_value object) const;
939
- const std::shared_ptr<jsi::HostObject> &getJsiHostObject(napi_value obj);
940
- napi_value getHostObjectProxyHandler();
941
- template <
942
- napi_value (NodeApiJsiRuntime::*trapMethod)(span<napi_value>),
943
- size_t argCount>
944
- void setProxyTrap(napi_value handler, napi_value propertyName);
945
- napi_value hostObjectHasTrap(span<napi_value> args);
946
- napi_value hostObjectGetTrap(span<napi_value> args);
947
- napi_value hostObjectSetTrap(span<napi_value> args);
948
- napi_value hostObjectOwnKeysTrap(span<napi_value> args);
949
- napi_value hostObjectGetOwnPropertyDescriptorTrap(span<napi_value> args);
950
-
951
- private: // Miscellaneous utility methods
952
- span<const uint8_t> toSpan(const jsi::Buffer &buffer);
953
- jsi::Value toJsiValue(napi_value value) const;
954
- napi_value getNodeApiValue(const jsi::Value &value) const;
955
- napi_value getNodeApiValue(const jsi::Pointer &ptr) const;
956
- napi_value getNodeApiValue(const NodeApiRefHolder &ref) const;
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);
962
-
963
- template <
964
- typename T,
965
- std::enable_if_t<std::is_same_v<jsi::Object, T>, int> = 0>
966
- T makeJsiPointer(napi_value value) const;
967
- template <
968
- typename T,
969
- std::enable_if_t<std::is_same_v<jsi::String, T>, int> = 0>
970
- T makeJsiPointer(napi_value value) const;
971
- template <
972
- typename T,
973
- std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int> = 0>
974
- T makeJsiPointer(napi_value value) const;
975
- #if JSI_VERSION >= 6
976
- template <
977
- typename T,
978
- std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int> = 0>
979
- T makeJsiPointer(napi_value value) const;
980
- #endif
981
- template <
982
- typename TTo,
983
- typename TFrom,
984
- std::enable_if_t<std::is_base_of_v<jsi::Pointer, TTo>, int> = 0,
985
- std::enable_if_t<std::is_base_of_v<jsi::Pointer, TFrom>, int> = 0>
986
- TTo cloneAs(const TFrom &pointer) const;
987
- NodeApiRefHolder makeNodeApiRef(
988
- napi_value value,
989
- NodeApiPointerValueKind pointerKind,
990
- int32_t initialRefCount = 1);
991
-
992
- void addStackValue(NodeApiStackValuePtr stackPointer);
993
- void pushPointerValueScope() noexcept;
994
- void popPointerValueScope() noexcept;
995
-
996
- napi_env getEnv() const noexcept {
997
- return env_;
998
- }
999
-
1000
- private: // Fields
1001
- napi_env env_{};
1002
- JSRuntimeApi *jsrApi_;
1003
- std::function<void()> onDelete_;
1004
- std::string sourceURL_;
1005
-
1006
- // Property ID cache to improve execution speed.
1007
- struct PropertyId {
1008
- NodeApiRefHolder Error;
1009
- NodeApiRefHolder Object;
1010
- NodeApiRefHolder Proxy;
1011
- NodeApiRefHolder Symbol;
1012
- NodeApiRefHolder byteLength;
1013
- NodeApiRefHolder configurable;
1014
- NodeApiRefHolder enumerable;
1015
- NodeApiRefHolder get;
1016
- NodeApiRefHolder getOwnPropertyDescriptor;
1017
- NodeApiRefHolder has;
1018
- NodeApiRefHolder hostFunctionSymbol;
1019
- NodeApiRefHolder hostObjectSymbol;
1020
- NodeApiRefHolder length;
1021
- NodeApiRefHolder message;
1022
- NodeApiRefHolder ownKeys;
1023
- NodeApiRefHolder propertyIsEnumerable;
1024
- NodeApiRefHolder prototype;
1025
- NodeApiRefHolder set;
1026
- NodeApiRefHolder stack;
1027
- NodeApiRefHolder toString;
1028
- NodeApiRefHolder value;
1029
- NodeApiRefHolder writable;
1030
- } propertyId_;
1031
-
1032
- // Cache of commonly used values.
1033
- struct CachedValue {
1034
- NodeApiRefHolder Error;
1035
- NodeApiRefHolder Global;
1036
- NodeApiRefHolder HostObjectProxyHandler;
1037
- NodeApiRefHolder ProxyConstructor;
1038
- NodeApiRefHolder SymbolToString;
1039
- } cachedValue_;
1040
-
1041
- bool hasPendingJSError_{false};
1042
-
1043
- std::vector<size_t> stackScopes_;
1044
- std::vector<NodeApiStackValuePtr> stackValues_;
1045
-
1046
- // TODO: implement GC for propNameIDs_
1047
- std::unordered_map<
1048
- StringKey,
1049
- NodeApiRefHolder,
1050
- StringKey::Hash,
1051
- StringKey::EqualTo>
1052
- propNameIDs_;
1053
-
1054
- NodeApiJsiRuntime &runtime{*this};
1055
- NodeApiRefCountedPtr<NodeApiPendingDeletions> pendingDeletions_{
1056
- NodeApiPendingDeletions::create()};
1057
- };
1058
-
1059
- //=====================================================================================================================
1060
- // StringKey implementation
1061
- //=====================================================================================================================
1062
-
1063
- StringKey::StringKey(std::string &&string) noexcept
1064
- : string_(std::move(string)),
1065
- type_(Type::String),
1066
- hash_(std::hash<std::string_view>{}(string_)) {}
1067
-
1068
- StringKey::StringKey(std::string_view view) noexcept
1069
- : view_(view),
1070
- type_(Type::View),
1071
- hash_(std::hash<std::string_view>{}(view_)) {}
1072
-
1073
- StringKey::StringKey(const char *data, size_t length) noexcept
1074
- : view_(data, length),
1075
- type_(Type::View),
1076
- hash_(std::hash<std::string_view>{}(view_)) {}
1077
-
1078
- StringKey::StringKey(StringKey &&other) noexcept
1079
- : type_(other.type_), hash_(std::exchange(other.hash_, 0)) {
1080
- if (type_ == Type::String) {
1081
- ::new (std::addressof(string_)) std::string(std::move(other.string_));
1082
- } else {
1083
- ::new (std::addressof(view_))
1084
- std::string_view(std::exchange(other.view_, std::string_view()));
1085
- }
1086
- }
1087
-
1088
- StringKey &StringKey::operator=(StringKey &&other) noexcept {
1089
- if (this != &other) {
1090
- this->~StringKey();
1091
- ::new (this) StringKey(std::move(other));
1092
- }
1093
- return *this;
1094
- }
1095
-
1096
- StringKey::~StringKey() {
1097
- if (type_ == Type::String) {
1098
- std::addressof(string_)->~basic_string();
1099
- } else {
1100
- std::addressof(view_)->~basic_string_view();
1101
- }
1102
- }
1103
-
1104
- std::string_view StringKey::getStringView() const {
1105
- return (type_ == Type::String) ? std::string_view(string_) : view_;
1106
- }
1107
-
1108
- bool StringKey::equalTo(const StringKey &other) const {
1109
- return getStringView().compare(other.getStringView()) == 0;
1110
- }
1111
-
1112
- size_t StringKey::hash() const {
1113
- return hash_;
1114
- }
1115
-
1116
- size_t StringKey::Hash::operator()(const StringKey &key) const {
1117
- return key.hash();
1118
- }
1119
-
1120
- bool StringKey::EqualTo::operator()(
1121
- const StringKey &left,
1122
- const StringKey &right) const {
1123
- return left.equalTo(right);
1124
- }
1125
-
1126
- //=====================================================================================================================
1127
- // NodeApiJsiRuntime implementation
1128
- //=====================================================================================================================
1129
-
1130
- NodeApiJsiRuntime::NodeApiJsiRuntime(
1131
- napi_env env,
1132
- JSRuntimeApi *jsrApi,
1133
- std::function<void()> onDelete) noexcept
1134
- : env_(env), jsrApi_(jsrApi), onDelete_(std::move(onDelete)) {
1135
- NodeApiScope scope{*this};
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);
1185
- cachedValue_.Error = makeNodeApiRef(
1186
- getProperty(
1187
- getNodeApiValue(cachedValue_.Global),
1188
- getNodeApiValue(propertyId_.Error)),
1189
- NodeApiPointerValueKind::Object);
1190
- }
1191
-
1192
- NodeApiJsiRuntime::~NodeApiJsiRuntime() {
1193
- if (onDelete_) {
1194
- onDelete_();
1195
- }
1196
- }
1197
-
1198
- jsi::Value NodeApiJsiRuntime::evaluateJavaScript(
1199
- const std::shared_ptr<const jsi::Buffer> &buffer,
1200
- const std::string &sourceURL) {
1201
- return evaluatePreparedJavaScript(prepareJavaScript(buffer, sourceURL));
1202
- }
1203
-
1204
- std::shared_ptr<const jsi::PreparedJavaScript>
1205
- NodeApiJsiRuntime::prepareJavaScript(
1206
- const std::shared_ptr<const jsi::Buffer> &sourceBuffer,
1207
- std::string sourceURL) {
1208
- NodeApiScope scope{*this};
1209
- jsr_prepared_script script{};
1210
- napi_status status = jsrApi_->jsr_create_prepared_script(
1211
- env_,
1212
- sourceBuffer->data(),
1213
- sourceBuffer->size(),
1214
- [](void * /*data*/, void *deleterData) {
1215
- delete reinterpret_cast<std::shared_ptr<const jsi::Buffer> *>(
1216
- deleterData);
1217
- },
1218
- new std::shared_ptr<const jsi::Buffer>(sourceBuffer),
1219
- sourceURL.c_str(),
1220
- &script);
1221
- CHECK_NAPI(status); // Not for the call to keep better automated formatting.
1222
- return std::make_shared<NodeApiPreparedJavaScript>(
1223
- env_, script, std::move(sourceURL));
1224
- }
1225
-
1226
- jsi::Value NodeApiJsiRuntime::evaluatePreparedJavaScript(
1227
- const std::shared_ptr<const jsi::PreparedJavaScript> &js) {
1228
- NodeApiScope scope{*this};
1229
- auto preparedScript =
1230
- static_cast<const NodeApiPreparedJavaScript *>(js.get());
1231
- AutoRestore<std::string> sourceURLScope{
1232
- sourceURL_, preparedScript->sourceURL()};
1233
- napi_value result{};
1234
- CHECK_NAPI(jsrApi_->jsr_prepared_script_run(
1235
- env_, preparedScript->getScript(), &result));
1236
- return toJsiValue(result);
1237
- }
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
-
1247
- #if JSI_VERSION >= 4
1248
- bool NodeApiJsiRuntime::drainMicrotasks(int maxMicrotasksHint) {
1249
- bool result{};
1250
- CHECK_NAPI(jsrApi_->jsr_drain_microtasks(env_, maxMicrotasksHint, &result));
1251
- return result;
1252
- }
1253
- #endif
1254
-
1255
- jsi::Object NodeApiJsiRuntime::global() {
1256
- return make<jsi::Object>(cachedValue_.Global->clone(*this));
1257
- }
1258
-
1259
- std::string NodeApiJsiRuntime::description() {
1260
- const char *desc{};
1261
- CHECK_NAPI(jsrApi_->jsr_get_description(env_, &desc));
1262
- return desc;
1263
- }
1264
-
1265
- bool NodeApiJsiRuntime::isInspectable() {
1266
- bool result{};
1267
- CHECK_NAPI(jsrApi_->jsr_is_inspectable(env_, &result));
1268
- return result;
1269
- }
1270
-
1271
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneSymbol(
1272
- const jsi::Runtime::PointerValue *pointerValue) {
1273
- return cloneNodeApiPointerValue(pointerValue);
1274
- }
1275
-
1276
- #if JSI_VERSION >= 6
1277
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneBigInt(
1278
- const jsi::Runtime::PointerValue *pointerValue) {
1279
- return cloneNodeApiPointerValue(pointerValue);
1280
- }
1281
- #endif
1282
-
1283
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneString(
1284
- const jsi::Runtime::PointerValue *pointerValue) {
1285
- return cloneNodeApiPointerValue(pointerValue);
1286
- }
1287
-
1288
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::cloneObject(
1289
- const jsi::Runtime::PointerValue *pointerValue) {
1290
- return cloneNodeApiPointerValue(pointerValue);
1291
- }
1292
-
1293
- jsi::Runtime::PointerValue *NodeApiJsiRuntime::clonePropNameID(
1294
- const jsi::Runtime::PointerValue *pointerValue) {
1295
- return cloneNodeApiPointerValue(pointerValue);
1296
- }
1297
-
1298
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromAscii(
1299
- const char *str,
1300
- size_t length) {
1301
- NodeApiScope scope{*this};
1302
- StringKey keyName{str, length};
1303
- auto it = propNameIDs_.find(keyName);
1304
- if (it != propNameIDs_.end()) {
1305
- return make<jsi::PropNameID>(it->second->clone(*this));
1306
- }
1307
-
1308
- napi_value obj = createNodeApiObject();
1309
- napi_value propName{};
1310
- CHECK_NAPI(jsrApi_->napi_create_string_latin1(env_, str, length, &propName));
1311
- CHECK_NAPI(jsrApi_->napi_set_property(env_, obj, propName, getUndefined()));
1312
- napi_value props{};
1313
- CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1314
- env_,
1315
- obj,
1316
- napi_key_own_only,
1317
- napi_key_skip_symbols,
1318
- napi_key_numbers_to_strings,
1319
- &props));
1320
- napi_value propNameId = getElement(props, 0);
1321
- NodeApiRefHolder propNameRef =
1322
- makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 2);
1323
- jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
1324
- propNameIDs_.try_emplace(
1325
- StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1326
- return result;
1327
- }
1328
-
1329
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromUtf8(
1330
- const uint8_t *utf8,
1331
- size_t length) {
1332
- NodeApiScope scope{*this};
1333
- StringKey keyName{reinterpret_cast<const char *>(utf8), length};
1334
- auto it = propNameIDs_.find(keyName);
1335
- if (it != propNameIDs_.end()) {
1336
- return make<jsi::PropNameID>(it->second->clone(*this));
1337
- }
1338
-
1339
- napi_value obj = createNodeApiObject();
1340
- napi_value propName{};
1341
- CHECK_NAPI(jsrApi_->napi_create_string_utf8(
1342
- env_, reinterpret_cast<const char *>(utf8), length, &propName));
1343
- CHECK_NAPI(jsrApi_->napi_set_property(env_, obj, propName, getUndefined()));
1344
- napi_value props{};
1345
- CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1346
- env_,
1347
- obj,
1348
- napi_key_own_only,
1349
- napi_key_skip_symbols,
1350
- napi_key_numbers_to_strings,
1351
- &props));
1352
- napi_value propNameId = getElement(props, 0);
1353
- NodeApiRefHolder propNameRef =
1354
- makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 2);
1355
- jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
1356
- propNameIDs_.try_emplace(
1357
- StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1358
- return result;
1359
- }
1360
-
1361
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromString(
1362
- const jsi::String &str) {
1363
- NodeApiScope scope{*this};
1364
- const NodeApiPointerValue *pv =
1365
- static_cast<const NodeApiPointerValue *>(getPointerValue(str));
1366
- if (pv->getKind() == NodeApiPointerValueKind::StringPropNameID) {
1367
- return make<jsi::PropNameID>(pv->clone(*this));
1368
- }
1369
-
1370
- StringKey keyName(utf8(str));
1371
- auto it = propNameIDs_.find(keyName);
1372
- if (it != propNameIDs_.end()) {
1373
- return make<jsi::PropNameID>(it->second->clone(*this));
1374
- }
1375
-
1376
- napi_value napiStr = const_cast<NodeApiPointerValue *>(pv)->getValue(*this);
1377
-
1378
- napi_value obj = createNodeApiObject();
1379
- setProperty(obj, napiStr, getUndefined());
1380
- napi_value props{};
1381
- CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1382
- env_,
1383
- obj,
1384
- napi_key_own_only,
1385
- napi_key_skip_symbols,
1386
- napi_key_numbers_to_strings,
1387
- &props));
1388
- napi_value propNameId = getElement(props, 0);
1389
- NodeApiRefHolder propNameRef =
1390
- makeNodeApiRef(propNameId, NodeApiPointerValueKind::StringPropNameID, 2);
1391
- jsi::PropNameID result = make<jsi::PropNameID>(propNameRef.get());
1392
- propNameIDs_.try_emplace(
1393
- StringKey(std::string(keyName.getStringView())), std::move(propNameRef));
1394
- return result;
1395
- }
1396
-
1397
- #if JSI_VERSION >= 5
1398
- jsi::PropNameID NodeApiJsiRuntime::createPropNameIDFromSymbol(
1399
- const jsi::Symbol &sym) {
1400
- // TODO: Should we ensure uniqueness of symbols?
1401
- return cloneAs<jsi::PropNameID>(sym);
1402
- }
1403
- #endif
1404
-
1405
- std::string NodeApiJsiRuntime::utf8(const jsi::PropNameID &id) {
1406
- NodeApiScope scope{*this};
1407
- return propertyIdToStdString(getNodeApiValue(id));
1408
- }
1409
-
1410
- bool NodeApiJsiRuntime::compare(
1411
- const jsi::PropNameID &lhs,
1412
- const jsi::PropNameID &rhs) {
1413
- NodeApiScope scope{*this};
1414
- return getPointerValue(lhs) == getPointerValue(rhs) ||
1415
- strictEquals(getNodeApiValue(lhs), getNodeApiValue(rhs));
1416
- }
1417
-
1418
- std::string NodeApiJsiRuntime::symbolToString(const jsi::Symbol &sym) {
1419
- NodeApiScope scope{*this};
1420
- return symbolToStdString(getNodeApiValue(sym));
1421
- }
1422
-
1423
- #if JSI_VERSION >= 8
1424
- jsi::BigInt NodeApiJsiRuntime::createBigIntFromInt64(int64_t val) {
1425
- NodeApiScope scope{*this};
1426
- napi_value bigint{};
1427
- CHECK_NAPI(jsrApi_->napi_create_bigint_int64(env_, val, &bigint));
1428
- return makeJsiPointer<jsi::BigInt>(bigint);
1429
- }
1430
-
1431
- jsi::BigInt NodeApiJsiRuntime::createBigIntFromUint64(uint64_t val) {
1432
- NodeApiScope scope{*this};
1433
- napi_value bigint{};
1434
- CHECK_NAPI(jsrApi_->napi_create_bigint_uint64(env_, val, &bigint));
1435
- return makeJsiPointer<jsi::BigInt>(bigint);
1436
- }
1437
-
1438
- bool NodeApiJsiRuntime::bigintIsInt64(const jsi::BigInt &bigint) {
1439
- NodeApiScope scope{*this};
1440
- napi_value value = getNodeApiValue(bigint);
1441
- bool lossless{false};
1442
- int64_t result{};
1443
- CHECK_NAPI(
1444
- jsrApi_->napi_get_value_bigint_int64(env_, value, &result, &lossless));
1445
- return lossless;
1446
- }
1447
-
1448
- bool NodeApiJsiRuntime::bigintIsUint64(const jsi::BigInt &bigint) {
1449
- NodeApiScope scope{*this};
1450
- napi_value value = getNodeApiValue(bigint);
1451
- bool lossless{false};
1452
- uint64_t result{};
1453
- CHECK_NAPI(
1454
- jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
1455
- return lossless;
1456
- }
1457
-
1458
- uint64_t NodeApiJsiRuntime::truncate(const jsi::BigInt &bigint) {
1459
- NodeApiScope scope{*this};
1460
- napi_value value = getNodeApiValue(bigint);
1461
- bool lossless{false};
1462
- uint64_t result{};
1463
- CHECK_NAPI(
1464
- jsrApi_->napi_get_value_bigint_uint64(env_, value, &result, &lossless));
1465
- return result;
1466
- }
1467
-
1468
- inline uint32_t constexpr maxCharsPerDigitInRadix(int32_t radix) {
1469
- // To compute the lower bound of bits in a BigIntDigitType "covered" by a
1470
- // char. For power of 2 radixes, it is known (exactly) that each character
1471
- // covers log2(radix) bits. For non-power of 2 radixes, a lower bound is
1472
- // log2(greatest power of 2 that is less than radix).
1473
- uint32_t minNumBitsPerChar = radix < 4 ? 1
1474
- : radix < 8 ? 2
1475
- : radix < 16 ? 3
1476
- : radix < 32 ? 4
1477
- : 5;
1478
-
1479
- // With minNumBitsPerChar being the lower bound estimate of how many bits each
1480
- // char can represent, the upper bound of how many chars "fit" in a bigint
1481
- // digit is ceil(sizeofInBits(bigint digit) / minNumBitsPerChar).
1482
- uint32_t numCharsPerDigits =
1483
- static_cast<uint32_t>(sizeof(uint64_t)) / (1 << minNumBitsPerChar);
1484
-
1485
- return numCharsPerDigits;
1486
- }
1487
-
1488
- // Return the high 32 bits of a 64 bit value.
1489
- constexpr inline uint32_t Hi_32(uint64_t Value) {
1490
- return static_cast<uint32_t>(Value >> 32);
1491
- }
1492
-
1493
- // Return the low 32 bits of a 64 bit value.
1494
- constexpr inline uint32_t Lo_32(uint64_t Value) {
1495
- return static_cast<uint32_t>(Value);
1496
- }
1497
-
1498
- // Make a 64-bit integer from a high / low pair of 32-bit integers.
1499
- constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
1500
- return ((uint64_t)High << 32) | (uint64_t)Low;
1501
- }
1502
-
1503
- jsi::String NodeApiJsiRuntime::bigintToString(
1504
- const jsi::BigInt &bigint,
1505
- int32_t radix) {
1506
- NodeApiScope scope{*this};
1507
- if (radix < 2 || radix > 36) {
1508
- throw makeJSError("Invalid radix ", radix, " to BigInt.toString");
1509
- }
1510
-
1511
- napi_value value = getNodeApiValue(bigint);
1512
- size_t wordCount{};
1513
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(
1514
- env_, value, nullptr, &wordCount, nullptr));
1515
- uint64_t stackWords[8]{};
1516
- std::unique_ptr<uint64_t[]> heapWords;
1517
- uint64_t *words = stackWords;
1518
- if (wordCount > std::size(stackWords)) {
1519
- heapWords = std::unique_ptr<uint64_t[]>(new uint64_t[wordCount]);
1520
- words = heapWords.get();
1521
- }
1522
- int32_t signBit{};
1523
- CHECK_NAPI(jsrApi_->napi_get_value_bigint_words(
1524
- env_, value, &signBit, &wordCount, words));
1525
-
1526
- if (wordCount == 0) {
1527
- return createStringFromAscii("0", 1);
1528
- }
1529
-
1530
- // avoid trashing the heap by pre-allocating the largest possible string
1531
- // returned by this function. The "1" below is to account for a possible "-"
1532
- // sign.
1533
- std::string digits;
1534
- digits.reserve(1 + wordCount * maxCharsPerDigitInRadix(radix));
1535
-
1536
- // Use 32-bit values for calculations to get 64-bit results.
1537
- // For the little-endian machines we just cast the words array.
1538
- // TODO: Add support for big-endian.
1539
- uint32_t *halfWords = reinterpret_cast<uint32_t *>(words);
1540
- size_t count = wordCount * 2;
1541
- for (size_t i = count; i > 0 && halfWords[i - 1] == 0; --i) {
1542
- --count;
1543
- }
1544
-
1545
- uint32_t divisor = static_cast<uint32_t>(radix);
1546
- uint32_t remainder = 0;
1547
- uint64_t word0 = words[0];
1548
-
1549
- do {
1550
- // We rewrite the halfWords array as we divide it by radix.
1551
- if (count <= 2) {
1552
- remainder = word0 % divisor;
1553
- word0 = word0 / divisor;
1554
- } else {
1555
- for (size_t i = count; i > 0; --i) {
1556
- uint64_t partialDividend = Make_64(remainder, halfWords[i - 1]);
1557
- if (partialDividend == 0) {
1558
- halfWords[i] = 0;
1559
- remainder = 0;
1560
- if (i == count) {
1561
- if (--count == 2) {
1562
- word0 = words[0];
1563
- }
1564
- }
1565
- } else if (partialDividend < divisor) {
1566
- halfWords[i] = 0;
1567
- remainder = Lo_32(partialDividend);
1568
- if (i == count) {
1569
- if (--count == 2) {
1570
- word0 = words[0];
1571
- }
1572
- }
1573
- } else if (partialDividend == divisor) {
1574
- halfWords[i] = 1;
1575
- remainder = 0;
1576
- } else {
1577
- halfWords[i] = Lo_32(partialDividend / divisor);
1578
- remainder = Lo_32(partialDividend % divisor);
1579
- }
1580
- }
1581
- }
1582
-
1583
- if (remainder < 10) {
1584
- digits.push_back(static_cast<char>('0' + remainder));
1585
- } else {
1586
- digits.push_back(static_cast<char>('a' + remainder - 10));
1587
- }
1588
- } while (count > 2 || word0 != 0);
1589
-
1590
- if (signBit) {
1591
- digits.push_back('-');
1592
- }
1593
-
1594
- std::reverse(digits.begin(), digits.end());
1595
- return createStringFromAscii(digits.data(), digits.size());
1596
- }
1597
- #endif
1598
-
1599
- jsi::String NodeApiJsiRuntime::createStringFromAscii(
1600
- const char *str,
1601
- size_t length) {
1602
- NodeApiScope scope{*this};
1603
- return makeJsiPointer<jsi::String>(createStringLatin1({str, length}));
1604
- }
1605
-
1606
- jsi::String NodeApiJsiRuntime::createStringFromUtf8(
1607
- const uint8_t *str,
1608
- size_t length) {
1609
- NodeApiScope scope{*this};
1610
- return makeJsiPointer<jsi::String>(createStringUtf8(str, length));
1611
- }
1612
-
1613
- std::string NodeApiJsiRuntime::utf8(const jsi::String &str) {
1614
- NodeApiScope scope{*this};
1615
- return stringToStdString(getNodeApiValue(str));
1616
- }
1617
-
1618
- jsi::Object NodeApiJsiRuntime::createObject() {
1619
- NodeApiScope scope{*this};
1620
- return makeJsiPointer<jsi::Object>(createNodeApiObject());
1621
- }
1622
-
1623
- jsi::Object NodeApiJsiRuntime::createObject(
1624
- std::shared_ptr<jsi::HostObject> hostObject) {
1625
- NodeApiScope scope{*this};
1626
- // The hostObjectHolder keeps the hostObject as external data.
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.
1631
- napi_value hostObjectHolder =
1632
- createExternalObject(std::make_unique<std::shared_ptr<jsi::HostObject>>(
1633
- std::move(hostObject)));
1634
- napi_value obj = createNodeApiObject();
1635
- setProperty(
1636
- obj, getNodeApiValue(propertyId_.hostObjectSymbol), hostObjectHolder);
1637
- if (!cachedValue_.ProxyConstructor) {
1638
- cachedValue_.ProxyConstructor = makeNodeApiRef(
1639
- getProperty(
1640
- getNodeApiValue(cachedValue_.Global),
1641
- getNodeApiValue(propertyId_.Proxy)),
1642
- NodeApiPointerValueKind::Object);
1643
- }
1644
- napi_value args[] = {obj, getHostObjectProxyHandler()};
1645
- napi_value proxy =
1646
- constructObject(getNodeApiValue(cachedValue_.ProxyConstructor), args);
1647
- return makeJsiPointer<jsi::Object>(proxy);
1648
- }
1649
-
1650
- std::shared_ptr<jsi::HostObject> NodeApiJsiRuntime::getHostObject(
1651
- const jsi::Object &obj) {
1652
- NodeApiScope scope{*this};
1653
- return getJsiHostObject(getNodeApiValue(obj));
1654
- }
1655
-
1656
- jsi::HostFunctionType &NodeApiJsiRuntime::getHostFunction(
1657
- const jsi::Function &func) {
1658
- NodeApiScope scope{*this};
1659
- napi_value hostFunctionHolder = getProperty(
1660
- getNodeApiValue(func), getNodeApiValue((propertyId_.hostFunctionSymbol)));
1661
- if (typeOf(hostFunctionHolder) == napi_valuetype::napi_external) {
1662
- return static_cast<HostFunctionWrapper *>(
1663
- getExternalData(hostFunctionHolder))
1664
- ->hostFunction();
1665
- } else {
1666
- throw jsi::JSINativeException(
1667
- "getHostFunction() can only be called with HostFunction.");
1668
- }
1669
- }
1670
-
1671
- #if JSI_VERSION >= 7
1672
- bool NodeApiJsiRuntime::hasNativeState(const jsi::Object &obj) {
1673
- NodeApiScope scope{*this};
1674
- void *nativeState{};
1675
- napi_status status =
1676
- jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState);
1677
- return status == napi_ok && nativeState != nullptr;
1678
- }
1679
-
1680
- std::shared_ptr<jsi::NativeState> NodeApiJsiRuntime::getNativeState(
1681
- const jsi::Object &obj) {
1682
- NodeApiScope scope{*this};
1683
- void *nativeState{};
1684
- CHECK_NAPI(jsrApi_->napi_unwrap(env_, getNodeApiValue(obj), &nativeState));
1685
- if (nativeState != nullptr) {
1686
- return *reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(nativeState);
1687
- } else {
1688
- return std::shared_ptr<jsi::NativeState>();
1689
- }
1690
- }
1691
-
1692
- void NodeApiJsiRuntime::setNativeState(
1693
- const jsi::Object &obj,
1694
- std::shared_ptr<jsi::NativeState> state) {
1695
- NodeApiScope scope{*this};
1696
- if (hasNativeState(obj)) {
1697
- void *nativeState{};
1698
- CHECK_NAPI(
1699
- jsrApi_->napi_remove_wrap(env_, getNodeApiValue(obj), &nativeState));
1700
- if (nativeState != nullptr) {
1701
- std::shared_ptr<jsi::NativeState> oldState{std::move(
1702
- *reinterpret_cast<std::shared_ptr<jsi::NativeState> *>(nativeState))};
1703
- }
1704
- }
1705
-
1706
- if (state) {
1707
- CHECK_NAPI(jsrApi_->napi_wrap(
1708
- env_,
1709
- getNodeApiValue(obj),
1710
- new std::shared_ptr<jsi::NativeState>(std::move(state)),
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))};
1714
- },
1715
- nullptr,
1716
- nullptr));
1717
- }
1718
- }
1719
- #endif
1720
-
1721
- jsi::Value NodeApiJsiRuntime::getProperty(
1722
- const jsi::Object &obj,
1723
- const jsi::PropNameID &name) {
1724
- NodeApiScope scope{*this};
1725
- return toJsiValue(getProperty(getNodeApiValue(obj), getNodeApiValue(name)));
1726
- }
1727
-
1728
- jsi::Value NodeApiJsiRuntime::getProperty(
1729
- const jsi::Object &obj,
1730
- const jsi::String &name) {
1731
- NodeApiScope scope{*this};
1732
- return toJsiValue(getProperty(getNodeApiValue(obj), getNodeApiValue(name)));
1733
- }
1734
-
1735
- bool NodeApiJsiRuntime::hasProperty(
1736
- const jsi::Object &obj,
1737
- const jsi::PropNameID &name) {
1738
- NodeApiScope scope{*this};
1739
- return hasProperty(getNodeApiValue(obj), getNodeApiValue(name));
1740
- }
1741
-
1742
- bool NodeApiJsiRuntime::hasProperty(
1743
- const jsi::Object &obj,
1744
- const jsi::String &name) {
1745
- NodeApiScope scope{*this};
1746
- return hasProperty(getNodeApiValue(obj), getNodeApiValue(name));
1747
- }
1748
-
1749
- void NodeApiJsiRuntime::setPropertyValue(
1750
- JSI_CONST_10 jsi::Object &obj,
1751
- const jsi::PropNameID &name,
1752
- const jsi::Value &value) {
1753
- NodeApiScope scope{*this};
1754
- setProperty(
1755
- getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
1756
- }
1757
-
1758
- void NodeApiJsiRuntime::setPropertyValue(
1759
- JSI_CONST_10 jsi::Object &obj,
1760
- const jsi::String &name,
1761
- const jsi::Value &value) {
1762
- NodeApiScope scope{*this};
1763
- setProperty(
1764
- getNodeApiValue(obj), getNodeApiValue(name), getNodeApiValue(value));
1765
- }
1766
-
1767
- bool NodeApiJsiRuntime::isArray(const jsi::Object &obj) const {
1768
- NodeApiScope scope{*this};
1769
- return isArray(getNodeApiValue(obj));
1770
- }
1771
-
1772
- bool NodeApiJsiRuntime::isArrayBuffer(const jsi::Object &obj) const {
1773
- NodeApiScope scope{*this};
1774
- bool result{};
1775
- CHECK_NAPI(jsrApi_->napi_is_arraybuffer(env_, getNodeApiValue(obj), &result));
1776
- return result;
1777
- }
1778
-
1779
- bool NodeApiJsiRuntime::isFunction(const jsi::Object &obj) const {
1780
- NodeApiScope scope{*this};
1781
- return typeOf(getNodeApiValue(obj)) == napi_valuetype::napi_function;
1782
- }
1783
-
1784
- bool NodeApiJsiRuntime::isHostObject(const jsi::Object &obj) const {
1785
- NodeApiScope scope{*this};
1786
- napi_value hostObjectHolder = getProperty(
1787
- getNodeApiValue(obj), getNodeApiValue(propertyId_.hostObjectSymbol));
1788
- if (typeOf(hostObjectHolder) == napi_valuetype::napi_external) {
1789
- return getExternalData(hostObjectHolder) != nullptr;
1790
- } else {
1791
- return false;
1792
- }
1793
- }
1794
-
1795
- bool NodeApiJsiRuntime::isHostFunction(const jsi::Function &func) const {
1796
- NodeApiScope scope{*this};
1797
- napi_value hostFunctionHolder = getProperty(
1798
- getNodeApiValue(func), getNodeApiValue(propertyId_.hostFunctionSymbol));
1799
- if (typeOf(hostFunctionHolder) == napi_valuetype::napi_external) {
1800
- return getExternalData(hostFunctionHolder) != nullptr;
1801
- } else {
1802
- return false;
1803
- }
1804
- }
1805
-
1806
- jsi::Array NodeApiJsiRuntime::getPropertyNames(const jsi::Object &obj) {
1807
- NodeApiScope scope{*this};
1808
- napi_value properties;
1809
- CHECK_NAPI(jsrApi_->napi_get_all_property_names(
1810
- env_,
1811
- getNodeApiValue(obj),
1812
- napi_key_collection_mode::napi_key_include_prototypes,
1813
- napi_key_filter(napi_key_enumerable | napi_key_skip_symbols),
1814
- napi_key_numbers_to_strings,
1815
- &properties));
1816
- return makeJsiPointer<jsi::Object>(properties).asArray(*this);
1817
- }
1818
-
1819
- jsi::WeakObject NodeApiJsiRuntime::createWeakObject(const jsi::Object &obj) {
1820
- NodeApiScope scope{*this};
1821
- return make<jsi::WeakObject>(NodeApiRefCountedPointerValue::make(
1822
- *const_cast<NodeApiJsiRuntime *>(this),
1823
- getNodeApiValue(obj),
1824
- NodeApiPointerValueKind::WeakObject)
1825
- .release());
1826
- }
1827
-
1828
- jsi::Value NodeApiJsiRuntime::lockWeakObject(
1829
- JSI_NO_CONST_3 JSI_CONST_10 jsi::WeakObject &weakObject) {
1830
- NodeApiScope scope{*this};
1831
- napi_value value = getNodeApiValue(weakObject);
1832
- if (value) {
1833
- return toJsiValue(value);
1834
- } else {
1835
- return jsi::Value::undefined();
1836
- }
1837
- }
1838
-
1839
- jsi::Array NodeApiJsiRuntime::createArray(size_t length) {
1840
- NodeApiScope scope{*this};
1841
- return makeJsiPointer<jsi::Object>(createNodeApiArray(length)).asArray(*this);
1842
- }
1843
-
1844
- #if JSI_VERSION >= 9
1845
- jsi::ArrayBuffer NodeApiJsiRuntime::createArrayBuffer(
1846
- std::shared_ptr<jsi::MutableBuffer> buffer) {
1847
- NodeApiScope scope{*this};
1848
- napi_value result{};
1849
- void *data = buffer->data();
1850
- size_t size = buffer->size();
1851
- CHECK_NAPI(jsrApi_->napi_create_external_arraybuffer(
1852
- env_,
1853
- data,
1854
- size,
1855
- [](node_api_nogc_env /*env*/, void * /*data*/, void *finalizeHint) {
1856
- std::shared_ptr<jsi::MutableBuffer> buffer{
1857
- std::move(*reinterpret_cast<std::shared_ptr<jsi::MutableBuffer> *>(
1858
- finalizeHint))};
1859
- },
1860
- new std::shared_ptr<jsi::MutableBuffer>{std::move(buffer)},
1861
- &result));
1862
- return makeJsiPointer<jsi::Object>(result).getArrayBuffer(*this);
1863
- }
1864
- #endif
1865
-
1866
- size_t NodeApiJsiRuntime::size(const jsi::Array &arr) {
1867
- NodeApiScope scope{*this};
1868
- return getArrayLength(getNodeApiValue(arr));
1869
- }
1870
-
1871
- size_t NodeApiJsiRuntime::size(const jsi::ArrayBuffer &arrBuf) {
1872
- NodeApiScope scope{*this};
1873
- size_t result{};
1874
- CHECK_NAPI(jsrApi_->napi_get_arraybuffer_info(
1875
- env_, getNodeApiValue(arrBuf), nullptr, &result));
1876
- return result;
1877
- }
1878
-
1879
- uint8_t *NodeApiJsiRuntime::data(const jsi::ArrayBuffer &arrBuf) {
1880
- NodeApiScope scope{*this};
1881
- uint8_t *result{};
1882
- CHECK_NAPI(jsrApi_->napi_get_arraybuffer_info(
1883
- env_,
1884
- getNodeApiValue(arrBuf),
1885
- reinterpret_cast<void **>(&result),
1886
- nullptr));
1887
- return result;
1888
- }
1889
-
1890
- jsi::Value NodeApiJsiRuntime::getValueAtIndex(
1891
- const jsi::Array &arr,
1892
- size_t index) {
1893
- NodeApiScope scope{*this};
1894
- return toJsiValue(getElement(getNodeApiValue(arr), index));
1895
- }
1896
-
1897
- void NodeApiJsiRuntime::setValueAtIndexImpl(
1898
- JSI_CONST_10 jsi::Array &arr,
1899
- size_t index,
1900
- const jsi::Value &value) {
1901
- NodeApiScope scope{*this};
1902
- setElement(
1903
- getNodeApiValue(arr),
1904
- static_cast<uint32_t>(index),
1905
- getNodeApiValue(value));
1906
- }
1907
-
1908
- jsi::Function NodeApiJsiRuntime::createFunctionFromHostFunction(
1909
- const jsi::PropNameID &name,
1910
- unsigned int paramCount,
1911
- jsi::HostFunctionType func) {
1912
- NodeApiScope scope{*this};
1913
- auto hostFunctionWrapper =
1914
- std::make_unique<HostFunctionWrapper>(std::move(func), *this);
1915
- napi_value function = createExternalFunction(
1916
- getNodeApiValue(name),
1917
- static_cast<int32_t>(paramCount),
1918
- jsiHostFunctionCallback,
1919
- hostFunctionWrapper.get());
1920
-
1921
- const napi_value hostFunctionHolder =
1922
- createExternalObject(std::move(hostFunctionWrapper));
1923
- setProperty(
1924
- function,
1925
- getNodeApiValue(propertyId_.hostFunctionSymbol),
1926
- hostFunctionHolder,
1927
- napi_property_attributes::napi_default);
1928
- return makeJsiPointer<jsi::Object>(function).getFunction(*this);
1929
- }
1930
-
1931
- jsi::Value NodeApiJsiRuntime::call(
1932
- const jsi::Function &func,
1933
- const jsi::Value &jsThis,
1934
- const jsi::Value *args,
1935
- size_t count) {
1936
- NodeApiScope scope{*this};
1937
- return toJsiValue(callFunction(
1938
- getNodeApiValue(jsThis),
1939
- getNodeApiValue(func),
1940
- NodeApiValueArgs(*this, span<const jsi::Value>(args, count))));
1941
- }
1942
-
1943
- jsi::Value NodeApiJsiRuntime::callAsConstructor(
1944
- const jsi::Function &func,
1945
- const jsi::Value *args,
1946
- size_t count) {
1947
- NodeApiScope scope{*this};
1948
- return toJsiValue(constructObject(
1949
- getNodeApiValue(func),
1950
- NodeApiValueArgs(*this, span<jsi::Value const>(args, count))));
1951
- }
1952
-
1953
- jsi::Runtime::ScopeState *NodeApiJsiRuntime::pushScope() {
1954
- napi_handle_scope result{};
1955
- CHECK_NAPI(jsrApi_->napi_open_handle_scope(env_, &result));
1956
- pushPointerValueScope();
1957
- return reinterpret_cast<jsi::Runtime::ScopeState *>(result);
1958
- }
1959
-
1960
- void NodeApiJsiRuntime::popScope(jsi::Runtime::ScopeState *state) {
1961
- popPointerValueScope();
1962
- CHECK_NAPI(jsrApi_->napi_close_handle_scope(
1963
- env_, reinterpret_cast<napi_handle_scope>(state)));
1964
- }
1965
-
1966
- bool NodeApiJsiRuntime::strictEquals(const jsi::Symbol &a, const jsi::Symbol &b)
1967
- const {
1968
- NodeApiScope scope{*this};
1969
- return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1970
- }
1971
-
1972
- #if JSI_VERSION >= 6
1973
- bool NodeApiJsiRuntime::strictEquals(const jsi::BigInt &a, const jsi::BigInt &b)
1974
- const {
1975
- NodeApiScope scope{*this};
1976
- return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1977
- }
1978
- #endif
1979
-
1980
- bool NodeApiJsiRuntime::strictEquals(const jsi::String &a, const jsi::String &b)
1981
- const {
1982
- NodeApiScope scope{*this};
1983
- return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1984
- }
1985
-
1986
- bool NodeApiJsiRuntime::strictEquals(const jsi::Object &a, const jsi::Object &b)
1987
- const {
1988
- NodeApiScope scope{*this};
1989
- return strictEquals(getNodeApiValue(a), getNodeApiValue(b));
1990
- }
1991
-
1992
- bool NodeApiJsiRuntime::instanceOf(
1993
- const jsi::Object &obj,
1994
- const jsi::Function &func) {
1995
- NodeApiScope scope{*this};
1996
- return instanceOf(getNodeApiValue(obj), getNodeApiValue(func));
1997
- }
1998
-
1999
- #if JSI_VERSION >= 11
2000
- void NodeApiJsiRuntime::setExternalMemoryPressure(
2001
- const jsi::Object & /*obj*/,
2002
- size_t /*amount*/) {
2003
- // TODO: implement
2004
- }
2005
- #endif
2006
-
2007
- //=====================================================================================================================
2008
- // NodeApiJsiRuntime::NodeApiScope implementation
2009
- //=====================================================================================================================
2010
-
2011
- NodeApiJsiRuntime::NodeApiScope::NodeApiScope(
2012
- const NodeApiJsiRuntime &runtime) noexcept
2013
- : NodeApiScope(const_cast<NodeApiJsiRuntime &>(runtime)) {}
2014
-
2015
- NodeApiJsiRuntime::NodeApiScope::NodeApiScope(
2016
- NodeApiJsiRuntime &runtime) noexcept
2017
- : runtime_(runtime),
2018
- envScope_(runtime_.getEnv()),
2019
- scopeState_(runtime_.pushScope()) {
2020
- runtime_.pushPointerValueScope();
2021
- }
2022
-
2023
- NodeApiJsiRuntime::NodeApiScope::~NodeApiScope() noexcept {
2024
- runtime_.popPointerValueScope();
2025
- runtime_.popScope(scopeState_);
2026
- }
2027
-
2028
- //=====================================================================================================================
2029
- // NodeApiJsiRuntime::NodeApiPointerValueScope implementation
2030
- //=====================================================================================================================
2031
-
2032
- NodeApiJsiRuntime::NodeApiPointerValueScope::NodeApiPointerValueScope(
2033
- NodeApiJsiRuntime &runtime) noexcept
2034
- : runtime_(runtime) {
2035
- runtime_.pushPointerValueScope();
2036
- }
2037
-
2038
- NodeApiJsiRuntime::NodeApiPointerValueScope::
2039
- ~NodeApiPointerValueScope() noexcept {
2040
- runtime_.popPointerValueScope();
2041
- }
2042
-
2043
- //=====================================================================================================================
2044
- // NodeApiJsiRuntime::AutoRestore implementation
2045
- //=====================================================================================================================
2046
-
2047
- template <typename T>
2048
- NodeApiJsiRuntime::AutoRestore<T>::AutoRestore(T &varRef, T newValue)
2049
- : varRef_{varRef}, oldValue_{std::exchange(varRef, newValue)} {}
2050
-
2051
- template <typename T>
2052
- NodeApiJsiRuntime::AutoRestore<T>::~AutoRestore() {
2053
- varRef_ = oldValue_;
2054
- }
2055
-
2056
- //=====================================================================================================================
2057
- // NodeApiJsiRuntime::NodeApiStackOnlyPointerValue implementation
2058
- //=====================================================================================================================
2059
-
2060
- NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::NodeApiStackOnlyPointerValue(
2061
- napi_value value,
2062
- NodeApiPointerValueKind pointerKind) noexcept
2063
- : value_(value), pointerKind_(pointerKind) {}
2064
-
2065
- // Intentionally do nothing since the value is allocated on the stack.
2066
- void NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::invalidate() noexcept {}
2067
-
2068
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2069
- NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::clone(
2070
- NodeApiJsiRuntime &runtime) const noexcept {
2071
- return NodeApiRefCountedPointerValue::make(runtime, value_, pointerKind_)
2072
- .release();
2073
- }
2074
-
2075
- napi_value NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getValue(
2076
- NodeApiJsiRuntime & /*runtime*/) noexcept {
2077
- return value_;
2078
- }
2079
-
2080
- NodeApiJsiRuntime::NodeApiPointerValueKind
2081
- NodeApiJsiRuntime::NodeApiStackOnlyPointerValue::getKind() const noexcept {
2082
- return pointerKind_;
2083
- }
2084
-
2085
- //=====================================================================================================================
2086
- // NodeApiJsiRuntime::NodeApiPointerValue implementation
2087
- //=====================================================================================================================
2088
-
2089
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue::NodeApiRefCountedPointerValue(
2090
- NodeApiJsiRuntime &runtime,
2091
- napi_value value,
2092
- NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
2093
- int32_t initialRefCount) noexcept
2094
- : pendingDeletions_(runtime.pendingDeletions_),
2095
- value_(value),
2096
- refCount_(initialRefCount),
2097
- pointerKind_(pointerKind) {}
2098
-
2099
- /*static*/ NodeApiJsiRuntime::NodeApiRefHolder
2100
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue::make(
2101
- NodeApiJsiRuntime &runtime,
2102
- napi_value value,
2103
- NodeApiJsiRuntime::NodeApiPointerValueKind pointerKind,
2104
- int32_t initialRefCount) {
2105
- NodeApiRefHolder result{
2106
- new NodeApiRefCountedPointerValue(
2107
- runtime, value, pointerKind, initialRefCount),
2108
- attachTag};
2109
- runtime.addStackValue(NodeApiStackValuePtr{result.get()});
2110
- return result;
2111
- }
2112
-
2113
- /*static*/ NodeApiJsiRuntime::NodeApiRefHolder
2114
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue::makeNodeApiRef(
2115
- NodeApiJsiRuntime &runtime,
2116
- napi_value value,
2117
- NodeApiPointerValueKind pointerKind,
2118
- int32_t initialRefCount) {
2119
- NodeApiRefHolder result{make(runtime, value, pointerKind, initialRefCount)};
2120
- result->createNodeApiRef(runtime);
2121
- return result;
2122
- }
2123
-
2124
- void NodeApiJsiRuntime::NodeApiRefCountedPointerValue::invalidate() noexcept {
2125
- decRefCount();
2126
- }
2127
-
2128
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2129
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue::clone(
2130
- NodeApiJsiRuntime & /*runtime*/) const noexcept {
2131
- incRefCount();
2132
- return const_cast<NodeApiRefCountedPointerValue *>(this);
2133
- }
2134
-
2135
- napi_value NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getValue(
2136
- NodeApiJsiRuntime &runtime) noexcept {
2137
- if (value_ != nullptr) {
2138
- return value_;
2139
- }
2140
-
2141
- if (ref_ == nullptr) {
2142
- return nullptr;
2143
- }
2144
-
2145
- JSRuntimeApi *jsrApi = JSRuntimeApi::current();
2146
- if (pointerKind_ == NodeApiPointerValueKind::Object ||
2147
- pointerKind_ == NodeApiPointerValueKind::WeakObject) {
2148
- CHECK_NAPI_ELSE_CRASH(
2149
- jsrApi->napi_get_reference_value(runtime.getEnv(), ref_, &value_));
2150
- } else {
2151
- napi_value obj{};
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_));
2157
- }
2158
-
2159
- if (value_ != nullptr) {
2160
- runtime.addStackValue(NodeApiStackValuePtr(this));
2161
- }
2162
-
2163
- return value_;
2164
- }
2165
-
2166
- NodeApiJsiRuntime::NodeApiPointerValueKind
2167
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue::getKind() const noexcept {
2168
- return pointerKind_;
2169
- }
2170
-
2171
- bool NodeApiJsiRuntime::NodeApiRefCountedPointerValue::usedByJsiPointer()
2172
- const noexcept {
2173
- return !NodeApiRefCount::isZero(refCount_);
2174
- }
2175
-
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;
2181
- return;
2182
- }
2183
-
2184
- if (usedByJsiPointer() && ref_ == nullptr) {
2185
- createNodeApiRef(runtime);
2186
- }
2187
-
2188
- value_ = nullptr;
2189
- }
2190
-
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;
2203
- }
2204
- }
2205
-
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;
2215
- }
2216
- }
2217
-
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
- }
2229
- }
2230
-
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)));
2241
- }
2242
- }
2243
-
2244
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
2245
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue::createNodeApiRef(
2246
- NodeApiJsiRuntime &runtime) {
2247
- JSRuntimeApi *jsrApi = JSRuntimeApi::current();
2248
- CHECK_ELSE_CRASH(value_ != nullptr, "value_ must not be null");
2249
- CHECK_ELSE_CRASH(ref_ == nullptr, "ref_ must be null");
2250
- if (pointerKind_ == NodeApiPointerValueKind::Object) {
2251
- CHECK_NAPI_ELSE_CRASH(
2252
- jsrApi->napi_create_reference(runtime.getEnv(), value_, 1, &ref_));
2253
- } else if (pointerKind_ != NodeApiPointerValueKind::WeakObject) {
2254
- napi_value obj{};
2255
- CHECK_NAPI_ELSE_CRASH(jsrApi->napi_create_object(runtime.getEnv(), &obj));
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_));
2260
- } else {
2261
- CHECK_NAPI_ELSE_CRASH(
2262
- jsrApi->napi_create_reference(runtime.getEnv(), value_, 0, &ref_));
2263
- }
2264
- return this;
2265
- }
2266
-
2267
- //=====================================================================================================================
2268
- // NodeApiJsiRuntime::SmallBuffer implementation
2269
- //=====================================================================================================================
2270
-
2271
- template <typename T, size_t InplaceSize>
2272
- NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::SmallBuffer(
2273
- size_t size) noexcept
2274
- : size_{size},
2275
- heapData_{size_ > InplaceSize ? std::make_unique<T[]>(size_) : nullptr} {}
2276
-
2277
- template <typename T, size_t InplaceSize>
2278
- T *NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::data() noexcept {
2279
- return heapData_ ? heapData_.get() : stackData_.data();
2280
- }
2281
-
2282
- template <typename T, size_t InplaceSize>
2283
- size_t NodeApiJsiRuntime::SmallBuffer<T, InplaceSize>::size() const noexcept {
2284
- return size_;
2285
- }
2286
-
2287
- //=====================================================================================================================
2288
- // NodeApiJsiRuntime::NodeApiValueArgs implementation
2289
- //=====================================================================================================================
2290
-
2291
- NodeApiJsiRuntime::NodeApiValueArgs::NodeApiValueArgs(
2292
- NodeApiJsiRuntime &runtime,
2293
- span<const jsi::Value> args)
2294
- : args_{args.size()} {
2295
- napi_value *jsArgs = args_.data();
2296
- for (size_t i = 0; i < args.size(); ++i) {
2297
- jsArgs[i] = runtime.getNodeApiValue(args[i]);
2298
- }
2299
- }
2300
-
2301
- NodeApiJsiRuntime::NodeApiValueArgs::operator span<napi_value>() {
2302
- return span<napi_value>{args_.data(), args_.size()};
2303
- }
2304
-
2305
- //=====================================================================================================================
2306
- // NodeApiJsiRuntime::JsiValueView implementation
2307
- //=====================================================================================================================
2308
-
2309
- NodeApiJsiRuntime::JsiValueView::JsiValueView(
2310
- NodeApiJsiRuntime *runtime,
2311
- napi_value jsValue)
2312
- : value_{initValue(runtime, jsValue, std::addressof(pointerStore_))} {}
2313
-
2314
- NodeApiJsiRuntime::JsiValueView::operator const jsi::Value &() const noexcept {
2315
- return value_;
2316
- }
2317
-
2318
- /*static*/ jsi::Value NodeApiJsiRuntime::JsiValueView::initValue(
2319
- NodeApiJsiRuntime *runtime,
2320
- napi_value value,
2321
- StoreType *store) {
2322
- switch (runtime->typeOf(value)) {
2323
- case napi_valuetype::napi_undefined:
2324
- return jsi::Value::undefined();
2325
- case napi_valuetype::napi_null:
2326
- return jsi::Value::null();
2327
- case napi_valuetype::napi_boolean:
2328
- return jsi::Value{runtime->getValueBool(value)};
2329
- case napi_valuetype::napi_number:
2330
- return jsi::Value{runtime->getValueDouble(value)};
2331
- case napi_valuetype::napi_string:
2332
- return make<jsi::String>(new (store) NodeApiStackOnlyPointerValue(
2333
- value, NodeApiPointerValueKind::String));
2334
- case napi_valuetype::napi_symbol:
2335
- return make<jsi::Symbol>(new (store) NodeApiStackOnlyPointerValue(
2336
- value, NodeApiPointerValueKind::Symbol));
2337
- case napi_valuetype::napi_object:
2338
- case napi_valuetype::napi_function:
2339
- case napi_valuetype::napi_external:
2340
- return make<jsi::Object>(new (store) NodeApiStackOnlyPointerValue(
2341
- value, NodeApiPointerValueKind::Object));
2342
- #if JSI_VERSION >= 8
2343
- case napi_valuetype::napi_bigint:
2344
- return make<jsi::BigInt>(new (store) NodeApiStackOnlyPointerValue(
2345
- value, NodeApiPointerValueKind::BigInt));
2346
- #endif
2347
- default:
2348
- throw jsi::JSINativeException("Unexpected value type");
2349
- }
2350
- }
2351
-
2352
- //=====================================================================================================================
2353
- // NodeApiJsiRuntime::JsiValueViewArgs implementation
2354
- //=====================================================================================================================
2355
-
2356
- NodeApiJsiRuntime::JsiValueViewArgs::JsiValueViewArgs(
2357
- NodeApiJsiRuntime *runtime,
2358
- span<napi_value> args) noexcept
2359
- : pointerStore_{args.size()}, args_{args.size()} {
2360
- JsiValueView::StoreType *pointerStore = pointerStore_.data();
2361
- jsi::Value *jsiArgs = args_.data();
2362
- for (size_t i = 0; i < args_.size(); ++i) {
2363
- jsiArgs[i] = JsiValueView::initValue(
2364
- runtime, args[i], std::addressof(pointerStore[i]));
2365
- }
2366
- }
2367
-
2368
- jsi::Value const *NodeApiJsiRuntime::JsiValueViewArgs::data() noexcept {
2369
- return args_.data();
2370
- }
2371
-
2372
- size_t NodeApiJsiRuntime::JsiValueViewArgs::size() const noexcept {
2373
- return args_.size();
2374
- }
2375
-
2376
- //=====================================================================================================================
2377
- // NodeApiJsiRuntime::PropNameIDView implementation
2378
- //=====================================================================================================================
2379
-
2380
- // TODO: account for symbol
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 {
2391
- return propertyId_;
2392
- }
2393
-
2394
- //=====================================================================================================================
2395
- // NodeApiJsiRuntime::HostFunctionWrapper implementation
2396
- //=====================================================================================================================
2397
-
2398
- NodeApiJsiRuntime::HostFunctionWrapper::HostFunctionWrapper(
2399
- jsi::HostFunctionType &&type,
2400
- NodeApiJsiRuntime &runtime)
2401
- : hostFunction_{std::move(type)}, runtime_{runtime} {}
2402
-
2403
- jsi::HostFunctionType &
2404
- NodeApiJsiRuntime::HostFunctionWrapper::hostFunction() noexcept {
2405
- return hostFunction_;
2406
- }
2407
-
2408
- NodeApiJsiRuntime &NodeApiJsiRuntime::HostFunctionWrapper::runtime() noexcept {
2409
- return runtime_;
2410
- }
2411
-
2412
- //=====================================================================================================================
2413
- // NodeApiJsiRuntime implementation
2414
- //=====================================================================================================================
2415
-
2416
- template <typename... Args>
2417
- jsi::JSError NodeApiJsiRuntime::makeJSError(Args &&...args) {
2418
- std::ostringstream errorStream;
2419
- ((errorStream << std::forward<Args>(args)), ...);
2420
- return jsi::JSError(*this, errorStream.str());
2421
- }
2422
-
2423
- // Throws jsi::JSError or jsi::JSINativeException from Node-API error.
2424
- [[noreturn]] void NodeApiJsiRuntime::throwJSException(
2425
- napi_status status) const {
2426
- napi_value 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));
2431
-
2432
- if (!hasPendingJSError_ &&
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));
2442
- } else {
2443
- std::ostringstream errorStream;
2444
- errorStream << "A call to Node-API returned error code 0x" << std::hex
2445
- << status << '.';
2446
- throw jsi::JSINativeException(errorStream.str().c_str());
2447
- }
2448
- }
2449
-
2450
- // Throws jsi::JSINativeException with a message.
2451
- [[noreturn]] void NodeApiJsiRuntime::throwNativeException(
2452
- char const *errorMessage) const {
2453
- throw jsi::JSINativeException(errorMessage);
2454
- }
2455
-
2456
- // Rewrites error messages to match the JSI unit test expectations.
2457
- void NodeApiJsiRuntime::rewriteErrorMessage(napi_value jsError) const {
2458
- // The code below must work correctly even if the 'message' getter throws.
2459
- // In case when it throws, we ignore that exception.
2460
- napi_value message{};
2461
- napi_status status = jsrApi_->napi_get_property(
2462
- env_, jsError, getNodeApiValue(propertyId_.message), &message);
2463
- if (status != napi_ok) {
2464
- // If the 'message' property getter throws, then we clear the exception and
2465
- // ignore it.
2466
- napi_value ignoreJSError{};
2467
- jsrApi_->napi_get_and_clear_last_exception(env_, &ignoreJSError);
2468
- } else if (typeOf(message) == napi_string) {
2469
- // JSI unit tests expect V8- or JSC-like messages for the stack overflow.
2470
- if (stringToStdString(message) == "Out of stack space") {
2471
- setProperty(
2472
- jsError,
2473
- getNodeApiValue(propertyId_.message),
2474
- createStringUtf8("RangeError : Maximum call stack size exceeded"sv));
2475
- }
2476
- }
2477
-
2478
- // Make sure that the call stack has the current URL
2479
- if (!sourceURL_.empty()) {
2480
- napi_value stack{};
2481
- status = jsrApi_->napi_get_property(
2482
- env_, jsError, getNodeApiValue(propertyId_.stack), &stack);
2483
- if (status != napi_ok) {
2484
- // If the 'stack' property getter throws, then we clear the exception and
2485
- // ignore it.
2486
- napi_value ignoreJSError{};
2487
- jsrApi_->napi_get_and_clear_last_exception(env_, &ignoreJSError);
2488
- } else if (typeOf(message) == napi_string) {
2489
- // JSI unit tests expect URL to be part of the call stack.
2490
- std::string stackStr = stringToStdString(stack);
2491
- if (stackStr.find(sourceURL_) == std::string::npos) {
2492
- stackStr += sourceURL_ + '\n' + stackStr;
2493
- setProperty(
2494
- jsError,
2495
- getNodeApiValue(propertyId_.stack),
2496
- createStringUtf8(stackStr.c_str()));
2497
- }
2498
- }
2499
- }
2500
- }
2501
-
2502
- // Evaluates lambda and augments exception messages with the method's name.
2503
- template <typename TLambda>
2504
- auto NodeApiJsiRuntime::runInMethodContext(
2505
- char const *methodName,
2506
- TLambda lambda) {
2507
- try {
2508
- return lambda();
2509
- } catch (jsi::JSError const &) {
2510
- throw; // do not augment the JSError exceptions.
2511
- } catch (std::exception const &ex) {
2512
- throwNativeException(
2513
- (std::string{"Exception in "} + methodName + ": " + ex.what()).c_str());
2514
- } catch (...) {
2515
- throwNativeException(
2516
- (std::string{"Exception in "} + methodName + ": <unknown>").c_str());
2517
- }
2518
- }
2519
-
2520
- // Evaluates lambda and converts all exceptions to Node-API errors.
2521
- template <typename TLambda>
2522
- napi_value NodeApiJsiRuntime::handleCallbackExceptions(
2523
- TLambda lambda) const noexcept {
2524
- try {
2525
- try {
2526
- return lambda();
2527
- } catch (jsi::JSError const &jsError) {
2528
- // This block may throw exceptions
2529
- setException(getNodeApiValue(jsError.value()));
2530
- }
2531
- } catch (std::exception const &ex) {
2532
- setException(ex.what());
2533
- } catch (...) {
2534
- setException("Unexpected error");
2535
- }
2536
-
2537
- return getUndefined();
2538
- }
2539
-
2540
- // Throws JavaScript exception using Node-API.
2541
- bool NodeApiJsiRuntime::setException(napi_value error) const noexcept {
2542
- // This method must not throw. We return false in case of error.
2543
- return jsrApi_->napi_throw(env_, error) == napi_status::napi_ok;
2544
- }
2545
-
2546
- // Throws JavaScript error exception with the provided message using Node-API.
2547
- bool NodeApiJsiRuntime::setException(std::string_view message) const noexcept {
2548
- // This method must not throw. We return false in case of error.
2549
- return jsrApi_->napi_throw_error(env_, "Unknown", message.data()) ==
2550
- napi_status::napi_ok;
2551
- }
2552
-
2553
- // Gets type of the napi_value.
2554
- napi_valuetype NodeApiJsiRuntime::typeOf(napi_value value) const {
2555
- napi_valuetype result{};
2556
- CHECK_NAPI(jsrApi_->napi_typeof(env_, value, &result));
2557
- return result;
2558
- }
2559
-
2560
- // Returns true if two napi_values are strict equal per JavaScript rules.
2561
- bool NodeApiJsiRuntime::strictEquals(napi_value left, napi_value right) const {
2562
- bool result{false};
2563
- CHECK_NAPI(jsrApi_->napi_strict_equals(env_, left, right, &result));
2564
- return result;
2565
- }
2566
-
2567
- // Gets the napi_value for the JavaScript's undefined value.
2568
- napi_value NodeApiJsiRuntime::getUndefined() const {
2569
- napi_value result{nullptr};
2570
- CHECK_NAPI(jsrApi_->napi_get_undefined(env_, &result));
2571
- return result;
2572
- }
2573
-
2574
- // Gets the napi_value for the JavaScript's null value.
2575
- napi_value NodeApiJsiRuntime::getNull() const {
2576
- napi_value result{};
2577
- CHECK_NAPI(jsrApi_->napi_get_null(env_, &result));
2578
- return result;
2579
- }
2580
-
2581
- // Gets the napi_value for the JavaScript's global object.
2582
- napi_value NodeApiJsiRuntime::getGlobal() const {
2583
- napi_value result{nullptr};
2584
- CHECK_NAPI(jsrApi_->napi_get_global(env_, &result));
2585
- return result;
2586
- }
2587
-
2588
- // Gets the napi_value for the JavaScript's true and false values.
2589
- napi_value NodeApiJsiRuntime::getBoolean(bool value) const {
2590
- napi_value result{nullptr};
2591
- CHECK_NAPI(jsrApi_->napi_get_boolean(env_, value, &result));
2592
- return result;
2593
- }
2594
-
2595
- // Gets value of the Boolean napi_value.
2596
- bool NodeApiJsiRuntime::getValueBool(napi_value value) const {
2597
- bool result{nullptr};
2598
- CHECK_NAPI(jsrApi_->napi_get_value_bool(env_, value, &result));
2599
- return result;
2600
- }
2601
-
2602
- // Creates napi_value with an int32_t value.
2603
- napi_value NodeApiJsiRuntime::createInt32(int32_t value) const {
2604
- napi_value result{};
2605
- CHECK_NAPI(jsrApi_->napi_create_int32(env_, value, &result));
2606
- return result;
2607
- }
2608
-
2609
- // Creates napi_value with an int32_t value.
2610
- napi_value NodeApiJsiRuntime::createUInt32(uint32_t value) const {
2611
- napi_value result{};
2612
- CHECK_NAPI(jsrApi_->napi_create_uint32(env_, value, &result));
2613
- return result;
2614
- }
2615
-
2616
- // Creates napi_value with a double value.
2617
- napi_value NodeApiJsiRuntime::createDouble(double value) const {
2618
- napi_value result{};
2619
- CHECK_NAPI(jsrApi_->napi_create_double(env_, value, &result));
2620
- return result;
2621
- }
2622
-
2623
- // Gets value of the Double napi_value.
2624
- double NodeApiJsiRuntime::getValueDouble(napi_value value) const {
2625
- double result{0};
2626
- CHECK_NAPI(jsrApi_->napi_get_value_double(env_, value, &result));
2627
- return result;
2628
- }
2629
-
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.
2632
- napi_value NodeApiJsiRuntime::createStringLatin1(std::string_view value) const {
2633
- CHECK_ELSE_THROW(value.data(), "Cannot convert a nullptr to a JS string.");
2634
- napi_value result{};
2635
- CHECK_NAPI(jsrApi_->napi_create_string_latin1(
2636
- env_, value.data(), value.size(), &result));
2637
- return result;
2638
- }
2639
-
2640
- // Creates a napi_value string from a UTF-8 string.
2641
- napi_value NodeApiJsiRuntime::createStringUtf8(std::string_view value) const {
2642
- CHECK_ELSE_THROW(value.data(), "Cannot convert a nullptr to a JS string.");
2643
- napi_value result{};
2644
- CHECK_NAPI(jsrApi_->napi_create_string_utf8(
2645
- env_, value.data(), value.size(), &result));
2646
- return result;
2647
- }
2648
-
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 {
2654
- return createStringUtf8({reinterpret_cast<const char *>(data), length});
2655
- }
2656
-
2657
- // Gets std::string from the napi_value string.
2658
- std::string NodeApiJsiRuntime::stringToStdString(napi_value stringValue) const {
2659
- std::string result;
2660
- CHECK_ELSE_THROW(
2661
- typeOf(stringValue) == napi_valuetype::napi_string,
2662
- "Cannot convert a non JS string Node-API Value to a std::string.");
2663
- size_t strLength{};
2664
- CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(
2665
- env_, stringValue, nullptr, 0, &strLength));
2666
- result.assign(strLength, '\0');
2667
- size_t copiedLength{};
2668
- CHECK_NAPI(jsrApi_->napi_get_value_string_utf8(
2669
- env_, stringValue, &result[0], result.length() + 1, &copiedLength));
2670
- CHECK_ELSE_THROW(result.length() == copiedLength, "Unexpected string length");
2671
- return result;
2672
- }
2673
-
2674
- // Gets or creates a unique string value from an UTF-8 string_view.
2675
- napi_value NodeApiJsiRuntime::getPropertyIdFromName(
2676
- std::string_view value) const {
2677
- napi_value result{};
2678
- CHECK_NAPI(jsrApi_->napi_create_string_utf8(
2679
- env_, value.data(), value.size(), &result));
2680
- return result;
2681
- }
2682
-
2683
- // Gets or creates a unique string value from an UTF-8 data/length range.
2684
- napi_value NodeApiJsiRuntime::getPropertyIdFromName(
2685
- const uint8_t *data,
2686
- size_t length) const {
2687
- return getPropertyIdFromName({reinterpret_cast<const char *>(data), length});
2688
- }
2689
-
2690
- // Gets or creates a unique string value from napi_value string.
2691
- napi_value NodeApiJsiRuntime::getPropertyIdFromName(napi_value str) const {
2692
- return str;
2693
- }
2694
-
2695
- // Gets or creates a unique string value from napi_value symbol.
2696
- napi_value NodeApiJsiRuntime::getPropertyIdFromSymbol(napi_value sym) const {
2697
- return sym;
2698
- }
2699
-
2700
- // Converts property id value to std::string.
2701
- std::string NodeApiJsiRuntime::propertyIdToStdString(napi_value propertyId) {
2702
- if (typeOf(propertyId) == napi_symbol) {
2703
- return symbolToStdString(propertyId);
2704
- }
2705
-
2706
- return stringToStdString(propertyId);
2707
- }
2708
-
2709
- // Creates a JavaScript symbol napi_value.
2710
- napi_value NodeApiJsiRuntime::createSymbol(
2711
- std::string_view symbolDescription) const {
2712
- napi_value result{};
2713
- napi_value description = createStringUtf8(symbolDescription);
2714
- CHECK_NAPI(jsrApi_->napi_create_symbol(env_, description, &result));
2715
- return result;
2716
- }
2717
-
2718
- // Calls Symbol.toString() and returns it as std::string.
2719
- std::string NodeApiJsiRuntime::symbolToStdString(napi_value symbolValue) {
2720
- if (!cachedValue_.SymbolToString) {
2721
- napi_value symbolCtor = getProperty(
2722
- getNodeApiValue(cachedValue_.Global),
2723
- getNodeApiValue(propertyId_.Symbol));
2724
- napi_value symbolPrototype =
2725
- getProperty(symbolCtor, getNodeApiValue(propertyId_.prototype));
2726
- cachedValue_.SymbolToString = makeNodeApiRef(
2727
- getProperty(symbolPrototype, getNodeApiValue(propertyId_.toString)),
2728
- NodeApiPointerValueKind::Object);
2729
- }
2730
- napi_value jsString = callFunction(
2731
- symbolValue, getNodeApiValue(cachedValue_.SymbolToString), {});
2732
- return stringToStdString(jsString);
2733
- }
2734
-
2735
- // Calls a JavaScript function.
2736
- napi_value NodeApiJsiRuntime::callFunction(
2737
- napi_value thisArg,
2738
- napi_value function,
2739
- span<napi_value> args) const {
2740
- napi_value result{};
2741
- CHECK_NAPI(jsrApi_->napi_call_function(
2742
- env_, thisArg, function, args.size(), args.data(), &result));
2743
- return result;
2744
- }
2745
-
2746
- // Constructs a new JavaScript Object using a constructor function.
2747
- napi_value NodeApiJsiRuntime::constructObject(
2748
- napi_value constructor,
2749
- span<napi_value> args) const {
2750
- napi_value result{};
2751
- CHECK_NAPI(jsrApi_->napi_new_instance(
2752
- env_, constructor, args.size(), args.data(), &result));
2753
- return result;
2754
- }
2755
-
2756
- // Returns true if object was constructed using the provided constructor.
2757
- bool NodeApiJsiRuntime::instanceOf(napi_value object, napi_value constructor)
2758
- const {
2759
- bool result{false};
2760
- CHECK_NAPI(jsrApi_->napi_instanceof(env_, object, constructor, &result));
2761
- return result;
2762
- }
2763
-
2764
- // Creates new JavaScript Object.
2765
- napi_value NodeApiJsiRuntime::createNodeApiObject() const {
2766
- napi_value result{};
2767
- CHECK_NAPI(jsrApi_->napi_create_object(env_, &result));
2768
- return result;
2769
- }
2770
-
2771
- // Returns true if the object has a property with the provided property ID.
2772
- bool NodeApiJsiRuntime::hasProperty(napi_value object, napi_value propertyId)
2773
- const {
2774
- bool result{};
2775
- CHECK_NAPI(jsrApi_->napi_has_property(env_, object, propertyId, &result));
2776
- return result;
2777
- }
2778
-
2779
- // Gets object property value.
2780
- napi_value NodeApiJsiRuntime::getProperty(
2781
- napi_value object,
2782
- napi_value propertyId) const {
2783
- napi_value result{};
2784
- CHECK_NAPI(jsrApi_->napi_get_property(env_, object, propertyId, &result));
2785
- return result;
2786
- }
2787
-
2788
- // Sets object property value.
2789
- void NodeApiJsiRuntime::setProperty(
2790
- napi_value object,
2791
- napi_value propertyId,
2792
- napi_value value) const {
2793
- CHECK_NAPI(jsrApi_->napi_set_property(env_, object, propertyId, value));
2794
- }
2795
-
2796
- // Sets object property value with the provided property accessibility
2797
- // attributes.
2798
- void NodeApiJsiRuntime::setProperty(
2799
- napi_value object,
2800
- napi_value propertyId,
2801
- napi_value value,
2802
- napi_property_attributes attrs) const {
2803
- napi_property_descriptor descriptor{};
2804
- descriptor.name = propertyId;
2805
- descriptor.value = value;
2806
- descriptor.attributes = attrs;
2807
- CHECK_NAPI(jsrApi_->napi_define_properties(env_, object, 1, &descriptor));
2808
- }
2809
-
2810
- // Creates a new JavaScript Array with the provided length.
2811
- napi_value NodeApiJsiRuntime::createNodeApiArray(size_t length) const {
2812
- napi_value result{};
2813
- CHECK_NAPI(jsrApi_->napi_create_array_with_length(env_, length, &result));
2814
- return result;
2815
- }
2816
-
2817
- bool NodeApiJsiRuntime::isArray(napi_value value) const {
2818
- bool result{};
2819
- CHECK_NAPI(jsrApi_->napi_is_array(env_, value, &result));
2820
- return result;
2821
- }
2822
-
2823
- size_t NodeApiJsiRuntime::getArrayLength(napi_value value) const {
2824
- uint32_t result{};
2825
- CHECK_NAPI(jsrApi_->napi_get_array_length(env_, value, &result));
2826
- return result;
2827
- }
2828
-
2829
- napi_value NodeApiJsiRuntime::getElement(napi_value arr, size_t index) const {
2830
- napi_value result{};
2831
- CHECK_NAPI(jsrApi_->napi_get_element(
2832
- env_, arr, static_cast<int32_t>(index), &result));
2833
- return result;
2834
- }
2835
-
2836
- // Sets array element.
2837
- void NodeApiJsiRuntime::setElement(
2838
- napi_value array,
2839
- uint32_t index,
2840
- napi_value value) const {
2841
- CHECK_NAPI(jsrApi_->napi_set_element(env_, array, index, value));
2842
- }
2843
-
2844
- // The Node-API external function callback used for the JSI host function
2845
- // implementation.
2846
- /*static*/ napi_value __cdecl NodeApiJsiRuntime::jsiHostFunctionCallback(
2847
- napi_env env,
2848
- napi_callback_info info) noexcept {
2849
- HostFunctionWrapper *hostFuncWrapper{};
2850
- size_t argc{};
2851
- CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
2852
- env,
2853
- info,
2854
- &argc,
2855
- nullptr,
2856
- nullptr,
2857
- reinterpret_cast<void **>(&hostFuncWrapper)));
2858
- CHECK_ELSE_CRASH(hostFuncWrapper, "Cannot find the host function");
2859
- NodeApiJsiRuntime &runtime = hostFuncWrapper->runtime();
2860
- NodeApiPointerValueScope scope{runtime};
2861
-
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
- });
2880
- }
2881
-
2882
- // Creates an external function.
2883
- napi_value NodeApiJsiRuntime::createExternalFunction(
2884
- napi_value name,
2885
- int32_t paramCount,
2886
- napi_callback callback,
2887
- void *callbackData) {
2888
- std::string funcName = stringToStdString(name);
2889
- napi_value function{};
2890
- CHECK_NAPI(jsrApi_->napi_create_function(
2891
- env_,
2892
- funcName.data(),
2893
- funcName.length(),
2894
- callback,
2895
- callbackData,
2896
- &function));
2897
- setProperty(
2898
- function,
2899
- getNodeApiValue(propertyId_.length),
2900
- createInt32(paramCount),
2901
- napi_property_attributes::napi_default);
2902
-
2903
- return function;
2904
- }
2905
-
2906
- // Creates an object that wraps up external data.
2907
- napi_value NodeApiJsiRuntime::createExternalObject(
2908
- void *data,
2909
- node_api_nogc_finalize finalizeCallback) const {
2910
- napi_value result{};
2911
- CHECK_NAPI(jsrApi_->napi_create_external(
2912
- env_, data, finalizeCallback, nullptr, &result));
2913
- return result;
2914
- }
2915
-
2916
- // Wraps up std::unique_ptr as an external object.
2917
- template <typename T>
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*/) {
2923
- // We wrap dataToDestroy in a unique_ptr to avoid calling delete explicitly.
2924
- std::unique_ptr<T> dataDeleter{static_cast<T *>(dataToDestroy)};
2925
- };
2926
- napi_value object = createExternalObject(data.get(), finalize);
2927
-
2928
- // We only call data.release() after the createExternalObject succeeds.
2929
- // Otherwise, when createExternalObject fails and an exception is thrown,
2930
- // the memory that data used to own will be leaked.
2931
- data.release();
2932
- return object;
2933
- }
2934
-
2935
- // Gets external data wrapped by an external object.
2936
- void *NodeApiJsiRuntime::getExternalData(napi_value object) const {
2937
- void *result{};
2938
- CHECK_NAPI(jsrApi_->napi_get_value_external(env_, object, &result));
2939
- return result;
2940
- }
2941
-
2942
- // Gets JSI host object wrapped into a napi_value object.
2943
- const std::shared_ptr<jsi::HostObject> &NodeApiJsiRuntime::getJsiHostObject(
2944
- napi_value obj) {
2945
- const napi_value hostObjectHolder =
2946
- getProperty(obj, getNodeApiValue(propertyId_.hostObjectSymbol));
2947
-
2948
- if (typeOf(hostObjectHolder) == napi_valuetype::napi_external) {
2949
- if (void *data = getExternalData(hostObjectHolder)) {
2950
- return *static_cast<std::shared_ptr<jsi::HostObject> *>(data);
2951
- }
2952
- }
2953
-
2954
- throw jsi::JSINativeException("Cannot get HostObjects.");
2955
- }
2956
-
2957
- // Gets cached or creates Proxy handler to implement the JSI host object.
2958
- napi_value NodeApiJsiRuntime::getHostObjectProxyHandler() {
2959
- if (!cachedValue_.HostObjectProxyHandler) {
2960
- const napi_value handler = createNodeApiObject();
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));
2969
- setProxyTrap<&NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap, 2>(
2970
- handler, getNodeApiValue(propertyId_.getOwnPropertyDescriptor));
2971
- cachedValue_.HostObjectProxyHandler =
2972
- makeNodeApiRef(handler, NodeApiPointerValueKind::Object);
2973
- }
2974
-
2975
- return getNodeApiValue(cachedValue_.HostObjectProxyHandler);
2976
- }
2977
-
2978
- // Sets Proxy trap method as a pointer to NodeApiJsiRuntime instance method.
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) {
2985
- napi_callback proxyTrap = [](napi_env env, napi_callback_info info) noexcept {
2986
- NodeApiJsiRuntime *runtime{};
2987
- napi_value args[argCount]{};
2988
- size_t actualArgCount{argCount};
2989
- CHECK_NAPI_ELSE_CRASH(JSRuntimeApi::current()->napi_get_cb_info(
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.");
2998
- NodeApiPointerValueScope scope{*runtime};
2999
- return runtime->handleCallbackExceptions([&runtime, &args]() {
3000
- return (runtime->*trapMethod)(span<napi_value>(args, argCount));
3001
- });
3002
- };
3003
-
3004
- setProperty(
3005
- handler,
3006
- propertyName,
3007
- createExternalFunction(propertyName, argCount, proxyTrap, this));
3008
- }
3009
-
3010
- // The host object Proxy 'has' trap implementation.
3011
- napi_value NodeApiJsiRuntime::hostObjectHasTrap(span<napi_value> args) {
3012
- // args[0] - the Proxy target object.
3013
- // args[1] - the name of the property to check.
3014
- napi_value propertyName = args[1];
3015
- const auto &hostObject = getJsiHostObject(args[0]);
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
- });
3027
- }
3028
-
3029
- // The host object Proxy 'get' trap implementation.
3030
- napi_value NodeApiJsiRuntime::hostObjectGetTrap(span<napi_value> args) {
3031
- // args[0] - the Proxy target object.
3032
- // args[1] - the name of the property to set.
3033
- // args[2] - the Proxy object (unused).
3034
- napi_value target = args[0];
3035
- napi_value propertyName = args[1];
3036
- bool isTargetOwnProp{};
3037
- CHECK_NAPI(jsrApi_->napi_has_own_property(
3038
- env_, target, propertyName, &isTargetOwnProp));
3039
- if (isTargetOwnProp) {
3040
- return getProperty(target, propertyName);
3041
- }
3042
- const auto &hostObject = getJsiHostObject(args[0]);
3043
- PropNameIDView propertyId{this, propertyName};
3044
- return runInMethodContext(
3045
- "HostObject::get", [&hostObject, &propertyId, this]() {
3046
- return getNodeApiValue(hostObject->get(*this, propertyId));
3047
- });
3048
- }
3049
-
3050
- // The host object Proxy 'set' trap implementation.
3051
- napi_value NodeApiJsiRuntime::hostObjectSetTrap(span<napi_value> args) {
3052
- // args[0] - the Proxy target object.
3053
- // args[1] - the name of the property to set.
3054
- // args[2] - the new value of the property to set.
3055
- // args[3] - the Proxy object (unused).
3056
- const auto &hostObject = getJsiHostObject(args[0]);
3057
- PropNameIDView propertyId{this, args[1]};
3058
- JsiValueView value{this, args[2]};
3059
- runInMethodContext(
3060
- "HostObject::set", [&hostObject, &propertyId, &value, this]() {
3061
- hostObject->set(*this, propertyId, value);
3062
- });
3063
- return getUndefined();
3064
- }
3065
-
3066
- // The host object Proxy 'ownKeys' trap implementation.
3067
- napi_value NodeApiJsiRuntime::hostObjectOwnKeysTrap(span<napi_value> args) {
3068
- // args[0] - the Proxy target object.
3069
- napi_value target = args[0];
3070
-
3071
- napi_value targetOwnKeys{};
3072
- CHECK_NAPI(jsrApi_->napi_get_all_property_names(
3073
- env_,
3074
- target,
3075
- napi_key_own_only,
3076
- napi_key_all_properties,
3077
- napi_key_numbers_to_strings,
3078
- &targetOwnKeys));
3079
- CHECK_ELSE_THROW(isArray(targetOwnKeys), "Expected an array");
3080
- size_t targetOwnKeysLength = getArrayLength(targetOwnKeys);
3081
-
3082
- const auto &hostObject = getJsiHostObject(target);
3083
- std::vector<jsi::PropNameID> hostOwnKeys = runInMethodContext(
3084
- "HostObject::getPropertyNames",
3085
- [&hostObject, this]() { return hostObject->getPropertyNames(*this); });
3086
-
3087
- std::vector<jsi::PropNameID> ownKeys;
3088
- std::unordered_set<const PointerValue *> uniqueOwnKeys;
3089
- // Minus one hostObjectSymbol key.
3090
- ownKeys.reserve(targetOwnKeysLength - 1 + hostOwnKeys.size());
3091
- uniqueOwnKeys.reserve(targetOwnKeysLength - 1 + hostOwnKeys.size());
3092
-
3093
- // Read all target own keys.
3094
- if (targetOwnKeysLength > 1) {
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
- };
3102
- for (size_t i = 0; i < targetOwnKeysLength; ++i) {
3103
- napi_value key = getElement(targetOwnKeys, i);
3104
- napi_valuetype keyType = typeOf(key);
3105
- if (keyType == napi_string) {
3106
- addPropNameId(
3107
- createPropNameIDFromString(makeJsiPointer<jsi::String>(key)));
3108
- #if JSI_VERSION >= 8
3109
- } else if (keyType == napi_symbol) {
3110
- if (strictEquals(key, getNodeApiValue(propertyId_.hostObjectSymbol))) {
3111
- continue;
3112
- }
3113
- addPropNameId(
3114
- createPropNameIDFromSymbol(makeJsiPointer<jsi::Symbol>(key)));
3115
- #endif
3116
- } else {
3117
- throwNativeException("Unexpected key type");
3118
- }
3119
- }
3120
- }
3121
-
3122
- // Read all unique host own keys.
3123
- for (jsi::PropNameID &propNameId : hostOwnKeys) {
3124
- const PointerValue *pv = getPointerValue(propNameId);
3125
- auto inserted = uniqueOwnKeys.insert(pv);
3126
- if (inserted.second) {
3127
- ownKeys.push_back(std::move(propNameId));
3128
- }
3129
- }
3130
-
3131
- // Put indexed properties before named ones.
3132
- struct Index {
3133
- uint32_t index;
3134
- napi_value value;
3135
- };
3136
- std::vector<Index> indexKeys;
3137
- std::vector<napi_value> nonIndexKeys;
3138
- nonIndexKeys.reserve(ownKeys.size());
3139
- for (const jsi::PropNameID &key : ownKeys) {
3140
- napi_value napiKey = getNodeApiValue(key);
3141
- napi_valuetype valueType = typeOf(napiKey);
3142
- if (valueType == napi_string) {
3143
- std::string keyStr = stringToStdString(napiKey);
3144
- std::optional<uint32_t> indexKey =
3145
- toArrayIndex(keyStr.begin(), keyStr.end());
3146
- if (indexKey.has_value()) {
3147
- indexKeys.push_back(Index{indexKey.value(), napiKey});
3148
- continue;
3149
- }
3150
- }
3151
- nonIndexKeys.push_back(napiKey);
3152
- }
3153
-
3154
- std::sort(
3155
- indexKeys.begin(),
3156
- indexKeys.end(),
3157
- [](const Index &left, const Index &right) {
3158
- return left.index < right.index;
3159
- });
3160
-
3161
- napi_value ownKeyArray = createNodeApiArray(0);
3162
- uint32_t index = 0;
3163
- for (const Index &indexKey : indexKeys) {
3164
- setElement(ownKeyArray, index++, indexKey.value);
3165
- }
3166
- for (napi_value napiKey : nonIndexKeys) {
3167
- setElement(ownKeyArray, index++, napiKey);
3168
- }
3169
-
3170
- return ownKeyArray;
3171
- }
3172
-
3173
- // The host object Proxy 'getOwnPropertyDescriptor' trap implementation.
3174
- napi_value NodeApiJsiRuntime::hostObjectGetOwnPropertyDescriptorTrap(
3175
- span<napi_value> args) {
3176
- // args[0] - the Proxy target object.
3177
- // args[1] - the property
3178
- const auto &hostObject = getJsiHostObject(args[0]);
3179
- PropNameIDView propertyId{this, args[1]};
3180
-
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
- });
3210
- }
3211
-
3212
- // Converts jsi::Bufer to span.
3213
- span<const uint8_t> NodeApiJsiRuntime::toSpan(const jsi::Buffer &buffer) {
3214
- return span<const uint8_t>(buffer.data(), buffer.size());
3215
- }
3216
-
3217
- // Creates jsi::Value from napi_value.
3218
- jsi::Value NodeApiJsiRuntime::toJsiValue(napi_value value) const {
3219
- switch (typeOf(value)) {
3220
- case napi_valuetype::napi_undefined:
3221
- return jsi::Value::undefined();
3222
- case napi_valuetype::napi_null:
3223
- return jsi::Value::null();
3224
- case napi_valuetype::napi_boolean:
3225
- return jsi::Value{getValueBool(value)};
3226
- case napi_valuetype::napi_number:
3227
- return jsi::Value{getValueDouble(value)};
3228
- case napi_valuetype::napi_string:
3229
- return jsi::Value{makeJsiPointer<jsi::String>(value)};
3230
- case napi_valuetype::napi_symbol:
3231
- return jsi::Value{makeJsiPointer<jsi::Symbol>(value)};
3232
- case napi_valuetype::napi_object:
3233
- case napi_valuetype::napi_function:
3234
- case napi_valuetype::napi_external:
3235
- return jsi::Value{makeJsiPointer<jsi::Object>(value)};
3236
- #if JSI_VERSION >= 6
3237
- case napi_valuetype::napi_bigint:
3238
- return jsi::Value{makeJsiPointer<jsi::BigInt>(value)};
3239
- #endif
3240
- default:
3241
- throw jsi::JSINativeException("Unexpected value type");
3242
- }
3243
- }
3244
-
3245
- napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Value &value) const {
3246
- if (value.isUndefined()) {
3247
- return getUndefined();
3248
- } else if (value.isNull()) {
3249
- return getNull();
3250
- } else if (value.isBool()) {
3251
- return getBoolean(value.getBool());
3252
- } else if (value.isNumber()) {
3253
- return createDouble(value.getNumber());
3254
- } else if (value.isSymbol()) {
3255
- return getNodeApiValue(
3256
- value.getSymbol(*const_cast<NodeApiJsiRuntime *>(this)));
3257
- } else if (value.isString()) {
3258
- return getNodeApiValue(
3259
- value.getString(*const_cast<NodeApiJsiRuntime *>(this)));
3260
- } else if (value.isObject()) {
3261
- return getNodeApiValue(
3262
- value.getObject(*const_cast<NodeApiJsiRuntime *>(this)));
3263
- #if JSI_VERSION >= 8
3264
- } else if (value.isBigInt()) {
3265
- return getNodeApiValue(
3266
- value.getBigInt(*const_cast<NodeApiJsiRuntime *>(this)));
3267
- #endif
3268
- } else {
3269
- throw jsi::JSINativeException("Unexpected jsi::Value type");
3270
- }
3271
- }
3272
-
3273
- napi_value NodeApiJsiRuntime::getNodeApiValue(const jsi::Pointer &ptr) const {
3274
- return const_cast<NodeApiPointerValue *>(
3275
- static_cast<const NodeApiPointerValue *>(getPointerValue(ptr)))
3276
- ->getValue(*const_cast<NodeApiJsiRuntime *>(this));
3277
- }
3278
-
3279
- napi_value NodeApiJsiRuntime::getNodeApiValue(
3280
- const NodeApiRefHolder &ref) const {
3281
- return ref->getValue(*const_cast<NodeApiJsiRuntime *>(this));
3282
- }
3283
-
3284
- NodeApiJsiRuntime::NodeApiRefCountedPointerValue *
3285
- NodeApiJsiRuntime::cloneNodeApiPointerValue(const PointerValue *pointerValue) {
3286
- return static_cast<const NodeApiPointerValue *>(pointerValue)->clone(*this);
3287
- }
3288
-
3289
- // Adopted from Hermes code.
3290
- std::optional<uint32_t> NodeApiJsiRuntime::toArrayIndex(
3291
- std::string::const_iterator first,
3292
- std::string::const_iterator last) {
3293
- // Empty string is invalid.
3294
- if (first == last)
3295
- return std::nullopt;
3296
-
3297
- // Leading 0 is special.
3298
- if (*first == '0') {
3299
- ++first;
3300
- // Just "0"?
3301
- if (first == last)
3302
- return 0;
3303
- // Leading 0 is invalid otherwise.
3304
- return std::nullopt;
3305
- }
3306
-
3307
- uint32_t res = 0;
3308
- do {
3309
- auto ch = *first;
3310
- if (ch < '0' || ch > '9')
3311
- return std::nullopt;
3312
- uint64_t tmp = (uint64_t)res * 10 + (ch - '0');
3313
- // Check for overflow.
3314
- if (tmp & ((uint64_t)0xFFFFFFFFu << 32))
3315
- return std::nullopt;
3316
- res = (uint32_t)tmp;
3317
- } while (++first != last);
3318
-
3319
- // 0xFFFFFFFF is not a valid array index.
3320
- if (res == 0xFFFFFFFFu)
3321
- return std::nullopt;
3322
-
3323
- return res;
3324
- }
3325
-
3326
- template <typename T, std::enable_if_t<std::is_same_v<jsi::Object, T>, int>>
3327
- T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
3328
- return make<T>(NodeApiRefCountedPointerValue::make(
3329
- *const_cast<NodeApiJsiRuntime *>(this),
3330
- value,
3331
- NodeApiPointerValueKind::Object)
3332
- .release());
3333
- }
3334
-
3335
- template <typename T, std::enable_if_t<std::is_same_v<jsi::String, T>, int>>
3336
- T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
3337
- return make<T>(NodeApiRefCountedPointerValue::make(
3338
- *const_cast<NodeApiJsiRuntime *>(this),
3339
- value,
3340
- NodeApiPointerValueKind::String)
3341
- .release());
3342
- }
3343
-
3344
- template <typename T, std::enable_if_t<std::is_same_v<jsi::Symbol, T>, int>>
3345
- T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
3346
- return make<T>(NodeApiRefCountedPointerValue::make(
3347
- *const_cast<NodeApiJsiRuntime *>(this),
3348
- value,
3349
- NodeApiPointerValueKind::Symbol)
3350
- .release());
3351
- }
3352
-
3353
- #if JSI_VERSION >= 6
3354
- template <typename T, std::enable_if_t<std::is_same_v<jsi::BigInt, T>, int>>
3355
- T NodeApiJsiRuntime::makeJsiPointer(napi_value value) const {
3356
- return make<T>(NodeApiRefCountedPointerValue::make(
3357
- *const_cast<NodeApiJsiRuntime *>(this),
3358
- value,
3359
- NodeApiPointerValueKind::BigInt)
3360
- .release());
3361
- }
3362
- #endif
3363
-
3364
- template <
3365
- typename TTo,
3366
- typename TFrom,
3367
- std::enable_if_t<std::is_base_of_v<jsi::Pointer, TTo>, int>,
3368
- std::enable_if_t<std::is_base_of_v<jsi::Pointer, TFrom>, int>>
3369
- TTo NodeApiJsiRuntime::cloneAs(const TFrom &pointer) const {
3370
- return make<TTo>(static_cast<const NodeApiRefCountedPointerValue *>(
3371
- getPointerValue(pointer))
3372
- ->clone(*const_cast<NodeApiJsiRuntime *>(this)));
3373
- }
3374
-
3375
- NodeApiJsiRuntime::NodeApiRefHolder NodeApiJsiRuntime::makeNodeApiRef(
3376
- napi_value value,
3377
- NodeApiPointerValueKind pointerKind,
3378
- int32_t initialRefCount) {
3379
- return NodeApiRefCountedPointerValue::make(
3380
- *this, value, pointerKind, initialRefCount);
3381
- }
3382
-
3383
- void NodeApiJsiRuntime::addStackValue(NodeApiStackValuePtr stackPointer) {
3384
- stackValues_.push_back(std::move(stackPointer));
3385
- }
3386
-
3387
- void NodeApiJsiRuntime::pushPointerValueScope() noexcept {
3388
- stackScopes_.push_back(stackValues_.size());
3389
- }
3390
-
3391
- void NodeApiJsiRuntime::popPointerValueScope() noexcept {
3392
- CHECK_ELSE_CRASH(!stackScopes_.empty(), "There are no scopes to pop");
3393
- size_t newStackSize = stackScopes_.back();
3394
- auto beginIterator = stackValues_.begin() + newStackSize;
3395
- stackScopes_.pop_back();
3396
- std::for_each(
3397
- beginIterator, stackValues_.end(), [this](NodeApiStackValuePtr &ptr) {
3398
- ptr.release()->deleteStackValue(*this);
3399
- });
3400
- stackValues_.resize(newStackSize);
3401
-
3402
- pendingDeletions_->deletePointerValues(*this);
3403
- }
3404
-
3405
- } // namespace
3406
-
3407
- std::unique_ptr<jsi::Runtime> makeNodeApiJsiRuntime(
3408
- napi_env env,
3409
- JSRuntimeApi *jsrApi,
3410
- std::function<void()> onDelete) noexcept {
3411
- return std::make_unique<NodeApiJsiRuntime>(env, jsrApi, std::move(onDelete));
3412
- }
3413
-
3414
- } // namespace Microsoft::NodeApiJsi
3415
-
3416
- EXTERN_C_START
3417
-
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) {
3422
- if (result != nullptr) {
3423
- *result = "NodeApiJsiRuntime";
3424
- }
3425
- return napi_ok;
3426
- }
3427
-
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) {
3441
- if (result != nullptr) {
3442
- *result = true; // All tasks are drained
3443
- }
3444
- return napi_ok;
3445
- }
3446
-
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) {
3451
- if (result != nullptr) {
3452
- *result = false;
3453
- }
3454
- return napi_ok;
3455
- }
3456
-
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*/) {
3462
- return napi_ok;
3463
- }
3464
-
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*/) {
3470
- return napi_ok;
3471
- }
3472
-
3473
- // TODO: Ensure that we either load all three functions or use their default
3474
- // versions and never mix and match.
3475
-
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.
3479
- napi_status NAPI_CDECL default_jsr_create_prepared_script(
3480
- napi_env env,
3481
- const uint8_t *script_data,
3482
- size_t script_length,
3483
- jsr_data_delete_cb script_delete_cb,
3484
- void *deleter_data,
3485
- const char * /*source_url*/,
3486
- jsr_prepared_script *result) {
3487
- Microsoft::NodeApiJsi::JSRuntimeApi *jsrApi =
3488
- Microsoft::NodeApiJsi::JSRuntimeApi::current();
3489
- napi_value script{}, obj{};
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);
3494
- if (script_delete_cb != nullptr) {
3495
- script_delete_cb(const_cast<uint8_t *>(script_data), deleter_data);
3496
- }
3497
- NAPI_CALL(status);
3498
- NAPI_CALL(jsrApi->napi_create_object(env, &obj));
3499
- NAPI_CALL(jsrApi->napi_set_named_property(env, obj, "script", script));
3500
- return jsrApi->napi_create_reference(
3501
- env, obj, 1, reinterpret_cast<napi_ref *>(result));
3502
- }
3503
-
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));
3513
- }
3514
-
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();
3524
- napi_value obj{}, script{};
3525
- NAPI_CALL(jsrApi->napi_get_reference_value(
3526
- env, reinterpret_cast<napi_ref>(prepared_script), &obj));
3527
- NAPI_CALL(jsrApi->napi_get_named_property(env, obj, "script", &script));
3528
- return jsrApi->napi_run_script(env, script, result);
3529
- }
3530
-
3531
- EXTERN_C_END