Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce executeOnUIRuntimeSync and use it to replace Sync Data Holder #4300

Merged
merged 14 commits into from
Jan 17, 2024
Merged
45 changes: 22 additions & 23 deletions Common/cpp/NativeModules/NativeReanimatedModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ NativeReanimatedModule::NativeReanimatedModule(
rnRuntime,
jsQueue,
jsScheduler_,
"Reanimated UI runtime")),
"Reanimated UI runtime",
WorkletRuntimeType::WithLocking)),
eventHandlerRegistry_(std::make_unique<EventHandlerRegistry>()),
requestRender_(platformDepMethodsHolder.requestRender),
onRenderCallback_([this](const double timestampMs) {
Expand Down Expand Up @@ -165,12 +166,31 @@ void NativeReanimatedModule::scheduleOnUI(
});
}

jsi::Value NativeReanimatedModule::executeOnUIRuntimeSync(
jsi::Runtime &rt,
const jsi::Value &worklet) {
auto shareableWorklet = extractShareableOrThrow<ShareableWorklet>(
rt,
worklet,
"[Reanimated] Only worklets can be executed synchronously on UI runtime.");
auto lock = uiWorkletRuntime_->lock();
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
auto result = uiWorkletRuntime_->runGuarded(shareableWorklet);
auto shareableResult = extractShareableOrThrow(uiRuntime, result);
lock.unlock();
return shareableResult->getJSValue(rt);
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
}

jsi::Value NativeReanimatedModule::createWorkletRuntime(
jsi::Runtime &rt,
const jsi::Value &name,
const jsi::Value &initializer) {
auto workletRuntime = std::make_shared<WorkletRuntime>(
rt, jsQueue_, jsScheduler_, name.asString(rt).utf8(rt));
rt,
jsQueue_,
jsScheduler_,
name.asString(rt).utf8(rt),
WorkletRuntimeType::WithoutLocking);
workletRuntime->installValueUnpacker(valueUnpackerCode_);
auto initializerShareable = extractShareableOrThrow<ShareableWorklet>(
rt, initializer, "[Reanimated] Initializer must be a worklet.");
Expand All @@ -186,27 +206,6 @@ jsi::Value NativeReanimatedModule::scheduleOnRuntime(
return jsi::Value::undefined();
}

jsi::Value NativeReanimatedModule::makeSynchronizedDataHolder(
jsi::Runtime &rt,
const jsi::Value &initialShareable) {
auto dataHolder =
std::make_shared<ShareableSynchronizedDataHolder>(rt, initialShareable);
return dataHolder->getJSValue(rt);
}

void NativeReanimatedModule::updateDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef,
const jsi::Value &newData) {
reanimated::updateDataSynchronously(rt, synchronizedDataHolderRef, newData);
}

jsi::Value NativeReanimatedModule::getDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef) {
return reanimated::getDataSynchronously(rt, synchronizedDataHolderRef);
}

jsi::Value NativeReanimatedModule::makeShareableClone(
jsi::Runtime &rt,
const jsi::Value &value,
Expand Down
13 changes: 2 additions & 11 deletions Common/cpp/NativeModules/NativeReanimatedModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,9 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec {
const jsi::Value &value,
const jsi::Value &shouldRetainRemote) override;

jsi::Value makeSynchronizedDataHolder(
jsi::Runtime &rt,
const jsi::Value &initialShareable) override;
jsi::Value getDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef) override;
void updateDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef,
const jsi::Value &newData);

void scheduleOnUI(jsi::Runtime &rt, const jsi::Value &worklet) override;
jsi::Value executeOnUIRuntimeSync(jsi::Runtime &rt, const jsi::Value &worklet)
override;

