react-native-windows 0.80.5 → 0.80.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,922 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #include <cassert>
9
+ #include <cmath>
10
+ #include <cstdlib>
11
+ #include <map>
12
+ #include <mutex>
13
+ #include <stdexcept>
14
+
15
+ #include <jsi/instrumentation.h>
16
+ #include <jsi/jsi.h>
17
+
18
+ namespace facebook {
19
+ namespace jsi {
20
+
21
+ namespace {
22
+
23
+ #if JSI_VERSION >= 20
24
+ /// A global map used to store custom runtime data for VMs that do not provide
25
+ /// their own default implementation of setRuntimeData and getRuntimeData.
26
+ struct RuntimeDataGlobal {
27
+ /// Mutex protecting the Runtime data map
28
+ std::mutex mutex_{};
29
+ /// Maps a runtime pointer to a map of its custom data. At destruction of the
30
+ /// runtime, its entry will be removed from the global map.
31
+ std::unordered_map<
32
+ Runtime*,
33
+ std::unordered_map<
34
+ UUID,
35
+ std::pair<const void*, void (*)(const void* data)>,
36
+ UUID::Hash>>
37
+ dataMap_;
38
+ };
39
+
40
+ RuntimeDataGlobal& getRuntimeDataGlobal() {
41
+ static RuntimeDataGlobal runtimeData{};
42
+ return runtimeData;
43
+ }
44
+
45
+ /// A host object that, when destructed, will remove the runtime's custom data
46
+ /// entry from the global map of custom data.
47
+ class RemoveRuntimeDataHostObject : public jsi::HostObject {
48
+ public:
49
+ explicit RemoveRuntimeDataHostObject(Runtime* runtime) : runtime_(runtime) {}
50
+
51
+ RemoveRuntimeDataHostObject(const RemoveRuntimeDataHostObject&) = default;
52
+ RemoveRuntimeDataHostObject(RemoveRuntimeDataHostObject&&) = default;
53
+ RemoveRuntimeDataHostObject& operator=(const RemoveRuntimeDataHostObject&) =
54
+ default;
55
+ RemoveRuntimeDataHostObject& operator=(RemoveRuntimeDataHostObject&&) =
56
+ default;
57
+
58
+ ~RemoveRuntimeDataHostObject() override {
59
+ auto& runtimeDataGlobal = getRuntimeDataGlobal();
60
+ std::lock_guard<std::mutex> lock(runtimeDataGlobal.mutex_);
61
+ auto runtimeMapIt = runtimeDataGlobal.dataMap_.find(runtime_);
62
+ // We install the RemoveRuntimeDataHostObject only when the first custom
63
+ // data for the runtime is added, and only this object is responsible for
64
+ // clearing runtime data. Thus, we should always be able to find the data
65
+ // entry.
66
+ assert(
67
+ runtimeMapIt != runtimeDataGlobal.dataMap_.end() &&
68
+ "Custom runtime data not found for this runtime");
69
+
70
+ for (auto [_, entry] : runtimeMapIt->second) {
71
+ auto* deleter = entry.second;
72
+ deleter(entry.first);
73
+ }
74
+ runtimeDataGlobal.dataMap_.erase(runtime_);
75
+ }
76
+
77
+ private:
78
+ Runtime* runtime_;
79
+ };
80
+ #endif
81
+
82
+ // This is used for generating short exception strings.
83
+ std::string kindToString(const Value& v, Runtime* rt = nullptr) {
84
+ if (v.isUndefined()) {
85
+ return "undefined";
86
+ } else if (v.isNull()) {
87
+ return "null";
88
+ } else if (v.isBool()) {
89
+ return v.getBool() ? "true" : "false";
90
+ } else if (v.isNumber()) {
91
+ return "a number";
92
+ } else if (v.isString()) {
93
+ return "a string";
94
+ } else if (v.isSymbol()) {
95
+ return "a symbol";
96
+ #if JSI_VERSION >= 6
97
+ } else if (v.isBigInt()) {
98
+ return "a bigint";
99
+ #endif
100
+ } else {
101
+ assert(v.isObject() && "Expecting object.");
102
+ return rt != nullptr && v.getObject(*rt).isFunction(*rt) ? "a function"
103
+ : "an object";
104
+ }
105
+ }
106
+
107
+ // getPropertyAsFunction() will try to create a JSError. If the
108
+ // failure is in building a JSError, this will lead to infinite
109
+ // recursion. This function is used in place of getPropertyAsFunction
110
+ // when building JSError, to avoid that infinite recursion.
111
+ Value callGlobalFunction(Runtime& runtime, const char* name, const Value& arg) {
112
+ Value v = runtime.global().getProperty(runtime, name);
113
+ if (!v.isObject()) {
114
+ throw JSINativeException(
115
+ std::string("callGlobalFunction: JS global property '") + name +
116
+ "' is " + kindToString(v, &runtime) + ", expected a Function");
117
+ }
118
+ Object o = v.getObject(runtime);
119
+ if (!o.isFunction(runtime)) {
120
+ throw JSINativeException(
121
+ std::string("callGlobalFunction: JS global property '") + name +
122
+ "' is a non-callable Object, expected a Function");
123
+ }
124
+ Function f = std::move(o).getFunction(runtime);
125
+ return f.call(runtime, arg);
126
+ }
127
+
128
+ #if JSI_VERSION >= 14
129
+ // Given a sequence of UTF8 encoded bytes, advance the input to past where a
130
+ // 32-bit unicode codepoint as been decoded and return the codepoint. If the
131
+ // UTF8 encoding is invalid, then return the value with the unicode replacement
132
+ // character (U+FFFD). This decoder also relies on zero termination at end of
133
+ // the input for bound checks.
134
+ // \param input char pointer pointing to the current character
135
+ // \return Unicode codepoint
136
+ uint32_t decodeUTF8(const char*& input) {
137
+ uint32_t ch = (unsigned char)input[0];
138
+ if (ch <= 0x7f) {
139
+ input += 1;
140
+ return ch;
141
+ }
142
+ uint32_t ret;
143
+ constexpr uint32_t replacementCharacter = 0xFFFD;
144
+ if ((ch & 0xE0) == 0xC0) {
145
+ uint32_t ch1 = (unsigned char)input[1];
146
+ if ((ch1 & 0xC0) != 0x80) {
147
+ input += 1;
148
+ return replacementCharacter;
149
+ }
150
+ ret = ((ch & 0x1F) << 6) | (ch1 & 0x3F);
151
+ input += 2;
152
+ if (ret <= 0x7F) {
153
+ return replacementCharacter;
154
+ }
155
+ } else if ((ch & 0xF0) == 0xE0) {
156
+ uint32_t ch1 = (unsigned char)input[1];
157
+ if ((ch1 & 0x40) != 0 || (ch1 & 0x80) == 0) {
158
+ input += 1;
159
+ return replacementCharacter;
160
+ }
161
+ uint32_t ch2 = (unsigned char)input[2];
162
+ if ((ch2 & 0x40) != 0 || (ch2 & 0x80) == 0) {
163
+ input += 2;
164
+ return replacementCharacter;
165
+ }
166
+ ret = ((ch & 0x0F) << 12) | ((ch1 & 0x3F) << 6) | (ch2 & 0x3F);
167
+ input += 3;
168
+ if (ret <= 0x7FF) {
169
+ return replacementCharacter;
170
+ }
171
+ } else if ((ch & 0xF8) == 0xF0) {
172
+ uint32_t ch1 = (unsigned char)input[1];
173
+ if ((ch1 & 0x40) != 0 || (ch1 & 0x80) == 0) {
174
+ input += 1;
175
+ return replacementCharacter;
176
+ }
177
+ uint32_t ch2 = (unsigned char)input[2];
178
+ if ((ch2 & 0x40) != 0 || (ch2 & 0x80) == 0) {
179
+ input += 2;
180
+ return replacementCharacter;
181
+ }
182
+ uint32_t ch3 = (unsigned char)input[3];
183
+ if ((ch3 & 0x40) != 0 || (ch3 & 0x80) == 0) {
184
+ input += 3;
185
+ return replacementCharacter;
186
+ }
187
+ ret = ((ch & 0x07) << 18) | ((ch1 & 0x3F) << 12) | ((ch2 & 0x3F) << 6) |
188
+ (ch3 & 0x3F);
189
+ input += 4;
190
+ if (ret <= 0xFFFF) {
191
+ return replacementCharacter;
192
+ }
193
+ if (ret > 0x10FFFF) {
194
+ return replacementCharacter;
195
+ }
196
+ } else {
197
+ input += 1;
198
+ return replacementCharacter;
199
+ }
200
+ return ret;
201
+ }
202
+
203
+ // Given a valid 32-bit unicode codepoint, encode it as UTF-16 into the output.
204
+ void encodeUTF16(std::u16string& out, uint32_t cp) {
205
+ if (cp < 0x10000) {
206
+ out.push_back((uint16_t)cp);
207
+ return;
208
+ }
209
+ cp -= 0x10000;
210
+ uint16_t highSurrogate = 0xD800 + ((cp >> 10) & 0x3FF);
211
+ out.push_back(highSurrogate);
212
+ uint16_t lowSurrogate = 0xDC00 + (cp & 0x3FF);
213
+ out.push_back(lowSurrogate);
214
+ }
215
+
216
+ // Convert the UTF8 encoded string into a UTF16 encoded string. If the
217
+ // input is not valid UTF8, the replacement character (U+FFFD) is used to
218
+ // represent the invalid sequence.
219
+ std::u16string convertUTF8ToUTF16(const std::string& utf8) {
220
+ std::u16string ret;
221
+ const char* curr = utf8.data();
222
+ const char* end = curr + utf8.length();
223
+ while (curr < end) {
224
+ auto cp = decodeUTF8(curr);
225
+ encodeUTF16(ret, cp);
226
+ }
227
+ return ret;
228
+ }
229
+ #endif
230
+
231
+ #if JSI_VERSION >= 19
232
+ // Given a unsigned number, which is less than 16, return the hex character.
233
+ inline char hexDigit(unsigned x) {
234
+ return static_cast<char>(x < 10 ? '0' + x : 'A' + (x - 10));
235
+ }
236
+
237
+ // Given a sequence of UTF 16 code units, return true if all code units are
238
+ // ASCII characters
239
+ bool isAllASCII(const char16_t* utf16, size_t length) {
240
+ for (const char16_t* e = utf16 + length; utf16 != e; ++utf16) {
241
+ if (*utf16 > 0x7F)
242
+ return false;
243
+ }
244
+ return true;
245
+ }
246
+
247
+ // Given a sequences of UTF 16 code units, return a string that explicitly
248
+ // expresses the code units
249
+ std::string getUtf16CodeUnitString(const char16_t* utf16, size_t length) {
250
+ // Every character will need 4 hex digits + the character escape "\u".
251
+ // Plus 2 character for the opening and closing single quote.
252
+ std::string s = std::string(6 * length + 2, 0);
253
+ s.front() = '\'';
254
+
255
+ for (size_t i = 0; i != length; ++i) {
256
+ char16_t ch = utf16[i];
257
+ size_t start = (6 * i) + 1;
258
+
259
+ s[start] = '\\';
260
+ s[start + 1] = 'u';
261
+
262
+ s[start + 2] = hexDigit((ch >> 12) & 0x000f);
263
+ s[start + 3] = hexDigit((ch >> 8) & 0x000f);
264
+ s[start + 4] = hexDigit((ch >> 4) & 0x000f);
265
+ s[start + 5] = hexDigit(ch & 0x000f);
266
+ }
267
+ s.back() = '\'';
268
+ return s;
269
+ }
270
+ #endif
271
+
272
+ } // namespace
273
+
274
+ Buffer::~Buffer() = default;
275
+
276
+ #if JSI_VERSION >= 9
277
+ MutableBuffer::~MutableBuffer() = default;
278
+ #endif
279
+
280
+ PreparedJavaScript::~PreparedJavaScript() = default;
281
+
282
+ Value HostObject::get(Runtime&, const PropNameID&) {
283
+ return Value();
284
+ }
285
+
286
+ void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) {
287
+ std::string msg("TypeError: Cannot assign to property '");
288
+ msg += name.utf8(rt);
289
+ msg += "' on HostObject with default setter";
290
+ throw JSError(rt, msg);
291
+ }
292
+
293
+ HostObject::~HostObject() {}
294
+
295
+ #if JSI_VERSION >= 7
296
+ NativeState::~NativeState() {}
297
+ #endif
298
+
299
+ Runtime::~Runtime() {}
300
+
301
+ #if JSI_VERSION >= 20
302
+ ICast* Runtime::castInterface(const UUID& /*interfaceUUID*/) {
303
+ return nullptr;
304
+ }
305
+ #endif
306
+
307
+ Instrumentation& Runtime::instrumentation() {
308
+ class NoInstrumentation : public Instrumentation {
309
+ std::string getRecordedGCStats() override {
310
+ return "";
311
+ }
312
+
313
+ std::unordered_map<std::string, int64_t> getHeapInfo(bool) override {
314
+ return std::unordered_map<std::string, int64_t>{};
315
+ }
316
+
317
+ void collectGarbage(std::string) override {}
318
+
319
+ void startTrackingHeapObjectStackTraces(
320
+ std::function<void(
321
+ uint64_t,
322
+ std::chrono::microseconds,
323
+ std::vector<HeapStatsUpdate>)>) override {}
324
+ void stopTrackingHeapObjectStackTraces() override {}
325
+
326
+ void startHeapSampling(size_t) override {}
327
+ void stopHeapSampling(std::ostream&) override {}
328
+
329
+ #if JSI_VERSION >= 13
330
+ void createSnapshotToFile(
331
+ const std::string& /*path*/,
332
+ const HeapSnapshotOptions& /*options*/) override
333
+ #else
334
+ void createSnapshotToFile(const std::string&) override
335
+ #endif
336
+ {
337
+ throw JSINativeException(
338
+ "Default instrumentation cannot create a heap snapshot");
339
+ }
340
+
341
+ #if JSI_VERSION >= 13
342
+ void createSnapshotToStream(
343
+ std::ostream& /*os*/,
344
+ const HeapSnapshotOptions& /*options*/) override
345
+ #else
346
+ void createSnapshotToStream(std::ostream&) override
347
+ #endif
348
+ {
349
+ throw JSINativeException(
350
+ "Default instrumentation cannot create a heap snapshot");
351
+ }
352
+
353
+ std::string flushAndDisableBridgeTrafficTrace() override {
354
+ std::abort();
355
+ }
356
+
357
+ void writeBasicBlockProfileTraceToFile(const std::string&) const override {
358
+ std::abort();
359
+ }
360
+
361
+ void dumpProfilerSymbolsToFile(const std::string&) const override {
362
+ std::abort();
363
+ }
364
+ };
365
+
366
+ static NoInstrumentation sharedInstance;
367
+ return sharedInstance;
368
+ }
369
+
370
+ #if JSI_VERSION >= 2
371
+ Value Runtime::createValueFromJsonUtf8(const uint8_t* json, size_t length) {
372
+ Function parseJson = global()
373
+ .getPropertyAsObject(*this, "JSON")
374
+ .getPropertyAsFunction(*this, "parse");
375
+ return parseJson.call(*this, String::createFromUtf8(*this, json, length));
376
+ }
377
+ #else
378
+ Value Value::createFromJsonUtf8(
379
+ Runtime& runtime,
380
+ const uint8_t* json,
381
+ size_t length) {
382
+ Function parseJson = runtime.global()
383
+ .getPropertyAsObject(runtime, "JSON")
384
+ .getPropertyAsFunction(runtime, "parse");
385
+ return parseJson.call(runtime, String::createFromUtf8(runtime, json, length));
386
+ }
387
+ #endif
388
+
389
+ #if JSI_VERSION >= 19
390
+ String Runtime::createStringFromUtf16(const char16_t* utf16, size_t length) {
391
+ if (isAllASCII(utf16, length)) {
392
+ std::string buffer(length, '\0');
393
+ for (size_t i = 0; i < length; ++i) {
394
+ buffer[i] = static_cast<char>(utf16[i]);
395
+ }
396
+ return createStringFromAscii(buffer.data(), length);
397
+ }
398
+ auto s = getUtf16CodeUnitString(utf16, length);
399
+ return global()
400
+ .getPropertyAsFunction(*this, "eval")
401
+ .call(*this, s)
402
+ .getString(*this);
403
+ }
404
+
405
+ PropNameID Runtime::createPropNameIDFromUtf16(
406
+ const char16_t* utf16,
407
+ size_t length) {
408
+ auto jsString = createStringFromUtf16(utf16, length);
409
+ return createPropNameIDFromString(jsString);
410
+ }
411
+ #endif
412
+
413
+ #if JSI_VERSION >= 14
414
+ std::u16string Runtime::utf16(const PropNameID& sym) {
415
+ auto utf8Str = utf8(sym);
416
+ return convertUTF8ToUTF16(utf8Str);
417
+ }
418
+
419
+ std::u16string Runtime::utf16(const String& str) {
420
+ auto utf8Str = utf8(str);
421
+ return convertUTF8ToUTF16(utf8Str);
422
+ }
423
+ #endif
424
+
425
+ #if JSI_VERSION >= 16
426
+ void Runtime::getStringData(
427
+ const jsi::String& str,
428
+ void* ctx,
429
+ void (*cb)(void* ctx, bool ascii, const void* data, size_t num)) {
430
+ auto utf16Str = utf16(str);
431
+ cb(ctx, false, utf16Str.data(), utf16Str.size());
432
+ }
433
+
434
+ void Runtime::getPropNameIdData(
435
+ const jsi::PropNameID& sym,
436
+ void* ctx,
437
+ void (*cb)(void* ctx, bool ascii, const void* data, size_t num)) {
438
+ auto utf16Str = utf16(sym);
439
+ cb(ctx, false, utf16Str.data(), utf16Str.size());
440
+ }
441
+ #endif
442
+
443
+ #if JSI_VERSION >= 17
444
+ void Runtime::setPrototypeOf(const Object& object, const Value& prototype) {
445
+ auto setPrototypeOfFn = global()
446
+ .getPropertyAsObject(*this, "Object")
447
+ .getPropertyAsFunction(*this, "setPrototypeOf");
448
+ setPrototypeOfFn.call(*this, object, prototype).asObject(*this);
449
+ }
450
+
451
+ Value Runtime::getPrototypeOf(const Object& object) {
452
+ auto setPrototypeOfFn = global()
453
+ .getPropertyAsObject(*this, "Object")
454
+ .getPropertyAsFunction(*this, "getPrototypeOf");
455
+ return setPrototypeOfFn.call(*this, object);
456
+ }
457
+ #endif
458
+
459
+ #if JSI_VERSION >= 18
460
+ Object Runtime::createObjectWithPrototype(const Value& prototype) {
461
+ auto createFn = global()
462
+ .getPropertyAsObject(*this, "Object")
463
+ .getPropertyAsFunction(*this, "create");
464
+ return createFn.call(*this, prototype).asObject(*this);
465
+ }
466
+ #endif
467
+
468
+ #if JSI_VERSION >= 20
469
+ void Runtime::setRuntimeDataImpl(
470
+ const UUID& uuid,
471
+ const void* data,
472
+ void (*deleter)(const void* data)) {
473
+ auto& runtimeDataGlobal = getRuntimeDataGlobal();
474
+ std::lock_guard<std::mutex> lock(runtimeDataGlobal.mutex_);
475
+ if (auto it = runtimeDataGlobal.dataMap_.find(this);
476
+ it != runtimeDataGlobal.dataMap_.end()) {
477
+ auto& map = it->second;
478
+ if (auto entryIt = map.find(uuid); entryIt != map.end()) {
479
+ // Free the old data
480
+ auto oldData = entryIt->second.first;
481
+ auto oldDataDeleter = entryIt->second.second;
482
+ oldDataDeleter(oldData);
483
+ }
484
+ map[uuid] = {data, deleter};
485
+ return;
486
+ }
487
+ // No custom data entry exist for this runtime in the global map, so create
488
+ // one.
489
+ runtimeDataGlobal.dataMap_[this][uuid] = {data, deleter};
490
+
491
+ // The first time data is added for this runtime is added to the map, install
492
+ // a host object on the global object of the runtime. This host object is used
493
+ // to release the runtime's entry from the global custom data map when the
494
+ // runtime is destroyed.
495
+ // Also, try to protect the host object by making it non-configurable,
496
+ // non-enumerable, and non-writable. These JSI operations are purposely
497
+ // performed after runtime-specific data map is added and the host object is
498
+ // created to prevent data leaks if any operations fail.
499
+ Object ho = Object::createFromHostObject(
500
+ *this, std::make_shared<RemoveRuntimeDataHostObject>(this));
501
+ global().setProperty(*this, "_jsiRuntimeDataCleanUp", ho);
502
+ auto definePropertyFn = global()
503
+ .getPropertyAsObject(*this, "Object")
504
+ .getPropertyAsFunction(*this, "defineProperty");
505
+ auto desc = Object(*this);
506
+ desc.setProperty(*this, "configurable", Value(false));
507
+ desc.setProperty(*this, "enumerable", Value(false));
508
+ desc.setProperty(*this, "writable", Value(false));
509
+ definePropertyFn.call(*this, global(), "_jsiRuntimeDataCleanUp", desc);
510
+ }
511
+
512
+ const void* Runtime::getRuntimeDataImpl(const UUID& uuid) {
513
+ auto& runtimeDataGlobal = getRuntimeDataGlobal();
514
+ std::lock_guard<std::mutex> lock(runtimeDataGlobal.mutex_);
515
+ if (auto runtimeMapIt = runtimeDataGlobal.dataMap_.find(this);
516
+ runtimeMapIt != runtimeDataGlobal.dataMap_.end()) {
517
+ if (auto customDataIt = runtimeMapIt->second.find(uuid);
518
+ customDataIt != runtimeMapIt->second.end()) {
519
+ return customDataIt->second.first;
520
+ }
521
+ }
522
+ return nullptr;
523
+ }
524
+ #endif
525
+
526
+ Pointer& Pointer::operator=(Pointer&& other) JSI_NOEXCEPT_15 {
527
+ if (ptr_) {
528
+ ptr_->invalidate();
529
+ }
530
+ ptr_ = other.ptr_;
531
+ other.ptr_ = nullptr;
532
+ return *this;
533
+ }
534
+
535
+ Object Object::getPropertyAsObject(Runtime& runtime, const char* name) const {
536
+ Value v = getProperty(runtime, name);
537
+
538
+ if (!v.isObject()) {
539
+ throw JSError(
540
+ runtime,
541
+ std::string("getPropertyAsObject: property '") + name + "' is " +
542
+ kindToString(v, &runtime) + ", expected an Object");
543
+ }
544
+
545
+ return v.getObject(runtime);
546
+ }
547
+
548
+ Function Object::getPropertyAsFunction(Runtime& runtime, const char* name)
549
+ const {
550
+ Object obj = getPropertyAsObject(runtime, name);
551
+ if (!obj.isFunction(runtime)) {
552
+ throw JSError(
553
+ runtime,
554
+ std::string("getPropertyAsFunction: property '") + name + "' is " +
555
+ kindToString(std::move(obj), &runtime) + ", expected a Function");
556
+ };
557
+
558
+ return std::move(obj).getFunction(runtime);
559
+ }
560
+
561
+ Array Object::asArray(Runtime& runtime) const& {
562
+ if (!isArray(runtime)) {
563
+ throw JSError(
564
+ runtime,
565
+ "Object is " + kindToString(Value(runtime, *this), &runtime) +
566
+ ", expected an array");
567
+ }
568
+ return getArray(runtime);
569
+ }
570
+
571
+ Array Object::asArray(Runtime& runtime) && {
572
+ if (!isArray(runtime)) {
573
+ throw JSError(
574
+ runtime,
575
+ "Object is " + kindToString(Value(runtime, *this), &runtime) +
576
+ ", expected an array");
577
+ }
578
+ return std::move(*this).getArray(runtime);
579
+ }
580
+
581
+ Function Object::asFunction(Runtime& runtime) const& {
582
+ if (!isFunction(runtime)) {
583
+ throw JSError(
584
+ runtime,
585
+ "Object is " + kindToString(Value(runtime, *this), &runtime) +
586
+ ", expected a function");
587
+ }
588
+ return getFunction(runtime);
589
+ }
590
+
591
+ Function Object::asFunction(Runtime& runtime) && {
592
+ if (!isFunction(runtime)) {
593
+ throw JSError(
594
+ runtime,
595
+ "Object is " + kindToString(Value(runtime, *this), &runtime) +
596
+ ", expected a function");
597
+ }
598
+ return std::move(*this).getFunction(runtime);
599
+ }
600
+
601
+ Value::Value(Value&& other) JSI_NOEXCEPT_15 : Value(other.kind_) {
602
+ if (kind_ == BooleanKind) {
603
+ data_.boolean = other.data_.boolean;
604
+ } else if (kind_ == NumberKind) {
605
+ data_.number = other.data_.number;
606
+ } else if (kind_ >= PointerKind) {
607
+ new (&data_.pointer) Pointer(std::move(other.data_.pointer));
608
+ }
609
+ // when the other's dtor runs, nothing will happen.
610
+ other.kind_ = UndefinedKind;
611
+ }
612
+
613
+ Value::Value(Runtime& runtime, const Value& other) : Value(other.kind_) {
614
+ // data_ is uninitialized, so use placement new to create non-POD
615
+ // types in it. Any other kind of initialization will call a dtor
616
+ // first, which is incorrect.
617
+ if (kind_ == BooleanKind) {
618
+ data_.boolean = other.data_.boolean;
619
+ } else if (kind_ == NumberKind) {
620
+ data_.number = other.data_.number;
621
+ } else if (kind_ == SymbolKind) {
622
+ new (&data_.pointer) Pointer(runtime.cloneSymbol(other.data_.pointer.ptr_));
623
+ #if JSI_VERSION >= 6
624
+ } else if (kind_ == BigIntKind) {
625
+ new (&data_.pointer) Pointer(runtime.cloneBigInt(other.data_.pointer.ptr_));
626
+ #endif
627
+ } else if (kind_ == StringKind) {
628
+ new (&data_.pointer) Pointer(runtime.cloneString(other.data_.pointer.ptr_));
629
+ } else if (kind_ >= ObjectKind) {
630
+ new (&data_.pointer) Pointer(runtime.cloneObject(other.data_.pointer.ptr_));
631
+ }
632
+ }
633
+
634
+ Value::~Value() {
635
+ if (kind_ >= PointerKind) {
636
+ data_.pointer.~Pointer();
637
+ }
638
+ }
639
+
640
+ bool Value::strictEquals(Runtime& runtime, const Value& a, const Value& b) {
641
+ if (a.kind_ != b.kind_) {
642
+ return false;
643
+ }
644
+ switch (a.kind_) {
645
+ case UndefinedKind:
646
+ case NullKind:
647
+ return true;
648
+ case BooleanKind:
649
+ return a.data_.boolean == b.data_.boolean;
650
+ case NumberKind:
651
+ return a.data_.number == b.data_.number;
652
+ case SymbolKind:
653
+ return runtime.strictEquals(
654
+ static_cast<const Symbol&>(a.data_.pointer),
655
+ static_cast<const Symbol&>(b.data_.pointer));
656
+ #if JSI_VERSION >= 6
657
+ case BigIntKind:
658
+ return runtime.strictEquals(
659
+ static_cast<const BigInt&>(a.data_.pointer),
660
+ static_cast<const BigInt&>(b.data_.pointer));
661
+ #endif
662
+ case StringKind:
663
+ return runtime.strictEquals(
664
+ static_cast<const String&>(a.data_.pointer),
665
+ static_cast<const String&>(b.data_.pointer));
666
+ case ObjectKind:
667
+ return runtime.strictEquals(
668
+ static_cast<const Object&>(a.data_.pointer),
669
+ static_cast<const Object&>(b.data_.pointer));
670
+ }
671
+ return false;
672
+ }
673
+
674
+ bool Value::asBool() const {
675
+ if (!isBool()) {
676
+ throw JSINativeException(
677
+ "Value is " + kindToString(*this) + ", expected a boolean");
678
+ }
679
+
680
+ return getBool();
681
+ }
682
+
683
+ double Value::asNumber() const {
684
+ if (!isNumber()) {
685
+ throw JSINativeException(
686
+ "Value is " + kindToString(*this) + ", expected a number");
687
+ }
688
+
689
+ return getNumber();
690
+ }
691
+
692
+ Object Value::asObject(Runtime& rt) const& {
693
+ if (!isObject()) {
694
+ throw JSError(
695
+ rt, "Value is " + kindToString(*this, &rt) + ", expected an Object");
696
+ }
697
+
698
+ return getObject(rt);
699
+ }
700
+
701
+ Object Value::asObject(Runtime& rt) && {
702
+ if (!isObject()) {
703
+ throw JSError(
704
+ rt, "Value is " + kindToString(*this, &rt) + ", expected an Object");
705
+ }
706
+ auto ptr = data_.pointer.ptr_;
707
+ data_.pointer.ptr_ = nullptr;
708
+ return static_cast<Object>(ptr);
709
+ }
710
+
711
+ Symbol Value::asSymbol(Runtime& rt) const& {
712
+ if (!isSymbol()) {
713
+ throw JSError(
714
+ rt, "Value is " + kindToString(*this, &rt) + ", expected a Symbol");
715
+ }
716
+
717
+ return getSymbol(rt);
718
+ }
719
+
720
+ Symbol Value::asSymbol(Runtime& rt) && {
721
+ if (!isSymbol()) {
722
+ throw JSError(
723
+ rt, "Value is " + kindToString(*this, &rt) + ", expected a Symbol");
724
+ }
725
+
726
+ return std::move(*this).getSymbol(rt);
727
+ }
728
+
729
+ #if JSI_VERSION >= 6
730
+ BigInt Value::asBigInt(Runtime& rt) const& {
731
+ if (!isBigInt()) {
732
+ throw JSError(
733
+ rt, "Value is " + kindToString(*this, &rt) + ", expected a BigInt");
734
+ }
735
+
736
+ return getBigInt(rt);
737
+ }
738
+
739
+ BigInt Value::asBigInt(Runtime& rt) && {
740
+ if (!isBigInt()) {
741
+ throw JSError(
742
+ rt, "Value is " + kindToString(*this, &rt) + ", expected a BigInt");
743
+ }
744
+
745
+ return std::move(*this).getBigInt(rt);
746
+ }
747
+ #endif
748
+
749
+ String Value::asString(Runtime& rt) const& {
750
+ if (!isString()) {
751
+ throw JSError(
752
+ rt, "Value is " + kindToString(*this, &rt) + ", expected a String");
753
+ }
754
+
755
+ return getString(rt);
756
+ }
757
+
758
+ String Value::asString(Runtime& rt) && {
759
+ if (!isString()) {
760
+ throw JSError(
761
+ rt, "Value is " + kindToString(*this, &rt) + ", expected a String");
762
+ }
763
+
764
+ return std::move(*this).getString(rt);
765
+ }
766
+
767
+ String Value::toString(Runtime& runtime) const {
768
+ Function toString = runtime.global().getPropertyAsFunction(runtime, "String");
769
+ return toString.call(runtime, *this).getString(runtime);
770
+ }
771
+
772
+ #if JSI_VERSION >= 8
773
+ uint64_t BigInt::asUint64(Runtime& runtime) const {
774
+ if (!isUint64(runtime)) {
775
+ throw JSError(runtime, "Lossy truncation in BigInt64::asUint64");
776
+ }
777
+ return getUint64(runtime);
778
+ }
779
+
780
+ int64_t BigInt::asInt64(Runtime& runtime) const {
781
+ if (!isInt64(runtime)) {
782
+ throw JSError(runtime, "Lossy truncation in BigInt64::asInt64");
783
+ }
784
+ return getInt64(runtime);
785
+ }
786
+ #endif
787
+
788
+ Array Array::createWithElements(
789
+ Runtime& rt,
790
+ std::initializer_list<Value> elements) {
791
+ Array result(rt, elements.size());
792
+ size_t index = 0;
793
+ for (const auto& element : elements) {
794
+ result.setValueAtIndex(rt, index++, element);
795
+ }
796
+ return result;
797
+ }
798
+
799
+ std::vector<PropNameID> HostObject::getPropertyNames(Runtime&) {
800
+ return {};
801
+ }
802
+
803
+ Runtime::ScopeState* Runtime::pushScope() {
804
+ return nullptr;
805
+ }
806
+
807
+ void Runtime::popScope(ScopeState*) {}
808
+
809
+ JSError::JSError(Runtime& rt, Value&& value) {
810
+ setValue(rt, std::move(value));
811
+ }
812
+
813
+ JSError::JSError(Runtime& rt, std::string msg) : message_(std::move(msg)) {
814
+ try {
815
+ setValue(
816
+ rt,
817
+ callGlobalFunction(rt, "Error", String::createFromUtf8(rt, message_)));
818
+ } catch (const JSIException& ex) {
819
+ message_ = std::string(ex.what()) + " (while raising " + message_ + ")";
820
+ setValue(rt, String::createFromUtf8(rt, message_));
821
+ }
822
+ }
823
+
824
+ JSError::JSError(Runtime& rt, std::string msg, std::string stack)
825
+ : message_(std::move(msg)), stack_(std::move(stack)) {
826
+ try {
827
+ Object e(rt);
828
+ e.setProperty(rt, "message", String::createFromUtf8(rt, message_));
829
+ e.setProperty(rt, "stack", String::createFromUtf8(rt, stack_));
830
+ setValue(rt, std::move(e));
831
+ } catch (const JSIException& ex) {
832
+ setValue(rt, String::createFromUtf8(rt, ex.what()));
833
+ }
834
+ }
835
+
836
+ JSError::JSError(std::string what, Runtime& rt, Value&& value)
837
+ : JSIException(std::move(what)) {
838
+ setValue(rt, std::move(value));
839
+ }
840
+
841
+ JSError::JSError(Value&& value, std::string message, std::string stack)
842
+ : JSIException(message + "\n\n" + stack),
843
+ value_(std::make_shared<Value>(std::move(value))),
844
+ message_(std::move(message)),
845
+ stack_(std::move(stack)) {}
846
+
847
+ void JSError::setValue(Runtime& rt, Value&& value) {
848
+ value_ = std::make_shared<Value>(std::move(value));
849
+
850
+ if ((message_.empty() || stack_.empty()) && value_->isObject()) {
851
+ auto obj = value_->getObject(rt);
852
+
853
+ if (message_.empty()) {
854
+ try {
855
+ Value message = obj.getProperty(rt, "message");
856
+ if (!message.isUndefined() && !message.isString()) {
857
+ message = callGlobalFunction(rt, "String", message);
858
+ }
859
+ if (message.isString()) {
860
+ message_ = message.getString(rt).utf8(rt);
861
+ } else if (!message.isUndefined()) {
862
+ message_ = "String(e.message) is a " + kindToString(message, &rt);
863
+ }
864
+ } catch (const JSIException& ex) {
865
+ message_ = std::string("[Exception while creating message string: ") +
866
+ ex.what() + "]";
867
+ }
868
+ }
869
+
870
+ if (stack_.empty()) {
871
+ try {
872
+ Value stack = obj.getProperty(rt, "stack");
873
+ if (!stack.isUndefined() && !stack.isString()) {
874
+ stack = callGlobalFunction(rt, "String", stack);
875
+ }
876
+ if (stack.isString()) {
877
+ stack_ = stack.getString(rt).utf8(rt);
878
+ } else if (!stack.isUndefined()) {
879
+ stack_ = "String(e.stack) is a " + kindToString(stack, &rt);
880
+ }
881
+ } catch (const JSIException& ex) {
882
+ message_ = std::string("[Exception while creating stack string: ") +
883
+ ex.what() + "]";
884
+ }
885
+ }
886
+ }
887
+
888
+ if (message_.empty()) {
889
+ try {
890
+ if (value_->isString()) {
891
+ message_ = value_->getString(rt).utf8(rt);
892
+ } else {
893
+ Value message = callGlobalFunction(rt, "String", *value_);
894
+ if (message.isString()) {
895
+ message_ = message.getString(rt).utf8(rt);
896
+ } else {
897
+ message_ = "String(e) is a " + kindToString(message, &rt);
898
+ }
899
+ }
900
+ } catch (const JSIException& ex) {
901
+ message_ = std::string("[Exception while creating message string: ") +
902
+ ex.what() + "]";
903
+ }
904
+ }
905
+
906
+ if (stack_.empty()) {
907
+ stack_ = "no stack";
908
+ }
909
+
910
+ if (what_.empty()) {
911
+ what_ = message_ + "\n\n" + stack_;
912
+ }
913
+ }
914
+
915
+ JSIException::~JSIException() {}
916
+
917
+ JSINativeException::~JSINativeException() {}
918
+
919
+ JSError::~JSError() {}
920
+
921
+ } // namespace jsi
922
+ } // namespace facebook