react-native-nitro-modules 0.31.10 → 0.32.0-beta.0

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 (35) hide show
  1. package/NitroModules.podspec +1 -0
  2. package/android/src/main/cpp/core/JAnyMap.cpp +120 -0
  3. package/android/src/main/cpp/core/JAnyMap.hpp +20 -56
  4. package/android/src/main/cpp/platform/NitroLogger.cpp +3 -1
  5. package/android/src/main/java/com/margelo/nitro/core/AnyMap.kt +3 -5
  6. package/cpp/core/AnyMap.hpp +2 -2
  7. package/cpp/core/HybridObject.cpp +10 -10
  8. package/cpp/entrypoint/InstallNitro.cpp +2 -2
  9. package/cpp/jsi/JSICache.cpp +10 -5
  10. package/cpp/jsi/JSICache.hpp +6 -0
  11. package/cpp/jsi/JSIConverter+AnyMap.hpp +4 -3
  12. package/cpp/jsi/JSIConverter+Date.hpp +8 -10
  13. package/cpp/jsi/JSIConverter+Exception.hpp +5 -5
  14. package/cpp/jsi/JSIConverter+Function.hpp +4 -1
  15. package/cpp/jsi/JSIConverter+Promise.hpp +8 -14
  16. package/cpp/jsi/JSIConverter+UnorderedMap.hpp +2 -1
  17. package/cpp/jsi/JSIHelpers.hpp +1 -1
  18. package/cpp/platform/NitroLogger.hpp +3 -1
  19. package/cpp/prototype/HybridObjectPrototype.cpp +28 -28
  20. package/cpp/threading/Dispatcher.cpp +5 -5
  21. package/cpp/utils/BorrowingReference.hpp +6 -6
  22. package/cpp/utils/CommonGlobals.cpp +215 -0
  23. package/cpp/utils/CommonGlobals.hpp +158 -0
  24. package/cpp/utils/NitroDefines.hpp +1 -1
  25. package/cpp/utils/PropNameIDCache.cpp +38 -0
  26. package/cpp/utils/PropNameIDCache.hpp +44 -0
  27. package/cpp/utils/{WeakReference+Owning.hpp → WeakReference+Borrowing.hpp} +1 -1
  28. package/cpp/utils/WeakReference.hpp +1 -1
  29. package/ios/platform/NitroLogger.cpp +37 -0
  30. package/ios/platform/ThreadUtils.cpp +43 -0
  31. package/package.json +1 -2
  32. package/cpp/utils/ObjectUtils.cpp +0 -172
  33. package/cpp/utils/ObjectUtils.hpp +0 -94
  34. package/ios/platform/NitroLogger.mm +0 -36
  35. package/ios/platform/ThreadUtils.mm +0 -46
@@ -48,6 +48,7 @@ Pod::Spec.new do |s|
48
48
  "cpp/utils/FastVectorCopy.hpp",
49
49
  "cpp/utils/NitroHash.hpp",
50
50
  "cpp/utils/NitroDefines.hpp",
51
+ "cpp/utils/PropNameIDCache.hpp",
51
52
  "cpp/views/CachedProp.hpp",
52
53
  # Public iOS-specific headers that will be exposed in modulemap (for Swift)
53
54
  "ios/core/ArrayBufferHolder.hpp",
