Skip to content

Commit 5a53dd6

Browse files
authored
fix: Destroy ArrayBuffer cache on Runtime reload (#558)
1 parent 4c3a611 commit 5a53dd6

13 files changed

+82
-27
lines changed

.github/workflows/build-android.yml

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Build Android
33
on:
44
push:
55
branches:
6-
- main
76
- 0.x
87
paths:
98
- '.github/workflows/build-android.yml'

.github/workflows/build-ios.yml

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Build iOS
33
on:
44
push:
55
branches:
6-
- main
76
- 0.x
87
paths:
98
- '.github/workflows/build-ios.yml'

.github/workflows/update-lockfiles.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: 'Update Lockfiles (bun.lockb + Podfile.lock)'
33
on:
44
push:
55
branches:
6-
- main
6+
- 0.x
77
paths:
88
- ".github/workflows/update-lockfiles.yml"
99
pull_request:

.github/workflows/validate-android.yml

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Validate Android
33
on:
44
push:
55
branches:
6-
- main
76
- 0.x
87
paths:
98
- '.github/workflows/validate-android.yml'

.github/workflows/validate-cpp.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: 'Validate C++'
33
on:
44
push:
55
branches:
6-
- main
76
- 0.x
87
paths:
98
- '.github/workflows/validate-cpp.yml'
@@ -35,4 +34,5 @@ jobs:
3534
,-build/namespaces\
3635
,-whitespace/comments\
3736
,-build/include_order\
37+
,-whitespace/parens\
3838
"

.github/workflows/validate-js.yml

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Validate JS
33
on:
44
push:
55
branches:
6-
- main
76
- 0.x
87
paths:
98
- '.github/workflows/validate-js.yml'

android/src/main/cpp/cpp-adapter.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
#include <fbjni/fbjni.h>
33
#include <jni.h>
44
#include <jsi/jsi.h>
5+
#include <memory>
56

67
#include "MGLQuickCryptoHostObject.h"
8+
#include "JSIUtils/MGLTypedArray.h"
79

810
using namespace facebook;
911

@@ -28,6 +30,13 @@ class CryptoCppAdapter : public jni::HybridClass<CryptoCppAdapter> {
2830
auto object = jsi::Object::createFromHostObject(runtime, hostObject);
2931
runtime.global().setProperty(runtime, "__QuickCryptoProxy",
3032
std::move(object));
33+
// Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets destroyed and the cache gets invalidated.
34+
auto propNameIdCache = std::make_shared<InvalidateCacheOnDestroy>(runtime);
35+
runtime.global().setProperty(
36+
runtime,
37+
"rnqcArrayBufferPropNameIdCache",
38+
jsi::Object::createFromHostObject(runtime, propNameIdCache)
39+
);
3140
}
3241

3342
void nativeInstall(

cpp/JSIUtils/MGLTypedArray.cpp

+38-17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include <algorithm>
1212
#include <memory>
13+
#include <utility>
14+
#include <vector>
1315
#include <string>
1416
#include <unordered_map>
1517

@@ -40,33 +42,37 @@ enum class Prop {
4042
class PropNameIDCache {
4143
public:
4244
const jsi::PropNameID &get(jsi::Runtime &runtime, Prop prop) {
43-
if (!this->props[prop]) {
44-
this->props[prop] =
45-
std::make_unique<jsi::PropNameID>(createProp(runtime, prop));
45+
auto key = reinterpret_cast<uintptr_t>(&runtime);
46+
if (this->props.find(key) == this->props.end()) {
47+
this->props[key] = std::unordered_map<Prop, std::unique_ptr<jsi::PropNameID>>();
4648
}
47-
return *(this->props[prop]);
49+
if (!this->props[key][prop]) {
50+
this->props[key][prop] = std::make_unique<jsi::PropNameID>(createProp(runtime, prop));
51+
}
52+
return *(this->props[key][prop]);
4853
}
4954

50-
const jsi::PropNameID &getConstructorNameProp(jsi::Runtime &runtime,
51-
MGLTypedArrayKind kind);
55+
const jsi::PropNameID &getConstructorNameProp(jsi::Runtime &runtime, MGLTypedArrayKind kind);
5256

53-
void invalidate() {
54-
/** This call (and attempts to use props.clear()) crash 💥 when the
55-
* JSI runtime has already been destroyed. So we are commenting it out
56-
* and waiting for Nitro and 1.0 to fix this the proper way.
57-
*/
58-
//props.erase(props.begin(), props.end());
57+
void invalidate(uintptr_t key) {
58+
if (props.find(key) != props.end()) {
59+
props[key].clear();
60+
}
5961
}
60-
6162
private:
62-
std::unordered_map<Prop, std::unique_ptr<jsi::PropNameID>> props;
63+
std::unordered_map<uintptr_t, std::unordered_map<Prop, std::unique_ptr<jsi::PropNameID>>> props;
6364

6465
jsi::PropNameID createProp(jsi::Runtime &runtime, Prop prop);
6566
};
6667

6768
PropNameIDCache propNameIDCache;
6869

69-
void invalidateJsiPropNameIDCache() { propNameIDCache.invalidate(); }
70+
InvalidateCacheOnDestroy::InvalidateCacheOnDestroy(jsi::Runtime &runtime) {
71+
key = reinterpret_cast<uintptr_t>(&runtime);
72+
}
73+
InvalidateCacheOnDestroy::~InvalidateCacheOnDestroy() {
74+
propNameIDCache.invalidate(key);
75+
}
7076

7177
MGLTypedArrayKind getTypedArrayKindForName(const std::string &name);
7278

@@ -75,8 +81,9 @@ MGLTypedArrayBase::MGLTypedArrayBase(jsi::Runtime &runtime, size_t size,
7581
: MGLTypedArrayBase(
7682
runtime,
7783
runtime.global()
78-
.getProperty(runtime, propNameIDCache.getConstructorNameProp(
79-
runtime, kind))
84+
.getProperty(
85+
runtime,
86+
propNameIDCache.getConstructorNameProp(runtime, kind))
8087
.asObject(runtime)
8188
.asFunction(runtime)
8289
.callAsConstructor(runtime, {static_cast<double>(size)})
@@ -236,6 +243,20 @@ void MGLTypedArray<T>::update(jsi::Runtime &runtime,
236243
reinterpret_cast<ContentType<T> *>(rawData));
237244
}
238245

246+
template <MGLTypedArrayKind T>
247+
void MGLTypedArray<T>::updateUnsafe(jsi::Runtime &runtime, ContentType<T> *data, size_t length) {
248+
if (length != size(runtime)) {
249+
throw jsi::JSError(runtime, "TypedArray can only be updated with an array of the same size");
250+
}
251+
uint8_t *rawData = getBuffer(runtime).data(runtime) + byteOffset(runtime);
252+
memcpy(rawData, data, length);
253+
}
254+
255+
template <MGLTypedArrayKind T>
256+
uint8_t* MGLTypedArray<T>::data(jsi::Runtime &runtime) {
257+
return getBuffer(runtime).data(runtime) + byteOffset(runtime);
258+
}
259+
239260
const jsi::PropNameID &PropNameIDCache::getConstructorNameProp(
240261
jsi::Runtime &runtime, MGLTypedArrayKind kind) {
241262
switch (kind) {

cpp/JSIUtils/MGLTypedArray.h

+20-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,24 @@ struct typedArrayTypeMap<MGLTypedArrayKind::Float64Array> {
6969
typedef double type;
7070
};
7171

72-
void invalidateJsiPropNameIDCache();
72+
// Instance of this class will invalidate PropNameIDCache when destructor is called.
73+
// Attach this object to global in specific jsi::Runtime to make sure lifecycle of
74+
// the cache object is connected to the lifecycle of the js runtime
75+
class InvalidateCacheOnDestroy : public jsi::HostObject {
76+
public:
77+
explicit InvalidateCacheOnDestroy(jsi::Runtime &runtime);
78+
virtual ~InvalidateCacheOnDestroy();
79+
virtual jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) {
80+
return jsi::Value::null();
81+
}
82+
virtual void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) {}
83+
virtual std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) {
84+
return {};
85+
}
86+
87+
private:
88+
uintptr_t key;
89+
};
7390

7491
class MGLTypedArrayBase : public jsi::Object {
7592
public:
@@ -126,6 +143,8 @@ class MGLTypedArray : public MGLTypedArrayBase {
126143

127144
std::vector<ContentType<T>> toVector(jsi::Runtime &runtime);
128145
void update(jsi::Runtime &runtime, const std::vector<ContentType<T>> &data);
146+
void updateUnsafe(jsi::Runtime &runtime, ContentType<T> *data, size_t length);
147+
uint8_t* data(jsi::Runtime &runtime);
129148
};
130149

131150
template <MGLTypedArrayKind T>

cpp/MGLQuickCryptoHostObject.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class JSI_EXPORT MGLQuickCryptoHostObject : public MGLSmartHostObject {
2222
std::shared_ptr<react::CallInvoker> jsCallInvoker,
2323
std::shared_ptr<DispatchQueue::dispatch_queue> workerQueue);
2424

25-
virtual ~MGLQuickCryptoHostObject() { invalidateJsiPropNameIDCache(); }
25+
virtual ~MGLQuickCryptoHostObject() {}
2626
};
2727

2828
} // namespace margelo

example/ios/Podfile.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ PODS:
323323
- react-native-quick-base64 (2.1.2):
324324
- RCT-Folly (= 2021.07.22.00)
325325
- React-Core
326-
- react-native-quick-crypto (0.7.6):
326+
- react-native-quick-crypto (0.7.9):
327327
- OpenSSL-Universal
328328
- RCT-Folly (= 2021.07.22.00)
329329
- React
@@ -628,7 +628,7 @@ SPEC CHECKSUMS:
628628
React-logger: 8edc785c47c8686c7962199a307015e2ce9a0e4f
629629
react-native-fast-encoder: 6f59e9b08e2bc5a8bf1f36e1630cdcfd66dd18af
630630
react-native-quick-base64: 61228d753294ae643294a75fece8e0e80b7558a6
631-
react-native-quick-crypto: 03d888b32a7d58adfe93926ee226c1adc5519c6e
631+
react-native-quick-crypto: d8c6ba8c31de79da1ebbbdb79cf16d1ee980b407
632632
react-native-safe-area-context: ab8f4a3d8180913bd78ae75dd599c94cce3d5e9a
633633
React-NativeModulesApple: b6868ee904013a7923128892ee4a032498a1024a
634634
React-perflogger: 31ea61077185eb1428baf60c0db6e2886f141a5a

ios/QuickCryptoModule.mm

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#import <jsi/jsi.h>
77

88
#import "../cpp/MGLQuickCryptoHostObject.h"
9+
#import "../cpp/JSIUtils/MGLTypedArray.h"
910

1011
@implementation QuickCryptoModule
1112

@@ -40,6 +41,15 @@ - (void)setBridge:(RCTBridge *)bridge {
4041
auto object = jsi::Object::createFromHostObject(runtime, hostObject);
4142
runtime.global().setProperty(runtime, "__QuickCryptoProxy", std::move(object));
4243

44+
// Adds the PropNameIDCache object to the Runtime. If the Runtime gets
45+
// destroyed, the Object gets destroyed and the cache gets invalidated.
46+
auto propNameIdCache = std::make_shared<InvalidateCacheOnDestroy>(runtime);
47+
runtime.global().setProperty(
48+
runtime,
49+
"rnqcArrayBufferPropNameIdCache",
50+
jsi::Object::createFromHostObject(runtime, propNameIdCache)
51+
);
52+
4353
NSLog(@"Successfully installed JSI bindings for react-native-quick-crypto!");
4454
return @true;
4555
}

test/test_suite_results.png

4.77 KB
Loading

0 commit comments

Comments
 (0)