diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index 01742cce7f07..7fb0a1184782 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -22,7 +22,7 @@ file(TO_CMAKE_PATH "${REACT_ANDROID_DIR}" REACT_ANDROID_DIR) file(TO_CMAKE_PATH "${REACT_BUILD_DIR}" REACT_BUILD_DIR) file(TO_CMAKE_PATH "${REACT_COMMON_DIR}" REACT_COMMON_DIR) -set(HERMES_V1_ENABLED OFF CACHE BOOL "Build with support for Hermes v1") +set(HERMES_V1_ENABLED ON CACHE BOOL "Build with support for Hermes v1") # If you have ccache installed, we're going to honor it. find_program(CCACHE_FOUND ccache) diff --git a/packages/react-native/ReactCommon/cmake-utils/react-native-flags.cmake b/packages/react-native/ReactCommon/cmake-utils/react-native-flags.cmake index b8a420af216d..160e9da55d8f 100644 --- a/packages/react-native/ReactCommon/cmake-utils/react-native-flags.cmake +++ b/packages/react-native/ReactCommon/cmake-utils/react-native-flags.cmake @@ -32,7 +32,5 @@ function(target_compile_reactnative_options target_name scope) if(ANDROID) target_compile_definitions(${target_name} ${scope} RN_SERIALIZABLE_STATE) endif() - if(HERMES_V1_ENABLED) - target_compile_definitions(${target_name} ${scope} HERMES_V1_ENABLED=1) - endif() + target_compile_definitions(${target_name} ${scope} HERMES_V1_ENABLED=1) endfunction() diff --git a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp index d83803fc4274..23ceb3f8f58f 100644 --- a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp +++ b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp @@ -17,11 +17,6 @@ #include -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) -#include -#include -#endif - using namespace facebook::hermes; using namespace facebook::jsi; @@ -29,43 +24,6 @@ namespace facebook::react { namespace { -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - -class HermesExecutorRuntimeAdapter - : public facebook::hermes::inspector_modern::RuntimeAdapter { - public: - HermesExecutorRuntimeAdapter( - std::shared_ptr runtime, - std::shared_ptr thread) - : runtime_(runtime), thread_(std::move(thread)) {} - - virtual ~HermesExecutorRuntimeAdapter() = default; - - HermesRuntime& getRuntime() override { - return *runtime_; - } - - void tickleJs() override { - thread_->runOnQueue( - [weakRuntime = std::weak_ptr(runtime_)]() { - auto runtime = weakRuntime.lock(); - if (!runtime) { - return; - } - jsi::Function func = - runtime->global().getPropertyAsFunction(*runtime, "__tickleJs"); - func.call(*runtime); - }); - } - - private: - std::shared_ptr runtime_; - - std::shared_ptr thread_; -}; - -#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - struct ReentrancyCheck { // This is effectively a very subtle and complex assert, so only // include it in builds which would include asserts. @@ -149,26 +107,13 @@ class DecoratedRuntime : public jsi::WithRuntimeDecorator { const std::string& debuggerName) : jsi::WithRuntimeDecorator(*runtime, reentrancyCheck_), runtime_(std::move(runtime)) { -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - enableDebugger_ = enableDebugger; - if (enableDebugger_) { - std::shared_ptr rt(runtime_, &hermesRuntime); - auto adapter = - std::make_unique(rt, jsQueue); - debugToken_ = facebook::hermes::inspector_modern::chrome::enableDebugging( - std::move(adapter), debuggerName); - } -#else + (void)hermesRuntime; (void)jsQueue; -#endif // HERMES_ENABLE_DEBUGGER + (void)enableDebugger; + (void)debuggerName; } ~DecoratedRuntime() { -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - if (enableDebugger_) { - facebook::hermes::inspector_modern::chrome::disableDebugging(debugToken_); - } -#endif // HERMES_ENABLE_DEBUGGER } private: @@ -181,10 +126,6 @@ class DecoratedRuntime : public jsi::WithRuntimeDecorator { std::shared_ptr runtime_; ReentrancyCheck reentrancyCheck_; -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - bool enableDebugger_; - facebook::hermes::inspector_modern::chrome::DebugSessionToken debugToken_; -#endif // HERMES_ENABLE_DEBUGGER }; } // namespace diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp deleted file mode 100644 index ad07660ae18c..000000000000 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 "ConnectionDemux.h" - -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - -#include -#include - -#include - -#include - -namespace facebook::hermes::inspector_modern::chrome { - -using ::facebook::react::jsinspector_modern::ILocalConnection; -using ::facebook::react::jsinspector_modern::IRemoteConnection; - -namespace { - -class LocalConnection : public ILocalConnection { - public: - LocalConnection( - std::shared_ptr conn, - std::shared_ptr> inspectedContexts); - ~LocalConnection() override; - - void sendMessage(std::string message) override; - void disconnect() override; - - private: - std::shared_ptr conn_; - std::shared_ptr> inspectedContexts_; -}; - -LocalConnection::LocalConnection( - std::shared_ptr conn, - std::shared_ptr> inspectedContexts) - : conn_(conn), inspectedContexts_(std::move(inspectedContexts)) { - inspectedContexts_->insert(conn->getTitle()); -} - -LocalConnection::~LocalConnection() = default; - -void LocalConnection::sendMessage(std::string message) { - conn_->handle(std::move(message)); -} - -void LocalConnection::disconnect() { - inspectedContexts_->erase(conn_->getTitle()); - conn_->unregisterCallbacks(); -} - -} // namespace - -ConnectionDemux::ConnectionDemux( - facebook::react::jsinspector_modern::IInspector& inspector) - : globalInspector_(inspector), - inspectedContexts_(std::make_shared>()) {} - -ConnectionDemux::~ConnectionDemux() = default; - -DebugSessionToken ConnectionDemux::enableDebugging( - std::unique_ptr adapter, - const std::string& title) { - std::scoped_lock lock(mutex_); - - // TODO(#22976087): workaround for ComponentScript contexts never being - // destroyed. - // - // After a reload, the old ComponentScript VM instance stays alive. When we - // register the new CS VM instance, check for any previous CS VM (via strcmp - // of title) and remove them. - std::vector pagesToDelete; - for (auto& conn : conns_) { - if (conn.second->getTitle() == title) { - pagesToDelete.push_back(conn.first); - } - } - - for (auto pageId : pagesToDelete) { - removePage(pageId); - } - - auto waitForDebugger = - (inspectedContexts_->find(title) != inspectedContexts_->end()); - return addPage( - hermes::inspector_modern::chrome::CDPHandler::create( - std::move(adapter), title, waitForDebugger)); -} - -void ConnectionDemux::disableDebugging(DebugSessionToken session) { - std::scoped_lock lock(mutex_); - if (conns_.find(session) == conns_.end()) { - return; - } - removePage(session); -} - -int ConnectionDemux::addPage( - std::shared_ptr conn) { - auto connectFunc = [conn, this](std::unique_ptr remoteConn) - -> std::unique_ptr { - // This cannot be unique_ptr as std::function is copyable but unique_ptr - // isn't. TODO: Change the CDPHandler API to accommodate this and not - // require a copyable callback? - std::shared_ptr sharedConn = std::move(remoteConn); - if (!conn->registerCallbacks( - [sharedConn](const std::string& message) { - sharedConn->onMessage(message); - }, - [sharedConn]() { sharedConn->onDisconnect(); })) { - return nullptr; - } - - return std::make_unique(conn, inspectedContexts_); - }; - - int pageId = globalInspector_.addPage( - conn->getTitle(), "Hermes", std::move(connectFunc)); - conns_[pageId] = std::move(conn); - - return pageId; -} - -void ConnectionDemux::removePage(int pageId) { - globalInspector_.removePage(pageId); - - auto conn = conns_.at(pageId); - std::string title = conn->getTitle(); - inspectedContexts_->erase(title); - conn->unregisterCallbacks(); - conns_.erase(pageId); -} - -} // namespace facebook::hermes::inspector_modern::chrome - -#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h deleted file mode 100644 index cc8dae74f8a4..000000000000 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace facebook::hermes::inspector_modern::chrome { - -/* - * ConnectionDemux keeps track of all debuggable Hermes runtimes (called - * "pages" in the higher-level React Native API) in this process. See - * Registration.h for documentation of the public API. - */ -class ConnectionDemux { - public: - explicit ConnectionDemux(facebook::react::jsinspector_modern::IInspector &inspector); - ~ConnectionDemux(); - - ConnectionDemux(const ConnectionDemux &) = delete; - ConnectionDemux &operator=(const ConnectionDemux &) = delete; - - DebugSessionToken enableDebugging(std::unique_ptr adapter, const std::string &title); - void disableDebugging(DebugSessionToken session); - - private: - int addPage(std::shared_ptr conn); - void removePage(int pageId); - - facebook::react::jsinspector_modern::IInspector &globalInspector_; - - std::mutex mutex_; - std::unordered_map> conns_; - std::shared_ptr> inspectedContexts_; -}; - -} // namespace facebook::hermes::inspector_modern::chrome - -#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp deleted file mode 100644 index 3274cba4f592..000000000000 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 "Registration.h" -#include "ConnectionDemux.h" - -#if defined(HERMES_ENABLE_DEBUGGER) - -#include - -#if !defined(HERMES_V1_ENABLED) - -namespace facebook::hermes::inspector_modern::chrome { -namespace { - -ConnectionDemux& demux() { - static ConnectionDemux instance{ - facebook::react::jsinspector_modern::getInspectorInstance()}; - return instance; -} - -} // namespace - -DebugSessionToken enableDebugging( - std::unique_ptr adapter, - const std::string& title) { - return demux().enableDebugging(std::move(adapter), title); -} - -void disableDebugging(DebugSessionToken session) { - demux().disableDebugging(session); -} - -} // namespace facebook::hermes::inspector_modern::chrome - -#else - -namespace facebook::hermes::inspector_modern { -class RuntimeAdapter { - // Backwards compatibility definition fallback for libraries that are compiled - // without `HERMES_V1_ENABLED` but are linked against React Native with - // `HERMES_V1_ENABLED` which doesn't provide this symbol. - public: - virtual ~RuntimeAdapter() = 0; - virtual HermesRuntime& getRuntime() = 0; - virtual void tickleJs(); -}; - -namespace chrome { - -using DebugSessionToken = int; - -DebugSessionToken enableDebugging( - std::unique_ptr, - const std::string&) { - // Backwards compatibility fallback for libraries that are compiled without - // `HERMES_V1_ENABLED` but are linked against React Native with - // `HERMES_V1_ENABLED` which doesn't provide this symbol. - return -1; -}; - -void disableDebugging(DebugSessionToken) { - // Backwards compatibility fallback for libraries that are compiled without - // `HERMES_V1_ENABLED` but are linked against React Native with - // `HERMES_V1_ENABLED` which doesn't provide this symbol. -} - -} // namespace chrome - -} // namespace facebook::hermes::inspector_modern - -#endif // !defined(HERMES_V1_ENABLED) - -#endif // defined(HERMES_ENABLE_DEBUGGER) diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.h b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.h deleted file mode 100644 index 2b60c27a6ee6..000000000000 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - -#include -#include - -#include -#include - -namespace facebook::hermes::inspector_modern::chrome { - -using DebugSessionToken = int; - -/* - * enableDebugging adds this runtime to the list of debuggable JS targets - * (called "pages" in the higher-level React Native API) in this process. It - * should be called before any JS runs in the runtime. The returned token - * can be used to disable debugging for this runtime. - */ -extern DebugSessionToken enableDebugging(std::unique_ptr adapter, const std::string &title); - -/* - * disableDebugging removes this runtime from the list of debuggable JS targets - * in this process. The runtime to remove is identified by the token returned - * from enableDebugging. - */ -extern void disableDebugging(DebugSessionToken session); - -} // namespace facebook::hermes::inspector_modern::chrome - -#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp deleted file mode 100644 index 0e652e207b18..000000000000 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace facebook { -namespace hermes { -namespace inspector_modern { -namespace chrome { - -using ::facebook::react::jsinspector_modern::IInspector; -using ::facebook::react::jsinspector_modern::InspectorPageDescription; -using ::facebook::react::jsinspector_modern::IRemoteConnection; - -namespace { - -std::unordered_map makePageMap( - const std::vector& pages) { - std::unordered_map pageMap; - - for (auto& page : pages) { - pageMap[page.id] = page.title; - } - - return pageMap; -} - -void expectPages( - IInspector& inspector, - const std::unordered_map& expected) { - auto pages = makePageMap(inspector.getPages()); - EXPECT_EQ(pages, expected); -} - -class TestRemoteConnection : public IRemoteConnection { - public: - class Data { - public: - void expectDisconnected() { - std::unique_lock lock(mutex_); - cv_.wait_for( - lock, std::chrono::milliseconds(2500), [&] { return !connected_; }); - EXPECT_FALSE(connected_); - } - - void setDisconnected() { - std::scoped_lock lock(mutex_); - connected_ = false; - cv_.notify_one(); - } - - private: - std::mutex mutex_; - std::condition_variable cv_; - bool connected_{true}; - }; - - TestRemoteConnection() : data_(std::make_shared()) {} - ~TestRemoteConnection() {} - - void onMessage(std::string message) override {} - - void onDisconnect() override { - data_->setDisconnected(); - } - - std::shared_ptr getData() { - return data_; - } - - private: - std::shared_ptr data_; -}; - -}; // namespace - -TEST(ConnectionDemuxTests, TestEnableDisable) { - std::shared_ptr runtime1( - facebook::hermes::makeHermesRuntime()); - std::shared_ptr runtime2( - facebook::hermes::makeHermesRuntime()); - auto inspector = - facebook::react::jsinspector_modern::makeTestInspectorInstance(); - - ConnectionDemux demux{*inspector}; - - int id1 = demux.enableDebugging( - std::make_unique(runtime1), "page1"); - int id2 = demux.enableDebugging( - std::make_unique(runtime2), "page2"); - - expectPages(*inspector, {{id1, "page1"}, {id2, "page2"}}); - - auto remoteConn1 = std::make_unique(); - auto remoteData1 = remoteConn1->getData(); - auto localConn1 = inspector->connect(id1, std::move(remoteConn1)); - EXPECT_NE(localConn1.get(), nullptr); - - { - // If we connect to the same page id again without disconnecting, we should - // get null - auto remoteConn = std::make_unique(); - auto localConn = inspector->connect(id1, std::move(remoteConn)); - EXPECT_EQ(localConn.get(), nullptr); - } - - auto remoteConn2 = std::make_unique(); - auto remoteData2 = remoteConn2->getData(); - auto localConn2 = inspector->connect(id2, std::move(remoteConn2)); - EXPECT_NE(localConn2.get(), nullptr); - - // Disable debugging on runtime2. This should remove its page from the list - // and call onDisconnect on its remoteConn - demux.disableDebugging(id2); - expectPages(*inspector, {{id1, "page1"}}); - remoteData2->expectDisconnected(); - - // Disconnect conn1. Its page should still be in the page list and - // onDisconnect should be called. - localConn1->disconnect(); - remoteData1->expectDisconnected(); - - { - // Should still be able to reconnect after disconnecting - auto remoteConn = std::make_unique(); - auto localConn = inspector->connect(id1, std::move(remoteConn)); - EXPECT_NE(localConn.get(), nullptr); - } -} - -} // namespace chrome -} // namespace inspector_modern -} // namespace hermes -} // namespace facebook diff --git a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp index b308cfd42082..d843a8338aeb 100644 --- a/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/hermes/HermesInstance.cpp @@ -12,90 +12,11 @@ #include #include -#ifdef HERMES_ENABLE_DEBUGGER -#include - -#ifndef HERMES_V1_ENABLED -#include -#endif - -#include -#endif - using namespace facebook::hermes; using namespace facebook::jsi; namespace facebook::react { -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - -// 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, - std::shared_ptr msgQueueThread) - : hermesRuntime_(std::move(hermesRuntime)), - messageQueueThread_(std::move(msgQueueThread)) {} - virtual ~HermesInstanceRuntimeAdapter() = default; - - HermesRuntime& getRuntime() override { - return *hermesRuntime_; - } - - void tickleJs() override { - std::weak_ptr 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_; - std::shared_ptr messageQueueThread_; -}; - -class DecoratedRuntime : public jsi::RuntimeDecorator { - public: - DecoratedRuntime( - std::unique_ptr runtime, - std::shared_ptr msgQueueThread) - : RuntimeDecorator(*runtime), runtime_(std::move(runtime)) { - auto adapter = std::make_unique( - runtime_, msgQueueThread); - - debugToken_ = inspector_modern::chrome::enableDebugging( - std::move(adapter), "Hermes Bridgeless React Native"); - } - - ~DecoratedRuntime() { - inspector_modern::chrome::disableDebugging(debugToken_); - } - - private: - std::shared_ptr runtime_; - inspector_modern::chrome::DebugSessionToken debugToken_; -}; - -#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - class HermesJSRuntime : public JSRuntime { public: HermesJSRuntime( @@ -164,17 +85,7 @@ std::unique_ptr HermesInstance::createJSRuntime( .getPropertyAsObject(*hermesRuntime, "prototype"); errorPrototype.setProperty(*hermesRuntime, "jsEngine", "hermes"); -#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED) - auto& inspectorFlags = jsinspector_modern::InspectorFlags::getInstance(); - if (!inspectorFlags.getFuseboxEnabled()) { - std::unique_ptr decoratedRuntime = - std::make_unique( - std::move(hermesRuntime), msgQueueThread); - return std::make_unique(std::move(decoratedRuntime)); - } -#else (void)msgQueueThread; -#endif HermesRuntime& hermesRuntimeRef = *hermesRuntime; return std::make_unique(