@@ -0,0 +1,120 @@
1
+ //
2
+ // JAnyMap.cpp
3
+ // react-native-nitro
4
+ //
5
+ // Created by Marc Rousavy on 14.07.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "JAnyMap.hpp"
11
+
12
+ namespace margelo::nitro {
13
+
14
+ using namespace facebook;
15
+
16
+ jni::local_ref<jni::JArrayClass<jni::JString>> JAnyMap::getAllKeys() {
17
+ auto& map = _map->getMap();
18
+ auto array = jni::JArrayClass<jni::JString>::newArray(map.size());
19
+ size_t index = 0;
20
+ for (const auto& pair : map) {
21
+ auto jKey = jni::make_jstring(pair.first);
22
+ array->setElement(index, *jKey);
23
+ index++;
24
+ }
25
+ return array;
26
+ }
27
+
28
+ jni::local_ref<JAnyArray> JAnyMap::getAnyArray(const std::string& key) {
29
+ const auto& vector = _map->getArray(key);
30
+ auto javaArray = jni::JArrayClass<JAnyValue::javaobject>::newArray(vector.size());
31
+ for (size_t i = 0; i < vector.size(); i++) {
32
+ auto value = JAnyValue::create(vector[i]);
33
+ javaArray->setElement(i, value.get());
34
+ }
35
+ return javaArray;
36
+ }
37
+
38
+ jni::local_ref<JAnyObject> JAnyMap::getAnyObject(const std::string& key) {
39
+ const auto& map = _map->getObject(key);
40
+ auto javaMap = jni::JHashMap<jni::JString, JAnyValue::javaobject>::create(map.size());
41
+ for (const auto& entry : map) {
42
+ auto string = jni::make_jstring(entry.first);
43
+ auto value = JAnyValue::create(entry.second);
44
+ javaMap->put(string, value);
45
+ }
46
+ return javaMap;
47
+ }
48
+
49
+ jni::local_ref<JAnyValue::javaobject> JAnyMap::getAnyValue(const std::string& key) {
50
+ const auto& any = _map->getAny(key);
51
+ return JAnyValue::create(any);
52
+ }
53
+
54
+ void JAnyMap::setAnyArray(const std::string& key, jni::alias_ref<JAnyArray> value) {
55
+ std::vector<AnyValue> vector;
56
+ size_t size = value->size();
57
+ vector.reserve(size);
58
+ for (size_t i = 0; i < size; i++) {
59
+ auto anyValue = value->getElement(i);
60
+ vector.push_back(anyValue->cthis()->getValue());
61
+ }
62
+ _map->setArray(key, vector);
63
+ }
64
+ void JAnyMap::setAnyObject(const std::string& key, const jni::alias_ref<JAnyObject>& value) {
65
+ std::unordered_map<std::string, AnyValue> map;
66
+ map.reserve(value->size());
67
+ for (const auto& entry : *value) {
68
+ map.emplace(entry.first->toStdString(), entry.second->cthis()->getValue());
69
+ }
70
+ _map->setObject(key, map);
71
+ }
72
+ void JAnyMap::setAnyValue(const std::string& key, const jni::alias_ref<JAnyValue::javaobject>& value) {
73
+ _map->setAny(key, value->cthis()->getValue());
74
+ }
75
+
76
+ jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> JAnyMap::toHashMap() {
77
+ const auto& map = _map->getMap();
78
+ auto javaMap = jni::JHashMap<jni::JString, jni::JObject>::create(map.size());
79
+ for (const auto& [key, value] : map) {
80
+ javaMap->put(jni::make_jstring(key), anyValueToJObject(value));
81
+ }
82
+ return javaMap;
83
+ }
84
+
85
+ jni::local_ref<jni::JObject> JAnyMap::anyValueToJObject(const AnyValue& value) {
86
+ if (std::holds_alternative<NullType>(value)) {
87
+ return nullptr;
88
+ } else if (std::holds_alternative<double>(value)) {
89
+ return jni::JDouble::valueOf(std::get<double>(value));
90
+ } else if (std::holds_alternative<bool>(value)) {
91
+ return jni::JBoolean::valueOf(std::get<bool>(value));
92
+ } else if (std::holds_alternative<int64_t>(value)) {
93
+ return jni::JLong::valueOf(std::get<int64_t>(value));
94
+ } else if (std::holds_alternative<std::string>(value)) {
95
+ return jni::make_jstring(std::get<std::string>(value));
96
+ } else if (std::holds_alternative<AnyArray>(value)) {
97
+ return jni::static_ref_cast<jni::JObject>(anyArrayToJList(std::get<AnyArray>(value)));
98
+ } else if (std::holds_alternative<AnyObject>(value)) {
99
+ return jni::static_ref_cast<jni::JObject>(anyObjectToJHashMap(std::get<AnyObject>(value)));
100
+ }
101
+ return nullptr;
102
+ }
103
+
104
+ jni::local_ref<jni::JArrayList<jni::JObject>> JAnyMap::anyArrayToJList(const AnyArray& array) {
105
+ auto jList = jni::JArrayList<jni::JObject>::create(static_cast<int>(array.size()));
106
+ for (const auto& item : array) {
107
+ jList->add(anyValueToJObject(item));
108
+ }
109
+ return jList;
110
+ }
111
+
112
+ jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> JAnyMap::anyObjectToJHashMap(const AnyObject& object) {
113
+ auto jMap = jni::JHashMap<jni::JString, jni::JObject>::create(object.size());
114
+ for (const auto& [key, val] : object) {
115
+ jMap->put(jni::make_jstring(key), anyValueToJObject(val));
116
+ }
117
+ return jMap;
118
+ }
119
+
120
+ } // namespace margelo::nitro
@@ -61,17 +61,7 @@ protected:
61
61
  void clear() {
62
62
  _map->clear();
63
63
  }