jsi::Value createWorkletRuntime(
jsi::Runtime &rt,
Expand Down
32 changes: 9 additions & 23 deletions Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,25 @@ static jsi::Value SPEC_PREFIX(makeShareableClone)(
->makeShareableClone(rt, std::move(args[0]), std::move(args[1]));
}

// Sync methods
// scheduler

static jsi::Value SPEC_PREFIX(makeSynchronizedDataHolder)(
static jsi::Value SPEC_PREFIX(scheduleOnUI)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->makeSynchronizedDataHolder(rt, std::move(args[0]));
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->scheduleOnUI(rt, std::move(args[0]));
return jsi::Value::undefined();
}

static jsi::Value SPEC_PREFIX(getDataSynchronously)(
static jsi::Value SPEC_PREFIX(executeOnUIRuntimeSync)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
return static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->getDataSynchronously(rt, std::move(args[0]));
}

// scheduler

static jsi::Value SPEC_PREFIX(scheduleOnUI)(
jsi::Runtime &rt,
TurboModule &turboModule,
const jsi::Value *args,
size_t) {
static_cast<NativeReanimatedModuleSpec *>(&turboModule)
->scheduleOnUI(rt, std::move(args[0]));
return jsi::Value::undefined();
->executeOnUIRuntimeSync(rt, std::move(args[0]));
}

static jsi::Value SPEC_PREFIX(createWorkletRuntime)(
Expand Down Expand Up @@ -204,12 +193,9 @@ NativeReanimatedModuleSpec::NativeReanimatedModuleSpec(
methodMap_["makeShareableClone"] =
MethodMetadata{2, SPEC_PREFIX(makeShareableClone)};

methodMap_["makeSynchronizedDataHolder"] =
MethodMetadata{1, SPEC_PREFIX(makeSynchronizedDataHolder)};
methodMap_["getDataSynchronously"] =
MethodMetadata{1, SPEC_PREFIX(getDataSynchronously)};

methodMap_["scheduleOnUI"] = MethodMetadata{1, SPEC_PREFIX(scheduleOnUI)};
methodMap_["executeOnUIRuntimeSync"] =
MethodMetadata{1, SPEC_PREFIX(executeOnUIRuntimeSync)};
methodMap_["createWorkletRuntime"] =
MethodMetadata{2, SPEC_PREFIX(createWorkletRuntime)};
methodMap_["scheduleOnRuntime"] =
Expand Down
11 changes: 3 additions & 8 deletions Common/cpp/NativeModules/NativeReanimatedModuleSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,11 @@ class JSI_EXPORT NativeReanimatedModuleSpec : public TurboModule {
const jsi::Value &value,
const jsi::Value &shouldRetainRemote) = 0;

// Synchronized data objects
virtual jsi::Value makeSynchronizedDataHolder(
jsi::Runtime &rt,
const jsi::Value &initialShareable) = 0;
virtual jsi::Value getDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef) = 0;

// Scheduling
virtual void scheduleOnUI(jsi::Runtime &rt, const jsi::Value &worklet) = 0;
virtual jsi::Value executeOnUIRuntimeSync(
jsi::Runtime &rt,
const jsi::Value &worklet) = 0;

// Worklet runtime
virtual jsi::Value createWorkletRuntime(
Expand Down
58 changes: 56 additions & 2 deletions Common/cpp/ReanimatedRuntime/WorkletRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,73 @@
#include "WorkletRuntimeCollector.h"
#include "WorkletRuntimeDecorator.h"

#include <jsi/decorator.h>

namespace reanimated {

struct AroundLock {
std::recursive_mutex *mutex;
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
void before() {
mutex->lock();
}
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
void after() {
mutex->unlock();
}
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
};

class LockableRuntime : public jsi::WithRuntimeDecorator<AroundLock> {
private:
AroundLock aroundLock_;
std::shared_ptr<jsi::Runtime> runtime_;
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved

public:
explicit LockableRuntime(
std::shared_ptr<jsi::Runtime> &&runtime,
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
std::recursive_mutex *runtimeMutex)
: jsi::WithRuntimeDecorator<AroundLock>(*runtime, aroundLock_),
runtime_(std::move(runtime)) {
aroundLock_.mutex = runtimeMutex;
}
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
};

static std::shared_ptr<jsi::Runtime> makeRuntime(
jsi::Runtime &runtime,
const std::shared_ptr<MessageQueueThread> &jsQueue,
const std::string &name,
bool supportLocking,
std::recursive_mutex *runtimeMutex) {
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
if (supportLocking) {
return std::make_shared<LockableRuntime>(
ReanimatedRuntime::make(runtime, jsQueue, name), runtimeMutex);
} else {
return ReanimatedRuntime::make(runtime, jsQueue, name);
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
}
}

WorkletRuntime::WorkletRuntime(
jsi::Runtime &rnRuntime,
const std::shared_ptr<MessageQueueThread> &jsQueue,
const std::shared_ptr<JSScheduler> &jsScheduler,
const std::string &name)
: runtime_(ReanimatedRuntime::make(rnRuntime, jsQueue, name)), name_(name) {
const std::string &name,
WorkletRuntimeType type)
: runtime_(makeRuntime(
rnRuntime,
jsQueue,
name,
WorkletRuntimeType::WithLocking,
&runtimeMutex_)),
name_(name),
supportsLocking_(type == WorkletRuntimeType::WithLocking) {
jsi::Runtime &rt = *runtime_;
WorkletRuntimeCollector::install(rt);
WorkletRuntimeDecorator::decorate(rt, name, jsScheduler);
}

std::unique_lock<std::recursive_mutex> WorkletRuntime::lock() {
assert(supportsLocking_ && "Runtime doesn't support locking");
return std::unique_lock<std::recursive_mutex>(runtimeMutex_);
}

void WorkletRuntime::installValueUnpacker(
const std::string &valueUnpackerCode) {
jsi::Runtime &rt = *runtime_;
Expand Down
13 changes: 10 additions & 3 deletions Common/cpp/ReanimatedRuntime/WorkletRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,32 @@ using namespace react;

namespace reanimated {

enum WorkletRuntimeType { WithLocking, WithoutLocking };
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved

class WorkletRuntime : public jsi::HostObject,
public std::enable_shared_from_this<WorkletRuntime> {
public:
explicit WorkletRuntime(
jsi::Runtime &rnRuntime,
const std::shared_ptr<MessageQueueThread> &jsQueue,
const std::shared_ptr<JSScheduler> &jsScheduler,
const std::string &name);
const std::string &name,
WorkletRuntimeType type);

void installValueUnpacker(const std::string &valueUnpackerCode);

jsi::Runtime &getJSIRuntime() const {
return *runtime_;
}

std::unique_lock<std::recursive_mutex> lock();
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved

template <typename... Args>
inline void runGuarded(
inline jsi::Value runGuarded(
const std::shared_ptr<ShareableWorklet> &shareableWorklet,
Args &&...args) const {
jsi::Runtime &rt = *runtime_;
runOnRuntimeGuarded(
return runOnRuntimeGuarded(
rt, shareableWorklet->getJSValue(rt), std::forward<Args>(args)...);
}

Expand All @@ -63,6 +68,8 @@ class WorkletRuntime : public jsi::HostObject,
const std::shared_ptr<jsi::Runtime> runtime_;
const std::string name_;
std::shared_ptr<AsyncQueue> queue_;
std::recursive_mutex runtimeMutex_;
bool supportsLocking_;
piaskowyk marked this conversation as resolved.
Show resolved Hide resolved
};

// This function needs to be non-inline to avoid problems with dynamic_cast on
Expand Down
17 changes: 0 additions & 17 deletions Common/cpp/ReanimatedRuntime/WorkletRuntimeDecorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,6 @@ void WorkletRuntimeDecorator::decorate(
rt, workletRuntimeValue, shareableWorkletValue);
});

jsi_utils::installJsiFunction(
rt,
"_updateDataSynchronously",
[](jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef,
const jsi::Value &newData) {
return reanimated::updateDataSynchronously(
rt, synchronizedDataHolderRef, newData);
});

jsi_utils::installJsiFunction(
rt,
"_getDataSynchronously",
[](jsi::Runtime &rt, const jsi::Value &synchronizedDataHolderRef) {
return reanimated::getDataSynchronously(rt, synchronizedDataHolderRef);
});

jsi::Object performance(rt);
performance.setProperty(
rt,
Expand Down
53 changes: 0 additions & 53 deletions Common/cpp/SharedItems/Shareables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,23 +110,6 @@ jsi::Value makeShareableClone(
return ShareableJSRef::newHostObject(rt, shareable);
}

void updateDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef,
const jsi::Value &newData) {
auto dataHolder = extractShareableOrThrow<ShareableSynchronizedDataHolder>(
rt, synchronizedDataHolderRef);
dataHolder->set(rt, newData);
}

jsi::Value getDataSynchronously(
jsi::Runtime &rt,
const jsi::Value &synchronizedDataHolderRef) {
auto dataHolder = extractShareableOrThrow<ShareableSynchronizedDataHolder>(
rt, synchronizedDataHolderRef);
return dataHolder->get(rt);
}

std::shared_ptr<Shareable> extractShareableOrThrow(
jsi::Runtime &rt,
const jsi::Value &maybeShareableValue,
Expand Down Expand Up @@ -273,42 +256,6 @@ jsi::Value ShareableHandle::toJSValue(jsi::Runtime &rt) {
return jsi::Value(rt, *remoteValue_);
}

jsi::Value ShareableSynchronizedDataHolder::get(jsi::Runtime &rt) {
std::unique_lock<std::mutex> read_lock(dataAccessMutex_);
if (&rt == primaryRuntime_) {
if (primaryValue_ != nullptr) {
return jsi::Value(rt, *primaryValue_);
}
auto value = data_->getJSValue(rt);
primaryValue_ = std::make_unique<jsi::Value>(rt, value);
return value;
}
if (secondaryValue_ == nullptr) {
auto value = data_->getJSValue(rt);
secondaryValue_ = std::make_unique<jsi::Value>(rt, value);
secondaryRuntime_ = &rt;
return value;
}
if (&rt == secondaryRuntime_) {
return jsi::Value(rt, *secondaryValue_);
}
throw std::runtime_error(
"[Reanimated] ShareableSynchronizedDataHolder supports only RN or UI runtime");
}

void ShareableSynchronizedDataHolder::set(
jsi::Runtime &rt,
const jsi::Value &data) {
std::unique_lock<std::mutex> write_lock(dataAccessMutex_);
data_ = extractShareableOrThrow(rt, data);
primaryValue_.reset();
secondaryValue_.reset();
}

jsi::Value ShareableSynchronizedDataHolder::toJSValue(jsi::Runtime &rt) {
return ShareableJSRef::newHostObject(rt, shared_from_this());
}

jsi::Value ShareableString::toJSValue(jsi::Runtime &rt) {
return jsi::String::createFromUtf8(rt, data_);
}
Expand Down
Loading
Loading