-
Notifications
You must be signed in to change notification settings - Fork 717
Description
Problem
In Nitro, array buffers are supported types for native modules.
Imagine the following native nitro module:
const seedArrayBuffer = myNitroModule.createRandomSeed()
const keyString = myNitroModule.getEncryptionKey(seedArrayBuffer)On the native side of getEncryptionKey, we can safely access the ArrayBuffer's data without any problems just fine because it is synchronous and we are running on the JS thread:
auto arrayBuffer = args[0].getObject(runtime).getArrayBuffer(runtime);
void* data = arrayBuffer.data(runtime);..but as soon as we make this function asynchronous:
const seedArrayBuffer = myNitroModule.createRandomSeed()
const keyString = await myNitroModule.getEncryptionKey(seedArrayBuffer)We can no longer safely access the ArrayBuffer's data because we are running on a separate Thread.
Nitro will convert the
jsi::ArrayBufferto a custom Nitro type that basically tells you to not access it on a different Thread and will throw if you try to do so. So the user is always forced to make a copy of the data before switching to a different Thread.
I think it'd be a cool API to get access to the underlying std::shared_ptr<jsi::MutableBuffer> if it has one (not every ArrayBuffer is created with one):
auto arrayBuffer = args[0].getObject(runtime).getArrayBuffer(runtime);
auto mutableBuffer = arrayBuffer.getMutableBuffer(runtime);
std::thread([=]() {
void* data = mutableBuffer.data();
});Note: This could cause data race issues if not used correctly. I think it's up to the user to guard against that (either via Mutexes, or just praying at night that their APIs will not be misused)
Solution
jsi::ArrayBuffer::isMutableBuffer(..)jsi::ArrayBuffer::getMutableBuffer(..)jsi::ArrayBuffer::asMutableBuffer(..)(?)
Additional Context
In Nitro, I currently solved it like this:
- The
nitro::ArrayBufferbase class - The
nitro::NativeArrayBufferclass, which allows you to access data from any Thread and is owning - The
nitro::JSArrayBufferclass, which only allows you to access data on the JS Thread
If I receive an ArrayBuffer from JS, it is currently always a nitro::JSArrayBuffer. I would love to look into it and unwrap the jsi::MutableBuffer from it so I can optionally also pass the user a nitro::NativeArrayBuffer instead though.