Create JSRuntime interface (#41549)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/41549

Changelog: [Internal]

Introduces the `JSRuntime` interface as a straightforward wrapper around `jsi::Runtime`, and refactors `ReactInstance` to hold a `JSRuntime` instead of a `jsi::Runtime`. In an upcoming diff we'll add debugging-related methods to `JSRuntime` and specialise their implementations for Hermes.

NOTE: `JSRuntime` is somewhat analogous to `JSExecutor` in the Bridge architecture.

Reviewed By: huntie

Differential Revision: D51447934

fbshipit-source-id: cfcab9ae0dd3d2a34c064abaac6cb676f435e216
This commit is contained in:
Moti Zilberman
2023-11-24 12:04:59 -08:00
committed by Facebook GitHub Bot
parent 0363485069
commit c464b215e5
16 changed files with 71 additions and 25 deletions
@@ -28,7 +28,7 @@ void JHermesInstance::registerNatives() {
});
}
std::unique_ptr<jsi::Runtime> JHermesInstance::createJSRuntime(
std::unique_ptr<JSRuntime> JHermesInstance::createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
return HermesInstance::createJSRuntime(
reactNativeConfig_, nullptr, msgQueueThread);
@@ -35,7 +35,7 @@ class JHermesInstance
JHermesInstance(std::shared_ptr<const ReactNativeConfig> reactNativeConfig)
: reactNativeConfig_(reactNativeConfig){};
std::unique_ptr<jsi::Runtime> createJSRuntime(
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept;
~JHermesInstance() {}
@@ -30,9 +30,9 @@ class JSCInstance : public jni::HybridClass<JSCInstance, JJSRuntimeFactory> {
});
}
std::unique_ptr<jsi::Runtime> createJSRuntime(
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
return jsc::makeJSCRuntime();
return std::make_unique<JSIRuntimeHolder>(jsc::makeJSCRuntime());
}
private:
@@ -0,0 +1,19 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "JSRuntimeFactory.h"
namespace facebook::react {
jsi::Runtime& JSIRuntimeHolder::getRuntime() noexcept {
return *runtime_;
}
JSIRuntimeHolder::JSIRuntimeHolder(std::unique_ptr<jsi::Runtime> runtime)
: runtime_(std::move(runtime)) {
assert(runtime_ != nullptr);
}
} // namespace facebook::react
@@ -13,15 +13,38 @@
namespace facebook::react {
/**
* An interface that represents an instance of a JS VM
*/
class JSRuntime {
public:
virtual jsi::Runtime& getRuntime() noexcept = 0;
virtual ~JSRuntime() = default;
};
/**
* Interface for a class that creates instances of a JS VM
*/
class JSRuntimeFactory {
public:
virtual std::unique_ptr<jsi::Runtime> createJSRuntime(
virtual std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept = 0;
virtual ~JSRuntimeFactory() = default;
};
/**
* Utility class for creating a JSRuntime from a uniquely owned jsi::Runtime.
*/
class JSIRuntimeHolder : public JSRuntime {
public:
jsi::Runtime& getRuntime() noexcept override;
explicit JSIRuntimeHolder(std::unique_ptr<jsi::Runtime> runtime);
private:
std::unique_ptr<jsi::Runtime> runtime_;
};
} // namespace facebook::react
@@ -48,6 +48,7 @@ Pod::Spec.new do |s|
s.dependency "React-jsitracing"
s.dependency "React-utils"
s.dependency "React-jsi"
s.dependency "React-RuntimeCore"
if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1"
s.dependency "hermes-engine"
@@ -26,7 +26,7 @@
namespace facebook::react {
ReactInstance::ReactInstance(
std::unique_ptr<jsi::Runtime> runtime,
std::unique_ptr<JSRuntime> runtime,
std::shared_ptr<MessageQueueThread> jsMessageQueueThread,
std::shared_ptr<TimerManager> timerManager,
JsErrorHandler::JsErrorHandlingFunc jsErrorHandlingFunc,
@@ -36,7 +36,7 @@ ReactInstance::ReactInstance(
timerManager_(std::move(timerManager)),
jsErrorHandler_(jsErrorHandlingFunc),
hasFatalJsError_(std::make_shared<bool>(false)) {
auto runtimeExecutor = [weakRuntime = std::weak_ptr<jsi::Runtime>(runtime_),
auto runtimeExecutor = [weakRuntime = std::weak_ptr<JSRuntime>(runtime_),
weakTimerManager =
std::weak_ptr<TimerManager>(timerManager_),
weakJsMessageQueueThread =
@@ -63,20 +63,20 @@ ReactInstance::ReactInstance(
sharedJsMessageQueueThread->runOnQueue(
[weakRuntime, weakTimerManager, callback = std::move(callback)]() {
if (auto strongRuntime = weakRuntime.lock()) {
jsi::Runtime& jsiRuntime = strongRuntime->getRuntime();
SystraceSection s("ReactInstance::_runtimeExecutor[Callback]");
try {
callback(*strongRuntime);
callback(jsiRuntime);
// If we have first-class support for microtasks,
// they would've been called as part of the previous callback.
if (!CoreFeatures::enableMicrotasks) {
if (auto strongTimerManager = weakTimerManager.lock()) {
strongTimerManager->callReactNativeMicrotasks(
*strongRuntime);
strongTimerManager->callReactNativeMicrotasks(jsiRuntime);
}
}
} catch (jsi::JSError& originalError) {
handleJSError(*strongRuntime, originalError, true);
handleJSError(jsiRuntime, originalError, true);
}
}
});
@@ -14,6 +14,7 @@
#include <jsireact/JSIExecutor.h>
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <react/runtime/BufferedRuntimeExecutor.h>
#include <react/runtime/JSRuntimeFactory.h>
#include <react/runtime/TimerManager.h>
namespace facebook::react {
@@ -29,7 +30,7 @@ class ReactInstance final {
using BindingsInstallFunc = std::function<void(jsi::Runtime& runtime)>;
ReactInstance(
std::unique_ptr<jsi::Runtime> runtime,
std::unique_ptr<JSRuntime> runtime,
std::shared_ptr<MessageQueueThread> jsMessageQueueThread,
std::shared_ptr<TimerManager> timerManager,
JsErrorHandler::JsErrorHandlingFunc JsErrorHandlingFunc,
@@ -64,7 +65,7 @@ class ReactInstance final {
void handleMemoryPressureJs(int pressureLevel);
private:
std::shared_ptr<jsi::Runtime> runtime_;
std::shared_ptr<JSRuntime> runtime_;
std::shared_ptr<MessageQueueThread> jsMessageQueueThread_;
std::shared_ptr<BufferedRuntimeExecutor> bufferedRuntimeExecutor_;
std::shared_ptr<TimerManager> timerManager_;
@@ -22,6 +22,7 @@ target_link_libraries(bridgelesshermes
hermes_inspector_modern
jsi
hermes_executor_common
bridgeless
)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
@@ -89,7 +89,7 @@ class DecoratedRuntime : public jsi::RuntimeDecorator<jsi::Runtime> {
#endif
std::unique_ptr<jsi::Runtime> HermesInstance::createJSRuntime(
std::unique_ptr<JSRuntime> HermesInstance::createJSRuntime(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
std::shared_ptr<::hermes::vm::CrashManager> cm,
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
@@ -144,10 +144,10 @@ std::unique_ptr<jsi::Runtime> HermesInstance::createJSRuntime(
std::unique_ptr<DecoratedRuntime> decoratedRuntime =
std::make_unique<DecoratedRuntime>(
std::move(hermesRuntime), msgQueueThread);
return decoratedRuntime;
return std::make_unique<JSIRuntimeHolder>(std::move(decoratedRuntime));
#endif
return hermesRuntime;
return std::make_unique<JSIRuntimeHolder>(std::move(hermesRuntime));
}
} // namespace facebook::react
@@ -11,12 +11,13 @@
#include <hermes/hermes.h>
#include <jsi/jsi.h>
#include <react/config/ReactNativeConfig.h>
#include <react/runtime/JSRuntimeFactory.h>
namespace facebook::react {
class HermesInstance {
public:
static std::unique_ptr<jsi::Runtime> createJSRuntime(
static std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
std::shared_ptr<::hermes::vm::CrashManager> cm,
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept;
@@ -26,7 +26,7 @@ class RCTHermesInstance : public JSRuntimeFactory {
std::shared_ptr<const ReactNativeConfig> reactNativeConfig,
CrashManagerProvider crashManagerProvider);
std::unique_ptr<jsi::Runtime> createJSRuntime(
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept override;
~RCTHermesInstance(){};
@@ -20,7 +20,7 @@ RCTHermesInstance::RCTHermesInstance(
{
}
std::unique_ptr<jsi::Runtime> RCTHermesInstance::createJSRuntime(
std::unique_ptr<JSRuntime> RCTHermesInstance::createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept
{
return _hermesInstance->createJSRuntime(
@@ -16,7 +16,7 @@ class RCTJscInstance : public JSRuntimeFactory {
public:
RCTJscInstance();
std::unique_ptr<jsi::Runtime> createJSRuntime(
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept override;
~RCTJscInstance(){};
@@ -13,10 +13,9 @@ namespace react {
RCTJscInstance::RCTJscInstance() {}
std::unique_ptr<jsi::Runtime> RCTJscInstance::createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept
std::unique_ptr<JSRuntime> RCTJscInstance::createJSRuntime(std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept
{
return jsc::makeJSCRuntime();
return std::make_unique<JSIRuntimeHolder>(jsc::makeJSCRuntime());
}
} // namespace react
@@ -116,8 +116,9 @@ class ReactInstanceTest : public ::testing::Test {
ReactInstanceTest() {}
void SetUp() override {
auto runtime = hermes::makeHermesRuntime();
runtime_ = runtime.get();
auto runtime =
std::make_unique<JSIRuntimeHolder>(hermes::makeHermesRuntime());
runtime_ = &runtime->getRuntime();
messageQueueThread_ = std::make_shared<MockMessageQueueThread>();
auto mockRegistry = std::make_unique<MockTimerRegistry>();
mockRegistry_ = mockRegistry.get();