Files
react-native/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp
T
Rubén Norte e04d1b47b6 Move feature flags for the event loop to ReactNativeFeatureFlags (#42434)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/42434

Changelog: [internal]

The flags for the event loop were set up using different mechanisms due to the limitations of the previous feature flags systems. Now we can centralize on the new system and use them consistently on Android and iOS.

Reviewed By: RSNara

Differential Revision: D52819137

fbshipit-source-id: e30a6f2e12b4a027a906502b80a70dd48bb657b6
2024-01-25 13:55:11 -08:00

149 lines
5.1 KiB
C++

/*
* 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 "HermesInstance.h"
#include <jsi/jsilib.h>
#include <jsinspector-modern/InspectorFlags.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#ifdef HERMES_ENABLE_DEBUGGER
#include <hermes/inspector-modern/chrome/Registration.h>
#include <hermes/inspector/RuntimeAdapter.h>
#include <jsi/decorator.h>
#endif
using namespace facebook::hermes;
using namespace facebook::jsi;
namespace facebook::react {
#ifdef HERMES_ENABLE_DEBUGGER
// Wrapper that strongly retains the HermesRuntime for on device debugging.
//
// HermesInstanceRuntimeAdapter needs to strongly retain the HermesRuntime. Why:
// - facebook::hermes::inspector_modern::chrome::Connection::Impl owns the
// Adapter
// - facebook::hermes::inspector_modern::chrome::Connection::Impl also owns
// jsi:: objects
// - jsi:: objects need to be deleted before the Runtime.
//
// If Adapter doesn't share ownership over jsi::Runtime, the runtime can be
// deleted before Connection::Impl cleans up all its jsi:: Objects. This will
// lead to a runtime crash.
class HermesInstanceRuntimeAdapter : public inspector_modern::RuntimeAdapter {
public:
HermesInstanceRuntimeAdapter(
std::shared_ptr<HermesRuntime> hermesRuntime,
std::shared_ptr<MessageQueueThread> msgQueueThread)
: hermesRuntime_(std::move(hermesRuntime)),
messageQueueThread_(std::move(msgQueueThread)) {}
virtual ~HermesInstanceRuntimeAdapter() = default;
HermesRuntime& getRuntime() override {
return *hermesRuntime_;
}
void tickleJs() override {
std::weak_ptr<HermesRuntime> weakRuntime(hermesRuntime_);
messageQueueThread_->runOnQueue([weakRuntime]() {
auto runtime = weakRuntime.lock();
if (!runtime) {
return;
}
jsi::Function func =
runtime->global().getPropertyAsFunction(*runtime, "__tickleJs");
func.call(*runtime);
});
}
private:
std::shared_ptr<HermesRuntime> hermesRuntime_;
std::shared_ptr<MessageQueueThread> messageQueueThread_;
};
class DecoratedRuntime : public jsi::RuntimeDecorator<jsi::Runtime> {
public:
DecoratedRuntime(
std::unique_ptr<HermesRuntime> runtime,
std::shared_ptr<MessageQueueThread> msgQueueThread)
: RuntimeDecorator<jsi::Runtime>(*runtime), runtime_(std::move(runtime)) {
auto adapter = std::make_unique<HermesInstanceRuntimeAdapter>(
runtime_, msgQueueThread);
debugToken_ = inspector_modern::chrome::enableDebugging(
std::move(adapter), "Hermes Bridgeless React Native");
}
~DecoratedRuntime() {
inspector_modern::chrome::disableDebugging(debugToken_);
}
private:
std::shared_ptr<HermesRuntime> runtime_;
inspector_modern::chrome::DebugSessionToken debugToken_;
};
#endif
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 {
assert(msgQueueThread != nullptr);
int64_t vmExperimentFlags = reactNativeConfig
? reactNativeConfig->getInt64("ios_hermes:vm_experiment_flags")
: 0;
int64_t heapSizeConfig = reactNativeConfig
? reactNativeConfig->getInt64("ios_hermes:rn_heap_size_mb")
: 0;
// Default to 3GB if MobileConfigs is not available
auto heapSizeMB = heapSizeConfig > 0
? static_cast<::hermes::vm::gcheapsize_t>(heapSizeConfig)
: 3072;
::hermes::vm::RuntimeConfig::Builder runtimeConfigBuilder =
::hermes::vm::RuntimeConfig::Builder()
.withGCConfig(::hermes::vm::GCConfig::Builder()
.withMaxHeapSize(heapSizeMB << 20)
.withName("RNBridgeless")
// For the next two arguments: avoid GC before TTI
// by initializing the runtime to allocate directly
// in the old generation, but revert to normal
// operation when we reach the (first) TTI point.
.withAllocInYoung(false)
.withRevertToYGAtTTI(true)
.build())
.withES6Proxy(false)
.withEnableSampleProfiling(true)
.withMicrotaskQueue(ReactNativeFeatureFlags::enableMicrotasks())
.withVMExperimentFlags(vmExperimentFlags);
if (cm) {
runtimeConfigBuilder.withCrashMgr(cm);
}
std::unique_ptr<HermesRuntime> hermesRuntime =
hermes::makeHermesRuntime(runtimeConfigBuilder.build());
#ifdef HERMES_ENABLE_DEBUGGER
auto& inspectorFlags = jsinspector_modern::InspectorFlags::getInstance();
if (!inspectorFlags.getEnableModernCDPRegistry()) {
std::unique_ptr<DecoratedRuntime> decoratedRuntime =
std::make_unique<DecoratedRuntime>(
std::move(hermesRuntime), msgQueueThread);
return std::make_unique<JSIRuntimeHolder>(std::move(decoratedRuntime));
}
#endif
return std::make_unique<JSIRuntimeHolder>(std::move(hermesRuntime));
}
} // namespace facebook::react