Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 91 additions & 45 deletions packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,60 +309,106 @@ void ReactInstance::loadScript(
});
}

namespace {

/*
* Calls a method on a JS module that has been registered with
* `registerCallableModule`. Used to invoke a JS function from platform code.
* `registerCallableModule`, with the arguments that `addArgs` adds.
*/
void ReactInstance::callFunctionOnModule(
template <typename AddArgs>
void callCallableModuleMethod(
jsi::Runtime& runtime,
std::unordered_map<std::string, std::variant<jsi::Function, jsi::Object>>&
callableModules,
const std::string& moduleName,
const std::string& methodName,
folly::dynamic&& args) {
bufferedRuntimeExecutor_->execute([this,
moduleName = moduleName,
methodName = methodName,
args = std::move(args)](
jsi::Runtime& runtime) {
TraceSection s(
"ReactInstance::callFunctionOnModule",
"moduleName",
moduleName,
"methodName",
methodName);
auto it = callableModules_.find(moduleName);
if (it == callableModules_.end()) {
std::ostringstream knownModules;
int i = 0;
for (it = callableModules_.begin(); it != callableModules_.end();
it++, i++) {
const char* space = (i > 0 ? ", " : " ");
knownModules << space << it->first;
}
throw jsi::JSError(
runtime,
"Failed to call into JavaScript module method " + moduleName + "." +
methodName +
"(). Module has not been registered as callable. Registered callable JavaScript modules (n = " +
std::to_string(callableModules_.size()) +
"):" + knownModules.str() +
". Did you forget to call `registerCallableModule`?");
const AddArgs& addArgs) {
TraceSection s(
"ReactInstance::callFunctionOnModule",
"moduleName",
moduleName,
"methodName",
methodName);
auto it = callableModules.find(moduleName);
if (it == callableModules.end()) {
std::ostringstream knownModules;
int i = 0;
for (it = callableModules.begin(); it != callableModules.end(); it++, i++) {
const char* space = (i > 0 ? ", " : " ");
knownModules << space << it->first;
}
throw jsi::JSError(
runtime,
"Failed to call into JavaScript module method " + moduleName + "." +
methodName +
"(). Module has not been registered as callable. Registered callable JavaScript modules (n = " +
std::to_string(callableModules.size()) + "):" + knownModules.str() +
". Did you forget to call `registerCallableModule`?");
}

if (std::holds_alternative<jsi::Function>(it->second)) {
auto module =
std::get<jsi::Function>(it->second).call(runtime).asObject(runtime);
it->second = std::move(module);
}
if (std::holds_alternative<jsi::Function>(it->second)) {
auto module =
std::get<jsi::Function>(it->second).call(runtime).asObject(runtime);
it->second = std::move(module);
}

auto& module = std::get<jsi::Object>(it->second);
auto method = module.getPropertyAsFunction(runtime, methodName.c_str());
auto& module = std::get<jsi::Object>(it->second);
auto method = module.getPropertyAsFunction(runtime, methodName.c_str());

std::vector<jsi::Value> jsArgs;
for (auto& arg : args) {
jsArgs.push_back(jsi::valueFromDynamic(runtime, arg));
}
method.callWithThis(
runtime, module, (const jsi::Value*)jsArgs.data(), jsArgs.size());
});
std::vector<jsi::Value> jsArgs;
addArgs(jsArgs);
method.callWithThis(
runtime, module, (const jsi::Value*)jsArgs.data(), jsArgs.size());
}

} // namespace

/*
* Calls a method on a JS module that has been registered with
* `registerCallableModule`. Used to invoke a JS function from platform code.
*/
void ReactInstance::callFunctionOnModule(
const std::string& moduleName,
const std::string& methodName,
folly::dynamic&& args) {
bufferedRuntimeExecutor_->execute(
[this,
moduleName = moduleName,
methodName = methodName,
args = std::move(args)](jsi::Runtime& runtime) {
callCallableModuleMethod(
runtime,
callableModules_,
moduleName,
methodName,
[&](std::vector<jsi::Value>& jsArgs) {
for (auto& arg : args) {
jsArgs.push_back(jsi::valueFromDynamic(runtime, arg));
}
});
});
}

void ReactInstance::callFunctionOnModule(
const std::string& moduleName,
const std::string& methodName,
ArgFactory&& argFactory) {
bufferedRuntimeExecutor_->execute(
[this,
moduleName = moduleName,
methodName = methodName,
argFactory = std::move(argFactory)](jsi::Runtime& runtime) {
callCallableModuleMethod(
runtime,
callableModules_,
moduleName,
methodName,
[&](std::vector<jsi::Value>& jsArgs) {
if (argFactory) {
argFactory(runtime, jsArgs);
}
});
});
}

void ReactInstance::registerSegment(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace facebook::react {
class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate {
public:
using BindingsInstallFunc = std::function<void(jsi::Runtime &runtime)>;
using ArgFactory = std::function<void(jsi::Runtime &runtime, std::vector<jsi::Value> &args)>;

ReactInstance(
std::unique_ptr<JSRuntime> runtime,
Expand Down Expand Up @@ -71,6 +72,12 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate {

void callFunctionOnModule(const std::string &moduleName, const std::string &methodName, folly::dynamic &&args);

/**
* Like the overload above, but `argFactory` adds the arguments on the JS thread, so platform
* values can be converted to JS values directly.
*/
void callFunctionOnModule(const std::string &moduleName, const std::string &methodName, ArgFactory &&argFactory);

void handleMemoryPressureJs(int pressureLevel);

/**
Expand Down
Loading
Loading