64
- jni::local_ref<jni::JArrayClass<jni::JString>> getAllKeys() {
65
- auto& map = _map->getMap();
66
- auto array = jni::JArrayClass<jni::JString>::newArray(map.size());
67
- size_t index = 0;
68
- for (const auto& pair : map) {
69
- auto jKey = jni::make_jstring(pair.first);
70
- array->setElement(index, *jKey);
71
- index++;
72
- }
73
- return array;
74
- }
64
+ jni::local_ref<jni::JArrayClass<jni::JString>> getAllKeys();
75
65
 
76
66
  protected:
77
67
  bool isNull(const std::string& key) {
@@ -109,29 +99,9 @@ protected:
109
99
  std::string getString(const std::string& key) {
110
100
  return _map->getString(key);
111
101
  }
112
- jni::local_ref<JAnyArray> getAnyArray(const std::string& key) {
113
- const auto& vector = _map->getArray(key);
114
- auto javaArray = jni::JArrayClass<JAnyValue::javaobject>::newArray(vector.size());
115
- for (size_t i = 0; i < vector.size(); i++) {
116
- auto value = JAnyValue::create(vector[i]);
117
- javaArray->setElement(i, value.get());
118
- }
119
- return javaArray;
120
- }
121
- jni::local_ref<JAnyObject> getAnyObject(const std::string& key) {
122
- const auto& map = _map->getObject(key);
123
- auto javaMap = jni::JHashMap<jni::JString, JAnyValue::javaobject>::create(map.size());
124
- for (const auto& entry : map) {
125
- auto string = jni::make_jstring(entry.first);
126
- auto value = JAnyValue::create(entry.second);
127
- javaMap->put(string, value);
128
- }
129
- return javaMap;
130
- }
131
- jni::local_ref<JAnyValue::javaobject> getAnyValue(const std::string& key) {
132
- const auto& any = _map->getAny(key);
133
- return JAnyValue::create(any);
134
- }
102
+ jni::local_ref<JAnyArray> getAnyArray(const std::string& key);
103
+ jni::local_ref<JAnyObject> getAnyObject(const std::string& key);
104
+ jni::local_ref<JAnyValue::javaobject> getAnyValue(const std::string& key);
135
105
 
136
106
  protected:
137
107
  void setNull(const std::string& key) {
@@ -149,33 +119,25 @@ protected:
149
119
  void setString(const std::string& key, const std::string& value) {
150
120
  _map->setString(key, value);
151
121
  }
152
- void setAnyArray(const std::string& key, jni::alias_ref<JAnyArray> value) {
153
- std::vector<AnyValue> vector;
154
- size_t size = value->size();
155
- vector.reserve(size);
156
- for (size_t i = 0; i < size; i++) {
157
- auto anyValue = value->getElement(i);
158
- vector.push_back(anyValue->cthis()->getValue());
159
- }
160
- _map->setArray(key, vector);
161
- }
162
- void setAnyObject(const std::string& key, const jni::alias_ref<JAnyObject>& value) {
163
- std::unordered_map<std::string, AnyValue> map;
164
- map.reserve(value->size());
165
- for (const auto& entry : *value) {
166
- map.emplace(entry.first->toStdString(), entry.second->cthis()->getValue());
167
- }
168
- _map->setObject(key, map);
169
- }
170
- void setAnyValue(const std::string& key, const jni::alias_ref<JAnyValue::javaobject>& value) {
171
- _map->setAny(key, value->cthis()->getValue());
172
- }
122
+ void setAnyArray(const std::string& key, jni::alias_ref<JAnyArray> value);
123
+ void setAnyObject(const std::string& key, const jni::alias_ref<JAnyObject>& value);
124
+ void setAnyValue(const std::string& key, const jni::alias_ref<JAnyValue::javaobject>& value);
173
125
 
174
126
  protected:
175
127
  void merge(jni::alias_ref<JAnyMap::javaobject> other) {
176
128
  _map->merge(other->cthis()->_map);
177
129
  }
178
130
 
131
+ /**
132
+ * Bulk-converts the entire `JAnyMap` to a Java `HashMap<String, Object>` in a single JNI call.
133
+ */
134
+ jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> toHashMap();
135
+
136
+ private:
137
+ static jni::local_ref<jni::JObject> anyValueToJObject(const AnyValue& value);
138
+ static jni::local_ref<jni::JArrayList<jni::JObject>> anyArrayToJList(const AnyArray& array);
139
+ static jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> anyObjectToJHashMap(const AnyObject& object);
140
+
179
141
  public:
180
142
  [[nodiscard]]
181
143
  std::shared_ptr<AnyMap> getMap() const {
@@ -225,8 +187,10 @@ public:
225
187
  makeNativeMethod("setAnyValue", JAnyMap::setAnyValue),
226
188
  // merge
227
189
  makeNativeMethod("merge", JAnyMap::merge),
190
+ // bulk conversion
191
+ makeNativeMethod("toHashMap", JAnyMap::toHashMap),
228
192
  });
229
193
  }
