Skip to content

Commit

Permalink
Restructure RuntimeDecorator (#1860)
Browse files Browse the repository at this point in the history
Part 2 of 3

* Restructures `RuntimeDecorator` to use the term "Worklet" instead of "UI", and "React Runtime" instead of "Host Runtime".
* Move `isHostRuntime` and `isUIRuntime` from `NativeReanimatedModule` to `RuntimeDecorator` (and make static)
  • Loading branch information
mrousavy authored Mar 23, 2021
1 parent fba7236 commit 3155b2b
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 113 deletions.
24 changes: 7 additions & 17 deletions Common/cpp/NativeModules/NativeReanimatedModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,13 @@ NativeReanimatedModule::NativeReanimatedModule(std::shared_ptr<CallInvoker> jsIn
frameCallbacks.push_back(callback);
maybeRequestRender();
};

RuntimeDecorator::addNativeObjects(*runtime,
platformDepMethodsHolder.updaterFunction,
requestAnimationFrame,
platformDepMethodsHolder.scrollToFunction,
platformDepMethodsHolder.measuringFunction,
platformDepMethodsHolder.getCurrentTime);
}

bool NativeReanimatedModule::isUIRuntime(jsi::Runtime &rt)
{
return runtime.get() == &rt;
}

bool NativeReanimatedModule::isHostRuntime(jsi::Runtime &rt)
{
return !isUIRuntime(rt);

RuntimeDecorator::decorateUIRuntime(*runtime,
platformDepMethodsHolder.updaterFunction,
requestAnimationFrame,
platformDepMethodsHolder.scrollToFunction,
platformDepMethodsHolder.measuringFunction,
platformDepMethodsHolder.getCurrentTime);
}

void NativeReanimatedModule::installCoreFunctions(jsi::Runtime &rt, const jsi::Value &valueSetter)
Expand Down
6 changes: 3 additions & 3 deletions Common/cpp/SharedItems/MutableValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void MutableValue::setValue(jsi::Runtime &rt, const jsi::Value &newValue) {
}
};

