diff --git a/API/hermes/cdp/CDPAgent.cpp b/API/hermes/cdp/CDPAgent.cpp index 22cbab52ee6..b5226fdbbb8 100644 --- a/API/hermes/cdp/CDPAgent.cpp +++ b/API/hermes/cdp/CDPAgent.cpp @@ -32,9 +32,15 @@ struct State::Private { std::unique_ptr debuggerDomainState; }; +State::State() : privateState_(nullptr) {} + State::State(std::unique_ptr privateState) : privateState_(std::move(privateState)) {} +State::State(State &&other) noexcept = default; + +State &State::operator=(State &&other) noexcept = default; + State::~State() = default; /// Implementation of the CDP Agent. This class accepts CDP commands from @@ -52,7 +58,7 @@ class CDPAgentImpl { ~CDPAgentImpl(); /// Schedule initialization of handlers for each message domain. - void initializeDomainAgents(std::unique_ptr state); + void initializeDomainAgents(State state); /// Process a CDP command encoded in \p json. void handleCommand(std::string json); @@ -62,7 +68,7 @@ class CDPAgentImpl { void enableRuntimeDomain(); /// Extract state to be persisted across reloads. - std::unique_ptr getState(); + State getState(); private: /// Collection of domain-specific message handlers. These handlers require @@ -77,7 +83,7 @@ class CDPAgentImpl { SynchronizedOutboundCallback messageCallback); /// Create the domain handlers and subscribing to any external events. - void initialize(std::shared_ptr state); + void initialize(State state); /// Releasing any domain handlers and event subscriptions. void dispose(); @@ -176,12 +182,16 @@ CDPAgentImpl::~CDPAgentImpl() { messageCallback_.invalidate(); } -void CDPAgentImpl::initializeDomainAgents(std::unique_ptr state) { +void CDPAgentImpl::initializeDomainAgents(State state) { // Call DomainAgents::initialize on the runtime thread. - std::shared_ptr initialState = std::move(state); + // NOTE: std::function is copyable but State isn't, so we need to pass it + // through a shared_ptr. + std::shared_ptr stateHolder = + std::make_shared(std::move(state)); runtimeTaskRunner_.enqueueTask( - [domainAgents = domainAgents_, initialState](HermesRuntime &) { - domainAgents->initialize(initialState); + [domainAgents = domainAgents_, + stateHolder = std::move(stateHolder)](HermesRuntime &) { + domainAgents->initialize(std::move(*stateHolder)); }); } @@ -209,14 +219,14 @@ void CDPAgentImpl::enableRuntimeDomain() { }); } -std::unique_ptr CDPAgentImpl::getState() { +State CDPAgentImpl::getState() { // This function might not be called on the runtime thread. Functions on // DomainAgents expect to be called on the runtime thread because they // manipulate the runtime. In this case, it's still fine to call // getDebuggerDomainState() because internally it's protected by a mutex so no // DomainAgents functions can simultaneously manipulate the runtime and get // the state. - return std::make_unique(std::make_unique( + return State(std::make_unique( domainAgents_->getDebuggerDomainState())); } @@ -232,11 +242,11 @@ CDPAgentImpl::DomainAgents::DomainAgents( messageCallback_(std::move(messageCallback)), objTable_(std::make_shared()) {} -void CDPAgentImpl::DomainAgents::initialize(std::shared_ptr state) { +void CDPAgentImpl::DomainAgents::initialize(State state) { std::lock_guard lock(mutex_); std::unique_ptr debuggerState = nullptr; if (state) { - debuggerState = std::move(state->get().debuggerDomainState); + debuggerState = std::move(state->debuggerDomainState); } debuggerAgent_ = std::make_unique( executionContextID_, @@ -368,7 +378,7 @@ std::unique_ptr CDPAgent::create( CDPDebugAPI &cdpDebugAPI, EnqueueRuntimeTaskFunc enqueueRuntimeTaskCallback, OutboundMessageFunc messageCallback, - std::unique_ptr state) { + State state) { return std::unique_ptr(new CDPAgent( executionContextID, cdpDebugAPI, @@ -382,7 +392,7 @@ CDPAgent::CDPAgent( CDPDebugAPI &cdpDebugAPI, EnqueueRuntimeTaskFunc enqueueRuntimeTaskCallback, OutboundMessageFunc messageCallback, - std::unique_ptr state) + State state) : impl_(std::make_unique( executionContextID, cdpDebugAPI, @@ -401,7 +411,7 @@ void CDPAgent::enableRuntimeDomain() { impl_->enableRuntimeDomain(); } -std::unique_ptr CDPAgent::getState() { +State CDPAgent::getState() { return impl_->getState(); } diff --git a/API/hermes/cdp/CDPAgent.h b/API/hermes/cdp/CDPAgent.h index 6fe33952967..386208269d8 100644 --- a/API/hermes/cdp/CDPAgent.h +++ b/API/hermes/cdp/CDPAgent.h @@ -23,7 +23,42 @@ using OutboundMessageFunc = std::function; class CDPAgentImpl; class CDPDebugAPI; -struct State; + +/// Public-facing wrapper for internal CDP state that can be preserved across +/// reloads. +struct HERMES_EXPORT State { + /// Incomplete type that stores the actual state. + struct Private; + + /// Create a new empty wrapper. + State(); + /// Create a new wrapper with the provided \p privateState. + explicit State(std::unique_ptr privateState); + + State(const State &other) = delete; + State &operator=(const State &other) = delete; + State(State &&other) noexcept; + State &operator=(State &&other) noexcept; + ~State(); + + inline operator bool() const { + return privateState_ != nullptr; + } + + /// Get the wrapped state. + inline Private &operator*() { + return *privateState_.get(); + } + + /// Get the wrapped state. + inline Private *operator->() { + return privateState_.get(); + } + + private: + /// Pointer to the actual stored state, hidden from users of this wrapper. + std::unique_ptr privateState_; +}; /// An agent for interacting with the provided \p runtime and /// \p asyncDebuggerAPI via CDP messages in the Debugger, Runtime, Profiler, @@ -45,7 +80,7 @@ class HERMES_EXPORT CDPAgent { CDPDebugAPI &cdpDebugAPI, debugger::EnqueueRuntimeTaskFunc enqueueRuntimeTaskCallback, OutboundMessageFunc messageCallback, - std::unique_ptr state); + State state); public: /// Create a new CDP Agent. This can be done on an arbitrary thread; the @@ -55,7 +90,7 @@ class HERMES_EXPORT CDPAgent { CDPDebugAPI &cdpDebugAPI, debugger::EnqueueRuntimeTaskFunc enqueueRuntimeTaskCallback, OutboundMessageFunc messageCallback, - std::unique_ptr state = nullptr); + State state = {}); /// Destroy the CDP Agent. This can be done on an arbitrary thread. /// It's expected that the integrator will continue to process any runtime @@ -72,7 +107,7 @@ class HERMES_EXPORT CDPAgent { /// Extract state to be persisted across reloads. This can be called from /// arbitrary threads. - std::unique_ptr getState(); + State getState(); private: /// This should be a unique_ptr to provide predictable destruction time lined @@ -80,26 +115,6 @@ class HERMES_EXPORT CDPAgent { std::unique_ptr impl_; }; -/// Public-facing wrapper for internal CDP state that can be preserved across -/// reloads. -struct HERMES_EXPORT State { - /// Incomplete type that stores the actual state. - struct Private; - - /// Create a new wrapper with the provided \p privateState. - explicit State(std::unique_ptr privateState); - ~State(); - - /// Get the wrapped state. - Private &get() { - return *privateState_.get(); - } - - private: - /// Pointer to the actual stored state, hidden from users of this wrapper. - std::unique_ptr privateState_; -}; - } // namespace cdp } // namespace hermes } // namespace facebook diff --git a/unittests/API/CDPAgentTest.cpp b/unittests/API/CDPAgentTest.cpp index fe9334b96d7..14c3fbd9074 100644 --- a/unittests/API/CDPAgentTest.cpp +++ b/unittests/API/CDPAgentTest.cpp @@ -1412,7 +1412,7 @@ TEST_F(CDPAgentTest, DebuggerRestoreState) { ensureSetBreakpointByUrlResponse(waitForMessage(), msgId++, {}); for (int i = 0; i < 2; i++) { - std::unique_ptr state; + State state; if (i == 0) { // Save CDPAgent state on non-runtime thread and shut everything down. state = cdpAgent_->getState();