230
194
  };
231
195
 
232
- } // namespace margelo::nitro
196
+ } // namespace margelo::nitro
@@ -26,7 +26,9 @@ int levelToAndroidLevel(LogLevel level) {
26
26
  }
27
27
  }
28
28
 
29
- void Logger::nativeLog([[maybe_unused]] LogLevel level, [[maybe_unused]] const char* tag, [[maybe_unused]] const std::string& message) {
29
+ void Logger::nativeLog([[maybe_unused]] LogLevel level, //
30
+ [[maybe_unused]] const char* tag, //
31
+ [[maybe_unused]] const std::string& message) {
30
32
  #ifdef NITRO_DEBUG
31
33
  int logLevel = levelToAndroidLevel(level);
32
34
  std::string combinedTag = "Nitro." + std::string(tag);
@@ -60,11 +60,7 @@ class AnyMap {
60
60
  }
61
61
 
62
62
  fun toMap(): Map<String, Any?> {
63
- val map = HashMap<String, Any?>()
64
- for (key in getAllKeys()) {
65
- map.put(key, getAny(key))
66
- }
67
- return map
63
+ return toHashMap()
68
64
  }
69
65
 
70
66
  fun setAny(
@@ -78,6 +74,8 @@ class AnyMap {
78
74
  return getAnyValue(key).toAny()
79
75
  }
80
76
 
77
+ external fun toHashMap(): HashMap<String, Any?>
78
+
81
79
  @FastNative
82
80
  external fun contains(key: String): Boolean
83
81
 
@@ -38,8 +38,8 @@ struct AnyValue : VariantType {
38
38
  */
39
39
  class AnyMap final {
40
40
  private:
41
- explicit AnyMap() {}
42
- AnyMap(size_t size) {
41
+ AnyMap() = default;
42
+ explicit AnyMap(size_t size) {
43
43
  _map.reserve(size);
44
44
  }
45
45
 
@@ -3,9 +3,9 @@
3
3
  //
4
4
 
5
5
  #include "HybridObject.hpp"
6
+ #include "CommonGlobals.hpp"
6
7
  #include "JSIConverter.hpp"
7
8
  #include "NitroDefines.hpp"
8
- #include "ObjectUtils.hpp"
9
9
 
10
10
  namespace margelo::nitro {
11
11
 
@@ -75,7 +75,7 @@ jsi::Value HybridObject::toObject(jsi::Runtime& runtime) {
75
75
  jsi::Value prototype = getPrototype(runtime);
76
76
 
77
77
  // 3. Create the object using Object.create(...)
78
- jsi::Object object = ObjectUtils::create(runtime, prototype);
78
+ jsi::Object object = CommonGlobals::Object::create(runtime, prototype);
79
79
 
80
80
  // 4. Assign NativeState to the object so the prototype can resolve the native methods
81
81
  object.setNativeState(runtime, shared());
@@ -86,14 +86,14 @@ jsi::Value HybridObject::toObject(jsi::Runtime& runtime) {
86
86
  #ifdef NITRO_DEBUG
87
87
  // 6. Assign a private __type property for debugging - this will be used so users know it's not just an empty object.
88
88
  std::string typeName = "HybridObject<" + std::string(_name) + ">";
89
- ObjectUtils::defineProperty(runtime, object, "__type",
90
- PlainPropertyDescriptor{
91
- // .configurable has to be true because this property is non-frozen
92
- .configurable = true,
93
- .enumerable = true,
94
- .value = jsi::String::createFromUtf8(runtime, typeName),
95
- .writable = false,
96
- });
89
+ CommonGlobals::Object::defineProperty(runtime, object, "__type",
90
+ PlainPropertyDescriptor{
91
+ // .configurable has to be true because this property is non-frozen
92
+ .configurable = true,
93
+ .enumerable = true,
94
+ .value = jsi::String::createFromUtf8(runtime, typeName),
95
+ .writable = false,
96
+ });
97
97
  #endif
98
98
 
99
99
  // 7. Throw a jsi::WeakObject pointing to our object into cache so subsequent calls can use it from cache
@@ -6,8 +6,8 @@
6
6
  //
7
7
 
8
8
  #include "InstallNitro.hpp"
9
+ #include "CommonGlobals.hpp"
9
10
  #include "HybridNitroModulesProxy.hpp"
10
- #include "ObjectUtils.hpp"
11
11
 
12
12
  namespace margelo::nitro {
13
13
 
@@ -23,7 +23,7 @@ void install(jsi::Runtime& runtime, std::shared_ptr<Dispatcher> dispatcher) {
23
23
  void install(jsi::Runtime& runtime) {
24
24
  // Installs global.NitroModulesProxy
25
25
  auto proxy = std::make_shared<HybridNitroModulesProxy>();
26
- ObjectUtils::defineGlobal(runtime, KnownGlobalPropertyName::NITRO_MODULES_PROXY, proxy->toObject(runtime));
26
+ CommonGlobals::defineGlobal(runtime, KnownGlobalPropertyName::NITRO_MODULES_PROXY, proxy->toObject(runtime));
27
27
  }
28
28
 
29
29
  } // namespace margelo::nitro
@@ -6,9 +6,9 @@
6
6
  //
7
7
 
8
8
  #include "JSICache.hpp"
9
+ #include "CommonGlobals.hpp"
9
10
  #include "JSIHelpers.hpp"
10
11
  #include "NitroDefines.hpp"
11
- #include "ObjectUtils.hpp"
12
12
 
13
13
  namespace margelo::nitro {
14
14
 
@@ -54,11 +54,16 @@ JSICacheReference JSICache::getOrCreateCache(jsi::Runtime& runtime) {
54
54
  // Wrap it in a jsi::Value using NativeState
55
55
  jsi::Object cache(runtime);
56
56
  cache.setNativeState(runtime, nativeState);
57
- // Inject it into the jsi::Runtime's global so it's memory is managed by it.
58
- // We pass `allowCache = false` because we are the JSICache, and this would cause recursion.
59
- ObjectUtils::defineGlobal(runtime, KnownGlobalPropertyName::JSI_CACHE, std::move(cache), /* allowCache */ false);
60
- // Add it to our map of caches
57
+ // Add it to our map of caches first, because the next `::defineGlobal(...)` call will already be using it (recursively)
61
58
  _globalCache[&runtime] = nativeState;
59
+ try {
60
+ // Call Object.defineProperty(global, ...) now with our cache (it internally already uses cache)
61
+ CommonGlobals::defineGlobal(runtime, KnownGlobalPropertyName::JSI_CACHE, std::move(cache));
62
+ } catch (...) {
63
+ // If `defineGlobal(...)` failed, we should remove it from `_globalCache` so we don't have invalid caches.
64
+ _globalCache.erase(&runtime);
65
+ throw;
66
+ }
62
67
  // Return it
63
68
  return JSICacheReference(nativeState);
64
69
  }
@@ -63,6 +63,7 @@ private:
63
63
  std::vector<WeakReference<jsi::Object>> _objectCache;
64
64
  std::vector<WeakReference<jsi::Function>> _functionCache;
65
65
  std::vector<WeakReference<jsi::WeakObject>> _weakObjectCache;
66
+ std::vector<WeakReference<jsi::PropNameID>> _propNameIDCache;
66
67
  std::vector<WeakReference<jsi::ArrayBuffer>> _arrayBufferCache;
67
68
 
68
69
  private:
@@ -103,6 +104,11 @@ public:
103
104
  _strongCache->_weakObjectCache.push_back(owning.weak());
104
105
  return owning;
105
106
  }
107
+ BorrowingReference<jsi::PropNameID> makeShared(jsi::PropNameID&& value) {
108
+ BorrowingReference<jsi::PropNameID> owning(new jsi::PropNameID(std::move(value)));
109
+ _strongCache->_propNameIDCache.push_back(owning.weak());
110
+ return owning;
111
+ }
106
112
  BorrowingReference<jsi::ArrayBuffer> makeShared(jsi::ArrayBuffer&& value) {
107
113
  BorrowingReference<jsi::ArrayBuffer> owning(new jsi::ArrayBuffer(std::move(value)));
108
114
  _strongCache->_arrayBufferCache.push_back(owning.weak());
@@ -18,6 +18,7 @@ struct JSIConverter;
18
18
 
19
19
  #include "AnyMap.hpp"
20
20
  #include "JSIHelpers.hpp"
21
+ #include "PropNameIDCache.hpp"
21
22
  #include <jsi/jsi.h>
22
23
  #include <memory>
23
24
 
@@ -48,9 +49,9 @@ struct JSIConverter<std::shared_ptr<AnyMap>> final {
48
49
  size_t size = propNames.size(runtime);
49
50
  std::shared_ptr<AnyMap> map = AnyMap::make();
50
51
  for (size_t i = 0; i < size; i++) {
51
- jsi::String jsKey = propNames.getValueAtIndex(runtime, i).getString(runtime);
52
- jsi::Value jsValue = object.getProperty(runtime, jsKey);
53
- map->setAny(jsKey.utf8(runtime), JSIConverter<AnyValue>::fromJSI(runtime, jsValue));
52
+ std::string jsKey = propNames.getValueAtIndex(runtime, i).getString(runtime).utf8(runtime);
53
+ jsi::Value jsValue = object.getProperty(runtime, PropNameIDCache::get(runtime, jsKey));
54
+ map->setAny(jsKey, JSIConverter<AnyValue>::fromJSI(runtime, jsValue));
54
55
  }
55
56
  return map;
56
57
  }
@@ -14,6 +14,8 @@ struct JSIConverter;
14
14
 
15
15
  #include "JSIConverter.hpp"
16
16
 
17
+ #include "CommonGlobals.hpp"
18
+ #include "PropNameIDCache.hpp"
17
19
  #include <chrono>
18
20
  #include <jsi/jsi.h>
19
21
  #include <memory>
@@ -38,15 +40,15 @@ struct JSIConverter<std::chrono::system_clock::time_point> final {
38
40
 
39
41
  jsi::Object object = arg.asObject(runtime);
40
42
  #ifdef NITRO_DEBUG
41
- if (!object.hasProperty(runtime, "getTime")) {
43
+ if (!object.hasProperty(runtime, PropNameIDCache::get(runtime, "getTime"))) {
42
44
  throw std::invalid_argument("Object \"" + arg.toString(runtime).utf8(runtime) +
43
45
  "\" does not have a .getTime() function! "
44
46
  "It's not a valid Date object.");
45
47
  }
46
48
  #endif
47
49
 
48
- // TODO: Cache this
49
- jsi::Function getTimeFunc = object.getPropertyAsFunction(runtime, "getTime");
50
+ jsi::Function getTimeFunc =
51
+ object.getProperty(runtime, PropNameIDCache::get(runtime, "getTime")).getObject(runtime).getFunction(runtime);
50
52
  double msSinceEpoch = getTimeFunc.callWithThis(runtime, object).getNumber();
51
53
 
52
54
  // ms -> std::chrono::system_clock::time_point
@@ -62,19 +64,15 @@ struct JSIConverter<std::chrono::system_clock::time_point> final {
62
64
  auto ms = chrono::duration_cast<chrono::milliseconds>(date.time_since_epoch()).count();
63
65
  auto msSinceEpoch = static_cast<double>(ms);
64
66
 
65
- // TODO: Cache this
66
- jsi::Function dateCtor = runtime.global().getPropertyAsFunction(runtime, "Date");
67
-
68
- jsi::Value jsDate = dateCtor.callAsConstructor(runtime, {jsi::Value(msSinceEpoch)});
67
+ // 2. Call `new Date(...)` with the milliseconds since epoch
68
+ jsi::Value jsDate = CommonGlobals::Date::callConstructor(runtime, msSinceEpoch);
69
69
  return jsDate;
70
70
  }
71
71
 
72
72
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
73
73
  if (value.isObject()) {
74
74
  jsi::Object object = value.getObject(runtime);
75
-
76
- jsi::Function dateCtor = runtime.global().getPropertyAsFunction(runtime, "Date");
77
- return object.instanceOf(runtime, dateCtor);
75
+ return CommonGlobals::Date::isInstanceOf(runtime, object);
78
76
  }
79
77
  return false;
80
78
  }
@@ -10,9 +10,10 @@ template <typename T, typename Enable>
10
10
  struct JSIConverter;
11
11
  } // namespace margelo::nitro
12
12
 
13
+ #include "CommonGlobals.hpp"
13
14
  #include "JSIConverter.hpp"
14
-
15
15
  #include "NitroTypeInfo.hpp"
16
+ #include "PropNameIDCache.hpp"
16
17
  #include <exception>
17
18
  #include <jsi/jsi.h>
18
19
 
@@ -25,8 +26,8 @@ template <>
25
26
  struct JSIConverter<std::exception_ptr> final {
26
27
  static inline std::exception_ptr fromJSI(jsi::Runtime& runtime, const jsi::Value& error) {
27
28
  jsi::Object object = error.asObject(runtime);
28
- std::string name = object.getProperty(runtime, "name").asString(runtime).utf8(runtime);
29
- std::string message = object.getProperty(runtime, "message").asString(runtime).utf8(runtime);
29
+ std::string name = object.getProperty(runtime, PropNameIDCache::get(runtime, "name")).asString(runtime).utf8(runtime);
30
+ std::string message = object.getProperty(runtime, PropNameIDCache::get(runtime, "message")).asString(runtime).utf8(runtime);
30
31
  return std::make_exception_ptr(std::runtime_error(name + ": " + message));
31
32
  }
32
33
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::exception_ptr& exception) {
@@ -51,8 +52,7 @@ struct JSIConverter<std::exception_ptr> final {
51
52
  return false;
52
53
  }
53
54
  jsi::Object object = value.getObject(runtime);
54
- jsi::Function errorCtor = runtime.global().getPropertyAsFunction(runtime, "Error");
55
- return object.instanceOf(runtime, errorCtor);
55
+ return CommonGlobals::Error::isInstanceOf(runtime, object);
56
56
  }
57
57
  };
58
58
 
@@ -16,6 +16,7 @@ struct JSIConverter;
16
16
  #include "JSCallback.hpp"
17
17
  #include "JSICache.hpp"
18
18
  #include "PromiseType.hpp"
19
+ #include "PropNameIDCache.hpp"
19
20
  #include <jsi/jsi.h>
20
21
 
21
22
  namespace margelo::nitro {
@@ -56,7 +57,9 @@ struct JSIConverter<std::function<R(Args...)>> final {
56
57
  }
57
58
  return callHybridFunction(function, runtime, args, std::index_sequence_for<Args...>{});
58
59
  };
59
- return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "hostFunction"), sizeof...(Args),
60
+ return jsi::Function::createFromHostFunction(runtime, //
61
+ PropNameIDCache::get(runtime, "hostFunction"), //
62
+ sizeof...(Args), //
60
63
  std::move(jsFunction));
61
64
  }
62
65
 
@@ -11,10 +11,12 @@ template <typename T, typename Enable>
11
11
  struct JSIConverter;
12
12
  } // namespace margelo::nitro
13
13
 
14
+ #include "CommonGlobals.hpp"
14
15
  #include "JSIConverter.hpp"
15
16
  #include "NitroTypeInfo.hpp"
16
17
  #include "Null.hpp"
17
18
  #include "Promise.hpp"
19
+ #include "PropNameIDCache.hpp"
18
20
  #include <exception>
19
21
  #include <jsi/jsi.h>
20
22
  #include <memory>
@@ -44,7 +46,7 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
44
46
 
45
47
  // Chain .then listeners on JS Promise (onResolved and onRejected)
46
48
  jsi::Object jsPromise = value.asObject(runtime);
47
- jsi::Function thenFn = jsPromise.getPropertyAsFunction(runtime, "then");
49
+ jsi::Function thenFn = jsPromise.getProperty(runtime, PropNameIDCache::get(runtime, "then")).asObject(runtime).getFunction(runtime);
48
50
  thenFn.callWithThis(runtime, jsPromise, thenCallback, catchCallback);
49
51
 
50
52
  return promise;
@@ -53,7 +55,6 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
53
55
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::shared_ptr<Promise<TResult>>& promise) {
54
56
  if (promise->isPending()) {
55
57
  // Get Promise ctor from global
56
- jsi::Function promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
57
58
  jsi::HostFunctionType executor = [promise](jsi::Runtime& runtime, const jsi::Value&, const jsi::Value* arguments,
58
59
  size_t) -> jsi::Value {
59
60
  // Add resolver listener
@@ -72,27 +73,21 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
72
73
 
73
74
  return jsi::Value::undefined();
74
75
  };
75
- // Call `Promise` constructor (aka create promise), and pass `executor` function
76
- return promiseCtor.callAsConstructor(
77
- runtime, jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "executor"), 2, executor));
76
+ return CommonGlobals::Promise::callConstructor(runtime, std::move(executor));
78
77
  } else if (promise->isResolved()) {
79
78
  // Promise is already resolved - just return immediately
80
- jsi::Object promiseObject = runtime.global().getPropertyAsObject(runtime, "Promise");
81
- jsi::Function createResolvedPromise = promiseObject.getPropertyAsFunction(runtime, "resolve");
82
79
  if constexpr (std::is_void_v<TResult>) {
83
80
  // It's resolving to void.
84
- return createResolvedPromise.call(runtime);
81
+ return CommonGlobals::Promise::resolved(runtime);
85
82
  } else {
86
83
  // It's resolving to a type.
87
84
  jsi::Value result = JSIConverter<TResult>::toJSI(runtime, promise->getResult());
88
- return createResolvedPromise.call(runtime, std::move(result));
85
+ return CommonGlobals::Promise::resolved(runtime, std::move(result));
89
86
  }
90
87
  } else if (promise->isRejected()) {
91
88
  // Promise is already rejected - just return immediately
92
- jsi::Object promiseObject = runtime.global().getPropertyAsObject(runtime, "Promise");
93
- jsi::Function createRejectedPromise = promiseObject.getPropertyAsFunction(runtime, "reject");
94
89
  jsi::Value error = JSIConverter<std::exception_ptr>::toJSI(runtime, promise->getError());
95
- return createRejectedPromise.call(runtime, std::move(error));
90
+ return CommonGlobals::Promise::rejected(runtime, std::move(error));
96
91
  } else {
97
92
  std::string typeName = TypeInfo::getFriendlyTypename<TResult>(true);
98
93
  throw std::runtime_error("Promise<" + typeName + "> has invalid state!");
@@ -104,8 +99,7 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
104
99
  return false;
105
100
  }
106
101
  jsi::Object object = value.getObject(runtime);
107
- jsi::Function promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
108
- return object.instanceOf(runtime, promiseCtor);
102
+ return CommonGlobals::Promise::isInstanceOf(runtime, object);
109
103
  }
110
104
  };
111
105
 
@@ -14,6 +14,7 @@ struct JSIConverter;
14
14
 
15
15
  #include "AnyMap.hpp"
16
16
  #include "JSIHelpers.hpp"
17
+ #include "PropNameIDCache.hpp"
17
18
  #include <jsi/jsi.h>
18
19
  #include <unordered_map>
19
20
 
@@ -33,7 +34,7 @@ struct JSIConverter<std::unordered_map<std::string, ValueType>> final {
33
34
  map.reserve(length);
34
35
  for (size_t i = 0; i < length; ++i) {
35
36
  std::string key = propertyNames.getValueAtIndex(runtime, i).asString(runtime).utf8(runtime);
36
- jsi::Value value = object.getProperty(runtime, key.c_str());
37
+ jsi::Value value = object.getProperty(runtime, PropNameIDCache::get(runtime, key));
37
38
  map.emplace(key, JSIConverter<ValueType>::fromJSI(runtime, value));
38
39
  }
39
40
  return map;
@@ -42,7 +42,7 @@ static inline bool isPlainObject(jsi::Runtime& runtime, const jsi::Object& objec
42
42
  * Get an ID for the given Runtime.
43
43
  *
44
44
  * The ID usually consists of a Runtime description (e.g. "HermesRuntime"),
45
- * and it's Thread (e.g. "com.facebook.react.runtime.JavaScript")
45
+ * and its Thread's name (e.g. "com.facebook.react.runtime.JavaScript")
46
46
  */
47
47
  static inline std::string getRuntimeId(jsi::Runtime& runtime) {
48
48
  std::string threadName = ThreadUtils::getThreadName();
@@ -22,7 +22,9 @@ private:
22
22
 
23
23
  public:
24
24
  template <typename... Args>
25
- static void log([[maybe_unused]] LogLevel level, [[maybe_unused]] const char* NON_NULL tag, [[maybe_unused]] const char* NON_NULL format,
25
+ static void log([[maybe_unused]] LogLevel level, //
26
+ [[maybe_unused]] const char* NON_NULL tag, //
27
+ [[maybe_unused]] const char* NON_NULL format, //
26
28
  [[maybe_unused]] Args... args) {
27
29
  #ifdef NITRO_DEBUG
28
30
  // 1. Make sure args can be passed to sprintf(..)