if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
notifyListeners();
} else {
module->scheduler->scheduleOnUI([notifyListeners] {
Expand All @@ -33,7 +33,7 @@ jsi::Value MutableValue::getValue(jsi::Runtime &rt) {
void MutableValue::set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi::Value &newValue) {
auto propName = name.utf8(rt);

if (module->isHostRuntime(rt)) {
if (RuntimeDecorator::isReactRuntime(rt)) {
if (propName == "value") {
auto shareable = ShareableValue::adapt(rt, newValue, module);
module->scheduler->scheduleOnUI([this, shareable] {
Expand Down Expand Up @@ -72,7 +72,7 @@ jsi::Value MutableValue::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
return getValue(rt);
}

if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
// _value and _animation should be accessed from UI only
if (propName == "_value") {
return getValue(rt);
Expand Down
7 changes: 4 additions & 3 deletions Common/cpp/SharedItems/RemoteObject.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "RemoteObject.h"
#include "SharedParent.h"
#include "NativeReanimatedModule.h"
#include "RuntimeDecorator.h"
#include <jsi/jsi.h>

using namespace facebook;

namespace reanimated {

void RemoteObject::maybeInitializeOnUIRuntime(jsi::Runtime &rt) {
void RemoteObject::maybeInitializeOnWorkletRuntime(jsi::Runtime &rt) {
if (initializer.get() != nullptr) {
backing = getWeakRef(rt);
*backing.lock() = initializer->shallowClone(rt);
Expand All @@ -16,14 +17,14 @@ void RemoteObject::maybeInitializeOnUIRuntime(jsi::Runtime &rt) {
}

jsi::Value RemoteObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
return backing.lock()->getObject(rt).getProperty(rt, name);
}
return jsi::Value::undefined();
}

void RemoteObject::set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi::Value &value) {
if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
backing.lock()->getObject(rt).setProperty(rt, name, value);
}
// TODO: we should throw if trying to update remote from host runtime
Expand Down
12 changes: 6 additions & 6 deletions Common/cpp/SharedItems/ShareableValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void freeze(jsi::Runtime &rt, jsi::Object &obj) {
void ShareableValue::adaptCache(jsi::Runtime &rt, const jsi::Value &value) {
// when adapting from host object we can assign cached value immediately such that we avoid
// running `toJSValue` in the future when given object is accessed
if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
if (remoteValue.expired()) {
remoteValue = getWeakRef(rt);
}
Expand All @@ -51,7 +51,7 @@ void ShareableValue::adaptCache(jsi::Runtime &rt, const jsi::Value &value) {
}

void ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, ValueType objectType) {
bool isRNRuntime = !(module->isUIRuntime(rt));
bool isRNRuntime = RuntimeDecorator::isReactRuntime(rt);
if (value.isObject()) {
jsi::Object object = value.asObject(rt);
jsi::Value hiddenValue = object.getProperty(rt, HIDDEN_HOST_OBJECT_PROP);
Expand Down Expand Up @@ -177,7 +177,7 @@ std::shared_ptr<ShareableValue> ShareableValue::adapt(jsi::Runtime &rt, const js

jsi::Value ShareableValue::getValue(jsi::Runtime &rt) {
// TODO: maybe we can cache toJSValue results on a per-runtime basis, need to avoid ref loops
if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
if (remoteValue.expired()) {
auto ref = getWeakRef(rt);
remoteValue = ref;
Expand Down Expand Up @@ -239,8 +239,8 @@ jsi::Value ShareableValue::toJSValue(jsi::Runtime &rt) {
}
case ValueType::RemoteObjectType: {
auto& remoteObject = ValueWrapper::asRemoteObject(valueContainer);
if (module->isUIRuntime(rt)) {
remoteObject->maybeInitializeOnUIRuntime(rt);
if (RuntimeDecorator::isWorkletRuntime(rt)) {
remoteObject->maybeInitializeOnWorkletRuntime(rt);
}
return createHost(rt, remoteObject);
}
Expand Down Expand Up @@ -328,7 +328,7 @@ jsi::Value ShareableValue::toJSValue(jsi::Runtime &rt) {
case ValueType::WorkletFunctionType: {
auto module = this->module;
auto& frozenObject = ValueWrapper::asFrozenObject(this->valueContainer);
if (module->isUIRuntime(rt)) {
if (RuntimeDecorator::isWorkletRuntime(rt)) {
// when running on UI thread we prep a function

auto jsThis = std::make_shared<jsi::Object>(frozenObject->shallowClone(*module->runtime));
Expand Down
138 changes: 76 additions & 62 deletions Common/cpp/Tools/RuntimeDecorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,34 @@

namespace reanimated {

void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt,
UpdaterFunction updater,
RequestFrameFunction requestFrame,
ScrollToFunction scrollTo,
MeasuringFunction measure,
TimeProviderFunction getCurrentTime) {
void RuntimeDecorator::decorateRuntime(jsi::Runtime &rt, std::string label) {
// This property will be used to find out if a runtime is a custom worklet runtime (e.g. UI, VisionCamera frame processor, ...)
rt.global().setProperty(rt, "_WORKLET", jsi::Value(true));
// This property will be used for debugging
rt.global().setProperty(rt, "_LABEL", jsi::String::createFromAscii(rt, label));

jsi::Object dummyGlobal(rt);
auto dummyFunction = [requestFrame](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
return jsi::Value::undefined();
auto dummyFunction = [](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
return jsi::Value::undefined();
};
jsi::Function __reanimatedWorkletInit = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "__reanimatedWorkletInit"), 1, dummyFunction);

dummyGlobal.setProperty(rt, "__reanimatedWorkletInit", __reanimatedWorkletInit);
rt.global().setProperty(rt, "global", dummyGlobal);

rt.global().setProperty(rt, "jsThis", jsi::Value::undefined());

auto callback = [](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
const jsi::Value *value = &args[0];
if (value->isString()) {
Logger::log(value->getString(rt).utf8(rt).c_str());
Expand All @@ -46,17 +44,36 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt,
Logger::log("unsupported value type");
}
return jsi::Value::undefined();
};
};
jsi::Value log = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_log"), 1, callback);
rt.global().setProperty(rt, "_log", log);

rt.global().setProperty(rt, "_log", log);

auto setGlobalConsole = [](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
rt.global().setProperty(rt, "console", args[0]);
return jsi::Value::undefined();
};
rt.global().setProperty(rt, "_setGlobalConsole", jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_setGlobalConsole"), 1, setGlobalConsole));
}

void RuntimeDecorator::decorateUIRuntime(jsi::Runtime &rt,
UpdaterFunction updater,
RequestFrameFunction requestFrame,
ScrollToFunction scrollTo,
MeasuringFunction measure,
TimeProviderFunction getCurrentTime) {
RuntimeDecorator::decorateRuntime(rt, "UI");

auto clb = [updater](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
const auto viewTag = args[0].asNumber();
const jsi::Value* viewName = &args[1];
const auto params = args[2].asObject(rt);
Expand All @@ -65,14 +82,14 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt,
};
jsi::Value updateProps = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_updateProps"), 2, clb);
rt.global().setProperty(rt, "_updateProps", updateProps);


auto clb2 = [requestFrame](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
auto fun = std::make_shared<jsi::Function>(args[0].asObject(rt).asFunction(rt));
requestFrame([&rt, fun](double timestampMs) {
fun->call(rt, jsi::Value(timestampMs));
Expand All @@ -83,11 +100,11 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt,
rt.global().setProperty(rt, "requestAnimationFrame", requestAnimationFrame);

auto clb3 = [scrollTo](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
int viewTag = (int)args[0].asNumber();
double x = args[1].asNumber();
double y = args[2].asNumber();
Expand All @@ -99,11 +116,11 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt,
rt.global().setProperty(rt, "_scrollTo", scrollToFunction);

auto clb4 = [measure](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
int viewTag = (int)args[0].asNumber();
auto result = measure(viewTag);
jsi::Object resultObject(rt);
Expand All @@ -115,31 +132,28 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt,
jsi::Value measureFunction = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_measure"), 1, clb4);
rt.global().setProperty(rt, "_measure", measureFunction);

auto clb5 = [](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
rt.global().setProperty(rt, "console", args[0]);
return jsi::Value::undefined();
};
jsi::Value setGlobalConsole = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_setGlobalConsole"), 1, clb5);
rt.global().setProperty(rt, "_setGlobalConsole", setGlobalConsole);

auto clb6 = [getCurrentTime](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
return getCurrentTime();
};
jsi::Value timeFun = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_getCurrentTime"), 0, clb6);
rt.global().setProperty(rt, "_getCurrentTime", timeFun);

rt.global().setProperty(rt, "_frameTimestamp", jsi::Value::undefined());
rt.global().setProperty(rt, "_eventTimestamp", jsi::Value::undefined());
}

bool RuntimeDecorator::isWorkletRuntime(jsi::Runtime& rt) {
auto isUi = rt.global().getProperty(rt, "_WORKLET");
return isUi.isBool() && isUi.getBool();
}

bool RuntimeDecorator::isReactRuntime(jsi::Runtime& rt) {
return !isWorkletRuntime(rt);
}

}
21 changes: 9 additions & 12 deletions Common/cpp/headers/NativeModules/NativeReanimatedModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,36 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec
{
friend ShareableValue;
friend MutableValue;

public:
NativeReanimatedModule(std::shared_ptr<CallInvoker> jsInvoker,
std::shared_ptr<Scheduler> scheduler,
std::unique_ptr<jsi::Runtime> rt,
std::shared_ptr<ErrorHandler> errorHandler,
std::function<jsi::Value(jsi::Runtime &, const int, const jsi::String &)> propObtainer,
PlatformDepMethodsHolder platformDepMethodsHolder);

virtual ~NativeReanimatedModule();

void installCoreFunctions(jsi::Runtime &rt, const jsi::Value &valueSetter) override;

jsi::Value makeShareable(jsi::Runtime &rt, const jsi::Value &value) override;
jsi::Value makeMutable(jsi::Runtime &rt, const jsi::Value &value) override;
jsi::Value makeRemote(jsi::Runtime &rt, const jsi::Value &value) override;

jsi::Value startMapper(jsi::Runtime &rt, const jsi::Value &worklet, const jsi::Value &inputs, const jsi::Value &outputs) override;
void stopMapper(jsi::Runtime &rt, const jsi::Value &mapperId) override;

jsi::Value registerEventHandler(jsi::Runtime &rt, const jsi::Value &eventHash, const jsi::Value &worklet) override;
void unregisterEventHandler(jsi::Runtime &rt, const jsi::Value &registrationId) override;

jsi::Value getViewProp(jsi::Runtime &rt, const jsi::Value &viewTag, const jsi::Value &propName, const jsi::Value &callback) override;

void onRender(double timestampMs);
void onEvent(std::string eventName, std::string eventAsString);
bool isAnyHandlerWaitingForEvent(std::string eventName);

void maybeRequestRender();

bool isUIRuntime(jsi::Runtime &rt);
bool isHostRuntime(jsi::Runtime &rt);
public:
std::unique_ptr<jsi::Runtime> runtime;
private:
Expand Down
Loading

0 comments on commit 3155b2b

Please sign in to comment.