mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Implement Hermes.setPauseOnLoad
Summary: This Hermes-specific mode is similar to Debugger.setPauseOnExceptions and lets the VM know that it should enter a Pause state whenever a new script is loaded/executed. The debugger can then take its time to parse the source map and update any breakpoints, before automatically continuing. Changelog: [Internal] Implement a Hermes.setPauseOnLoad CDP call Reviewed By: bestander Differential Revision: D20754604 fbshipit-source-id: 7f9d0638706c99e9dcb534699b633f658e364909
This commit is contained in:
committed by
Facebook GitHub Bot
parent
04bc315eba
commit
33ccc0a0bc
@@ -382,6 +382,34 @@ folly::Future<folly::Unit> Inspector::setPauseOnExceptions(
|
||||
return promise->getFuture();
|
||||
};
|
||||
|
||||
folly::Future<folly::Unit> Inspector::setPauseOnLoads(
|
||||
const PauseOnLoadMode mode) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
auto promise = std::make_shared<folly::Promise<Unit>>();
|
||||
pauseOnLoadMode_ = mode;
|
||||
promise->setValue();
|
||||
return promise->getFuture();
|
||||
};
|
||||
|
||||
bool Inspector::shouldPauseOnThisScriptLoad() {
|
||||
switch (pauseOnLoadMode_) {
|
||||
case None:
|
||||
return false;
|
||||
case All:
|
||||
return true;
|
||||
case Smart:
|
||||
// If we don't have active breakpoints, there's nothing to set or update.
|
||||
if (debugger_.getBreakpoints().size() == 0) {
|
||||
return false;
|
||||
}
|
||||
// If there's no source map URL, it's probably not a file we care about.
|
||||
if (getScriptInfoFromTopCallFrame().sourceMappingUrl.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
debugger::Command Inspector::didPause(debugger::Debugger &debugger) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ struct ConsoleMessageInfo {
|
||||
args(std::move(args)) {}
|
||||
};
|
||||
|
||||
enum PauseOnLoadMode { None, Smart, All };
|
||||
|
||||
/**
|
||||
* InspectorObserver notifies the observer of events that occur in the VM.
|
||||
*/
|
||||
@@ -200,6 +202,19 @@ class Inspector : public facebook::hermes::debugger::EventObserver,
|
||||
folly::Future<folly::Unit> setPauseOnExceptions(
|
||||
const facebook::hermes::debugger::PauseOnThrowMode &mode);
|
||||
|
||||
/**
|
||||
* Set whether to pause on loads. This does not require runtime modifications,
|
||||
* but returns a future for consistency.
|
||||
*/
|
||||
folly::Future<folly::Unit> setPauseOnLoads(const PauseOnLoadMode mode);
|
||||
|
||||
/**
|
||||
* If called during a script load event, return true if we should pause.
|
||||
* Assumed to be called from a script load event where we already hold
|
||||
* `mutex_`.
|
||||
*/
|
||||
bool shouldPauseOnThisScriptLoad();
|
||||
|
||||
/**
|
||||
* didPause implements the pause callback from Hermes. This callback arrives
|
||||
* on the JS thread.
|
||||
@@ -297,6 +312,9 @@ class Inspector : public facebook::hermes::debugger::EventObserver,
|
||||
// this state is here rather than in the Running class.
|
||||
AsyncPauseState pendingPauseState_ = AsyncPauseState::None;
|
||||
|
||||
// Whether we should enter a paused state when a script loads.
|
||||
PauseOnLoadMode pauseOnLoadMode_ = PauseOnLoadMode::None;
|
||||
|
||||
// All scripts loaded in to the VM, along with whether we've notified the
|
||||
// client about the script yet.
|
||||
struct LoadedScriptInfo {
|
||||
|
||||
@@ -236,6 +236,10 @@ std::pair<NextStatePtr, CommandPtr> InspectorState::Running::didPause(
|
||||
} else if (reason == debugger::PauseReason::ScriptLoaded) {
|
||||
inspector_.addCurrentScriptToLoadedScripts();
|
||||
inspector_.notifyScriptsLoaded();
|
||||
if (inspector_.shouldPauseOnThisScriptLoad()) {
|
||||
return std::make_pair<NextStatePtr, CommandPtr>(
|
||||
InspectorState::Paused::make(inspector_), nullptr);
|
||||
}
|
||||
} else if (reason == debugger::PauseReason::EvalComplete) {
|
||||
assert(pendingEvalPromise_);
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ class Connection::Impl : public inspector::InspectorObserver,
|
||||
const m::heapProfiler::StopTrackingHeapObjectsRequest &req) override;
|
||||
void handle(const m::runtime::EvaluateRequest &req) override;
|
||||
void handle(const m::runtime::GetPropertiesRequest &req) override;
|
||||
void handle(const m::hermes::SetPauseOnLoadRequest &req) override;
|
||||
|
||||
private:
|
||||
std::vector<m::runtime::PropertyDescriptor> makePropsFromScope(
|
||||
@@ -290,6 +291,9 @@ void Connection::Impl::onPause(
|
||||
case debugger::PauseReason::Exception:
|
||||
note.reason = "exception";
|
||||
break;
|
||||
case debugger::PauseReason::ScriptLoaded:
|
||||
note.reason = "load";
|
||||
break;
|
||||
default:
|
||||
note.reason = "other";
|
||||
break;
|
||||
@@ -757,6 +761,21 @@ void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) {
|
||||
.thenError<std::exception>(sendErrorToClient(req.id));
|
||||
}
|
||||
|
||||
void Connection::Impl::handle(const m::hermes::SetPauseOnLoadRequest &req) {
|
||||
PauseOnLoadMode mode;
|
||||
if (req.state == "none") {
|
||||
mode = PauseOnLoadMode::None;
|
||||
} else if (req.state == "all") {
|
||||
mode = PauseOnLoadMode::All;
|
||||
} else if (req.state == "smart") {
|
||||
mode = PauseOnLoadMode::Smart;
|
||||
} else {
|
||||
sendErrorToClientViaExecutor(req.id, "Unrecognized pause on load mode");
|
||||
return;
|
||||
}
|
||||
sendResponseToClientViaExecutor(inspector_->setPauseOnLoads(mode), req.id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send-to-client methods
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// @generated SignedSource<<4ab81efd6f767bd583d00c806b7d1d9b>>
|
||||
// @generated SignedSource<<0d7691362d081e7bc44d2b7a0ed24371>>
|
||||
|
||||
#include "MessageTypes.h"
|
||||
|
||||
@@ -46,6 +46,7 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
|
||||
makeUnique<heapProfiler::StopTrackingHeapObjectsRequest>},
|
||||
{"HeapProfiler.takeHeapSnapshot",
|
||||
makeUnique<heapProfiler::TakeHeapSnapshotRequest>},
|
||||
{"Hermes.setPauseOnLoad", makeUnique<hermes::SetPauseOnLoadRequest>},
|
||||
{"Runtime.evaluate", makeUnique<runtime::EvaluateRequest>},
|
||||
{"Runtime.getProperties", makeUnique<runtime::GetPropertiesRequest>},
|
||||
};
|
||||
@@ -682,6 +683,33 @@ void heapProfiler::TakeHeapSnapshotRequest::accept(
|
||||
handler.handle(*this);
|
||||
}
|
||||
|
||||
hermes::SetPauseOnLoadRequest::SetPauseOnLoadRequest()
|
||||
: Request("Hermes.setPauseOnLoad") {}
|
||||
|
||||
hermes::SetPauseOnLoadRequest::SetPauseOnLoadRequest(const dynamic &obj)
|
||||
: Request("Hermes.setPauseOnLoad") {
|
||||
assign(id, obj, "id");
|
||||
assign(method, obj, "method");
|
||||
|
||||
dynamic params = obj.at("params");
|
||||
assign(state, params, "state");
|
||||
}
|
||||
|
||||
dynamic hermes::SetPauseOnLoadRequest::toDynamic() const {
|
||||
dynamic params = dynamic::object;
|
||||
put(params, "state", state);
|
||||
|
||||
dynamic obj = dynamic::object;
|
||||
put(obj, "id", id);
|
||||
put(obj, "method", method);
|
||||
put(obj, "params", std::move(params));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void hermes::SetPauseOnLoadRequest::accept(RequestHandler &handler) const {
|
||||
handler.handle(*this);
|
||||
}
|
||||
|
||||
runtime::EvaluateRequest::EvaluateRequest() : Request("Runtime.evaluate") {}
|
||||
|
||||
runtime::EvaluateRequest::EvaluateRequest(const dynamic &obj)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// @generated SignedSource<<0a1a011902fd18d4eebd2fe12fafb8b1>>
|
||||
// @generated SignedSource<<08b66e22784e225b926d36131b9a7693>>
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -73,6 +73,10 @@ struct StopTrackingHeapObjectsRequest;
|
||||
struct TakeHeapSnapshotRequest;
|
||||
} // namespace heapProfiler
|
||||
|
||||
namespace hermes {
|
||||
struct SetPauseOnLoadRequest;
|
||||
} // namespace hermes
|
||||
|
||||
/// RequestHandler handles requests via the visitor pattern.
|
||||
struct RequestHandler {
|
||||
virtual ~RequestHandler() = default;
|
||||
@@ -95,6 +99,7 @@ struct RequestHandler {
|
||||
virtual void handle(
|
||||
const heapProfiler::StopTrackingHeapObjectsRequest &req) = 0;
|
||||
virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0;
|
||||
virtual void handle(const hermes::SetPauseOnLoadRequest &req) = 0;
|
||||
virtual void handle(const runtime::EvaluateRequest &req) = 0;
|
||||
virtual void handle(const runtime::GetPropertiesRequest &req) = 0;
|
||||
};
|
||||
@@ -119,6 +124,7 @@ struct NoopRequestHandler : public RequestHandler {
|
||||
void handle(
|
||||
const heapProfiler::StopTrackingHeapObjectsRequest &req) override {}
|
||||
void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {}
|
||||
void handle(const hermes::SetPauseOnLoadRequest &req) override {}
|
||||
void handle(const runtime::EvaluateRequest &req) override {}
|
||||
void handle(const runtime::GetPropertiesRequest &req) override {}
|
||||
};
|
||||
@@ -411,6 +417,16 @@ struct heapProfiler::TakeHeapSnapshotRequest : public Request {
|
||||
folly::Optional<bool> treatGlobalObjectsAsRoots;
|
||||
};
|
||||
|
||||
struct hermes::SetPauseOnLoadRequest : public Request {
|
||||
SetPauseOnLoadRequest();
|
||||
explicit SetPauseOnLoadRequest(const folly::dynamic &obj);
|
||||
|
||||
folly::dynamic toDynamic() const override;
|
||||
void accept(RequestHandler &handler) const override;
|
||||
|
||||
std::string state;
|
||||
};
|
||||
|
||||
struct runtime::EvaluateRequest : public Request {
|
||||
EvaluateRequest();
|
||||
explicit EvaluateRequest(const folly::dynamic &obj);
|
||||
|
||||
@@ -23,3 +23,4 @@ Runtime.consoleAPICalled
|
||||
Runtime.evaluate
|
||||
Runtime.executionContextCreated
|
||||
Runtime.getProperties
|
||||
Hermes.setPauseOnLoad
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
{
|
||||
"domains": []
|
||||
"domains": [
|
||||
{
|
||||
"domain": "Hermes",
|
||||
"description": "Hermes specific messages",
|
||||
"commands": [
|
||||
{
|
||||
"name": "setPauseOnLoad",
|
||||
"description": "Pause VM when new scripts are loaded (reason='load')",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "state",
|
||||
"description": "Pause on script load mode",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"smart",
|
||||
"all"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user