diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index 0c02af18..bf8b3bd9 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -3,7 +3,6 @@ name: Build Android on: push: branches: - - main - 0.x paths: - '.github/workflows/build-android.yml' diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml index 22ef4674..086778e2 100644 --- a/.github/workflows/build-ios.yml +++ b/.github/workflows/build-ios.yml @@ -3,7 +3,6 @@ name: Build iOS on: push: branches: - - main - 0.x paths: - '.github/workflows/build-ios.yml' diff --git a/.github/workflows/update-lockfiles.yml b/.github/workflows/update-lockfiles.yml index a7d3e468..06e9ae66 100644 --- a/.github/workflows/update-lockfiles.yml +++ b/.github/workflows/update-lockfiles.yml @@ -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: diff --git a/.github/workflows/validate-android.yml b/.github/workflows/validate-android.yml index 9358ad68..c98656f3 100644 --- a/.github/workflows/validate-android.yml +++ b/.github/workflows/validate-android.yml @@ -3,7 +3,6 @@ name: Validate Android on: push: branches: - - main - 0.x paths: - '.github/workflows/validate-android.yml' diff --git a/.github/workflows/validate-cpp.yml b/.github/workflows/validate-cpp.yml index 4af2a98a..0d8e4828 100644 --- a/.github/workflows/validate-cpp.yml +++ b/.github/workflows/validate-cpp.yml @@ -3,7 +3,6 @@ name: 'Validate C++' on: push: branches: - - main - 0.x paths: - '.github/workflows/validate-cpp.yml' @@ -35,4 +34,5 @@ jobs: ,-build/namespaces\ ,-whitespace/comments\ ,-build/include_order\ + ,-whitespace/parens\ " diff --git a/.github/workflows/validate-js.yml b/.github/workflows/validate-js.yml index 32a0a514..91560984 100644 --- a/.github/workflows/validate-js.yml +++ b/.github/workflows/validate-js.yml @@ -3,7 +3,6 @@ name: Validate JS on: push: branches: - - main - 0.x paths: - '.github/workflows/validate-js.yml' diff --git a/android/src/main/cpp/cpp-adapter.cpp b/android/src/main/cpp/cpp-adapter.cpp index fabdf45b..bf6fb2cc 100644 --- a/android/src/main/cpp/cpp-adapter.cpp +++ b/android/src/main/cpp/cpp-adapter.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include "MGLQuickCryptoHostObject.h" +#include "JSIUtils/MGLTypedArray.h" using namespace facebook; @@ -28,6 +30,13 @@ class CryptoCppAdapter : public jni::HybridClass { 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(runtime); + runtime.global().setProperty( + runtime, + "rnqcArrayBufferPropNameIdCache", + jsi::Object::createFromHostObject(runtime, propNameIdCache) + ); } void nativeInstall( diff --git a/cpp/JSIUtils/MGLTypedArray.cpp b/cpp/JSIUtils/MGLTypedArray.cpp index 116f8269..6c38da7d 100644 --- a/cpp/JSIUtils/MGLTypedArray.cpp +++ b/cpp/JSIUtils/MGLTypedArray.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -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(createProp(runtime, prop)); + auto key = reinterpret_cast(&runtime); + if (this->props.find(key) == this->props.end()) { + this->props[key] = std::unordered_map>(); } - return *(this->props[prop]); + if (!this->props[key][prop]) { + this->props[key][prop] = std::make_unique(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> props; + std::unordered_map>> props; jsi::PropNameID createProp(jsi::Runtime &runtime, Prop prop); }; PropNameIDCache propNameIDCache; -void invalidateJsiPropNameIDCache() { propNameIDCache.invalidate(); } +InvalidateCacheOnDestroy::InvalidateCacheOnDestroy(jsi::Runtime &runtime) { + key = reinterpret_cast(&runtime); +} +InvalidateCacheOnDestroy::~InvalidateCacheOnDestroy() { + propNameIDCache.invalidate(key); +} MGLTypedArrayKind getTypedArrayKindForName(const std::string &name); @@ -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(size)}) @@ -236,6 +243,20 @@ void MGLTypedArray::update(jsi::Runtime &runtime, reinterpret_cast *>(rawData)); } +template +void MGLTypedArray::updateUnsafe(jsi::Runtime &runtime, ContentType *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 +uint8_t* MGLTypedArray::data(jsi::Runtime &runtime) { + return getBuffer(runtime).data(runtime) + byteOffset(runtime); +} + const jsi::PropNameID &PropNameIDCache::getConstructorNameProp( jsi::Runtime &runtime, MGLTypedArrayKind kind) { switch (kind) { diff --git a/cpp/JSIUtils/MGLTypedArray.h b/cpp/JSIUtils/MGLTypedArray.h index d6266855..086c5783 100644 --- a/cpp/JSIUtils/MGLTypedArray.h +++ b/cpp/JSIUtils/MGLTypedArray.h @@ -69,7 +69,24 @@ struct typedArrayTypeMap { 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 getPropertyNames(jsi::Runtime &rt) { + return {}; + } + + private: + uintptr_t key; +}; class MGLTypedArrayBase : public jsi::Object { public: @@ -126,6 +143,8 @@ class MGLTypedArray : public MGLTypedArrayBase { std::vector> toVector(jsi::Runtime &runtime); void update(jsi::Runtime &runtime, const std::vector> &data); + void updateUnsafe(jsi::Runtime &runtime, ContentType *data, size_t length); + uint8_t* data(jsi::Runtime &runtime); }; template diff --git a/cpp/MGLQuickCryptoHostObject.h b/cpp/MGLQuickCryptoHostObject.h index 50efcf2f..0280791d 100644 --- a/cpp/MGLQuickCryptoHostObject.h +++ b/cpp/MGLQuickCryptoHostObject.h @@ -22,7 +22,7 @@ class JSI_EXPORT MGLQuickCryptoHostObject : public MGLSmartHostObject { std::shared_ptr jsCallInvoker, std::shared_ptr workerQueue); - virtual ~MGLQuickCryptoHostObject() { invalidateJsiPropNameIDCache(); } + virtual ~MGLQuickCryptoHostObject() {} }; } // namespace margelo diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 5ea2755f..1d204a15 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -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 @@ -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 diff --git a/ios/QuickCryptoModule.mm b/ios/QuickCryptoModule.mm index c69e7a16..cbe54819 100644 --- a/ios/QuickCryptoModule.mm +++ b/ios/QuickCryptoModule.mm @@ -6,6 +6,7 @@ #import #import "../cpp/MGLQuickCryptoHostObject.h" +#import "../cpp/JSIUtils/MGLTypedArray.h" @implementation QuickCryptoModule @@ -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(runtime); + runtime.global().setProperty( + runtime, + "rnqcArrayBufferPropNameIdCache", + jsi::Object::createFromHostObject(runtime, propNameIdCache) + ); + NSLog(@"Successfully installed JSI bindings for react-native-quick-crypto!"); return @true; } diff --git a/test/test_suite_results.png b/test/test_suite_results.png index c3ed7f82..20874d80 100644 Binary files a/test/test_suite_results.png and b/test/test_suite_results.png differ