Skip to content

Commit

Permalink
fix: Destroy ArrayBuffer cache on Runtime reload (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
boorad authored Dec 13, 2024
1 parent 4c3a611 commit 5a53dd6
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 27 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Build Android
on:
push:
branches:
- main
- 0.x
paths:
- '.github/workflows/build-android.yml'
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Build iOS
on:
push:
branches:
- main
- 0.x
paths:
- '.github/workflows/build-ios.yml'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-lockfiles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: 'Update Lockfiles (bun.lockb + Podfile.lock)'
on:
push:
branches:
- main
- 0.x
paths:
- ".github/workflows/update-lockfiles.yml"
pull_request:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/validate-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Validate Android
on:
push:
branches:
- main
- 0.x
paths:
- '.github/workflows/validate-android.yml'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: 'Validate C++'
on:
push:
branches:
- main
- 0.x
paths:
- '.github/workflows/validate-cpp.yml'
Expand Down Expand Up @@ -35,4 +34,5 @@ jobs:
,-build/namespaces\
,-whitespace/comments\
,-build/include_order\
,-whitespace/parens\
"
1 change: 0 additions & 1 deletion .github/workflows/validate-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Validate JS
on:
push:
branches:
- main
- 0.x
paths:
- '.github/workflows/validate-js.yml'
Expand Down
9 changes: 9 additions & 0 deletions android/src/main/cpp/cpp-adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
#include <fbjni/fbjni.h>
#include <jni.h>
#include <jsi/jsi.h>
#include <memory>

#include "MGLQuickCryptoHostObject.h"
#include "JSIUtils/MGLTypedArray.h"

using namespace facebook;

Expand All @@ -28,6 +30,13 @@ class CryptoCppAdapter : public jni::HybridClass<CryptoCppAdapter> {
auto object = jsi::Object::createFromHostObject(runtime, hostObject);
runtime.global().setProperty(runtime, "__QuickCryptoProxy",
std::move(object));
// Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets destroyed and the cache gets invalidated.
auto propNameIdCache = std::make_shared<InvalidateCacheOnDestroy>(runtime);
runtime.global().setProperty(
runtime,
"rnqcArrayBufferPropNameIdCache",
jsi::Object::createFromHostObject(runtime, propNameIdCache)
);
}

void nativeInstall(
Expand Down
55 changes: 38 additions & 17 deletions cpp/JSIUtils/MGLTypedArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include <algorithm>
#include <memory>
#include <utility>
#include <vector>
#include <string>
#include <unordered_map>

Expand Down Expand Up @@ -40,33 +42,37 @@ enum class Prop {
class PropNameIDCache {
public:
const jsi::PropNameID &get(jsi::Runtime &runtime, Prop prop) {
if (!this->props[prop]) {
this->props[prop] =
std::make_unique<jsi::PropNameID>(createProp(runtime, prop));
auto key = reinterpret_cast<uintptr_t>(&runtime);
if (this->props.find(key) == this->props.end()) {
this->props[key] = std::unordered_map<Prop, std::unique_ptr<jsi::PropNameID>>();
}
return *(this->props[prop]);
if (!this->props[key][prop]) {
this->props[key][prop] = std::make_unique<jsi::PropNameID>(createProp(runtime, prop));
}
return *(this->props[key][prop]);
}

const jsi::PropNameID &getConstructorNameProp(jsi::Runtime &runtime,
MGLTypedArrayKind kind);
const jsi::PropNameID &getConstructorNameProp(jsi::Runtime &runtime, MGLTypedArrayKind kind);

void invalidate() {
/** This call (and attempts to use props.clear()) crash 💥 when the
* JSI runtime has already been destroyed. So we are commenting it out
* and waiting for Nitro and 1.0 to fix this the proper way.
*/
//props.erase(props.begin(), props.end());
void invalidate(uintptr_t key) {
if (props.find(key) != props.end()) {
props[key].clear();
}
}

private:
std::unordered_map<Prop, std::unique_ptr<jsi::PropNameID>> props;
std::unordered_map<uintptr_t, std::unordered_map<Prop, std::unique_ptr<jsi::PropNameID>>> props;

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

PropNameIDCache propNameIDCache;

void invalidateJsiPropNameIDCache() { propNameIDCache.invalidate(); }
InvalidateCacheOnDestroy::InvalidateCacheOnDestroy(jsi::Runtime &runtime) {
key = reinterpret_cast<uintptr_t>(&runtime);
}
InvalidateCacheOnDestroy::~InvalidateCacheOnDestroy() {
propNameIDCache.invalidate(key);
}

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

Expand All @@ -75,8 +81,9 @@ MGLTypedArrayBase::MGLTypedArrayBase(jsi::Runtime &runtime, size_t size,
: MGLTypedArrayBase(
runtime,
runtime.global()
.getProperty(runtime, propNameIDCache.getConstructorNameProp(
runtime, kind))
.getProperty(
runtime,
propNameIDCache.getConstructorNameProp(runtime, kind))
.asObject(runtime)
.asFunction(runtime)
.callAsConstructor(runtime, {static_cast<double>(size)})
Expand Down Expand Up @@ -236,6 +243,20 @@ void MGLTypedArray<T>::update(jsi::Runtime &runtime,
reinterpret_cast<ContentType<T> *>(rawData));
}

template <MGLTypedArrayKind T>
void MGLTypedArray<T>::updateUnsafe(jsi::Runtime &runtime, ContentType<T> *data, size_t length) {
if (length != size(runtime)) {
throw jsi::JSError(runtime, "TypedArray can only be updated with an array of the same size");
}
uint8_t *rawData = getBuffer(runtime).data(runtime) + byteOffset(runtime);
memcpy(rawData, data, length);
}

template <MGLTypedArrayKind T>
uint8_t* MGLTypedArray<T>::data(jsi::Runtime &runtime) {
return getBuffer(runtime).data(runtime) + byteOffset(runtime);
}

const jsi::PropNameID &PropNameIDCache::getConstructorNameProp(
jsi::Runtime &runtime, MGLTypedArrayKind kind) {
switch (kind) {
Expand Down
21 changes: 20 additions & 1 deletion cpp/JSIUtils/MGLTypedArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,24 @@ struct typedArrayTypeMap<MGLTypedArrayKind::Float64Array> {
typedef double type;
};

void invalidateJsiPropNameIDCache();
// Instance of this class will invalidate PropNameIDCache when destructor is called.
// Attach this object to global in specific jsi::Runtime to make sure lifecycle of
// the cache object is connected to the lifecycle of the js runtime
class InvalidateCacheOnDestroy : public jsi::HostObject {
public:
explicit InvalidateCacheOnDestroy(jsi::Runtime &runtime);
virtual ~InvalidateCacheOnDestroy();
virtual jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) {
return jsi::Value::null();
}
virtual void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) {}
virtual std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) {
return {};
}

private:
uintptr_t key;
};

class MGLTypedArrayBase : public jsi::Object {
public:
Expand Down Expand Up @@ -126,6 +143,8 @@ class MGLTypedArray : public MGLTypedArrayBase {

std::vector<ContentType<T>> toVector(jsi::Runtime &runtime);
void update(jsi::Runtime &runtime, const std::vector<ContentType<T>> &data);
void updateUnsafe(jsi::Runtime &runtime, ContentType<T> *data, size_t length);
uint8_t* data(jsi::Runtime &runtime);
};

template <MGLTypedArrayKind T>
Expand Down
2 changes: 1 addition & 1 deletion cpp/MGLQuickCryptoHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class JSI_EXPORT MGLQuickCryptoHostObject : public MGLSmartHostObject {
std::shared_ptr<react::CallInvoker> jsCallInvoker,
std::shared_ptr<DispatchQueue::dispatch_queue> workerQueue);

virtual ~MGLQuickCryptoHostObject() { invalidateJsiPropNameIDCache(); }
virtual ~MGLQuickCryptoHostObject() {}
};

} // namespace margelo
Expand Down
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ PODS:
- react-native-quick-base64 (2.1.2):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- react-native-quick-crypto (0.7.6):
- react-native-quick-crypto (0.7.9):
- OpenSSL-Universal
- RCT-Folly (= 2021.07.22.00)
- React
Expand Down Expand Up @@ -628,7 +628,7 @@ SPEC CHECKSUMS:
React-logger: 8edc785c47c8686c7962199a307015e2ce9a0e4f
react-native-fast-encoder: 6f59e9b08e2bc5a8bf1f36e1630cdcfd66dd18af
react-native-quick-base64: 61228d753294ae643294a75fece8e0e80b7558a6
react-native-quick-crypto: 03d888b32a7d58adfe93926ee226c1adc5519c6e
react-native-quick-crypto: d8c6ba8c31de79da1ebbbdb79cf16d1ee980b407
react-native-safe-area-context: ab8f4a3d8180913bd78ae75dd599c94cce3d5e9a
React-NativeModulesApple: b6868ee904013a7923128892ee4a032498a1024a
React-perflogger: 31ea61077185eb1428baf60c0db6e2886f141a5a
Expand Down
10 changes: 10 additions & 0 deletions ios/QuickCryptoModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#import <jsi/jsi.h>

#import "../cpp/MGLQuickCryptoHostObject.h"
#import "../cpp/JSIUtils/MGLTypedArray.h"

@implementation QuickCryptoModule

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

// Adds the PropNameIDCache object to the Runtime. If the Runtime gets
// destroyed, the Object gets destroyed and the cache gets invalidated.
auto propNameIdCache = std::make_shared<InvalidateCacheOnDestroy>(runtime);
runtime.global().setProperty(
runtime,
"rnqcArrayBufferPropNameIdCache",
jsi::Object::createFromHostObject(runtime, propNameIdCache)
);

NSLog(@"Successfully installed JSI bindings for react-native-quick-crypto!");
return @true;
}
Expand Down
Binary file modified test/test_suite_results.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5a53dd6

Please sign in to comment.