diff --git a/ReactCommon/hermes/inspector/chrome/Connection.cpp b/ReactCommon/hermes/inspector/chrome/Connection.cpp index 2fa87b5386452c..e554f654dcbf51 100644 --- a/ReactCommon/hermes/inspector/chrome/Connection.cpp +++ b/ReactCommon/hermes/inspector/chrome/Connection.cpp @@ -103,6 +103,7 @@ class Connection::Impl : public inspector::InspectorObserver, void handle(const m::heapProfiler::GetHeapObjectIdRequest &req) override; void handle(const m::runtime::CallFunctionOnRequest &req) override; void handle(const m::runtime::EvaluateRequest &req) override; + void handle(const m::runtime::GetHeapUsageRequest &req) override; void handle(const m::runtime::GetPropertiesRequest &req) override; void handle(const m::runtime::RunIfWaitingForDebuggerRequest &req) override; @@ -1348,6 +1349,23 @@ Connection::Impl::makePropsFromValue( return result; } +void Connection::Impl::handle(const m::runtime::GetHeapUsageRequest &req) { + auto resp = std::make_shared(); + resp->id = req.id; + + inspector_ + ->executeIfEnabled( + "Runtime.getHeapUsage", + [this, req, resp](const debugger::ProgramState &state) { + auto heapInfo = getRuntime().instrumentation().getHeapInfo(false); + resp->usedSize = heapInfo["hermes_allocatedBytes"]; + resp->totalSize = heapInfo["hermes_heapSize"]; + }) + .via(executor_.get()) + .thenValue([this, resp](auto &&) { sendResponseToClient(*resp); }) + .thenError(sendErrorToClient(req.id)); +} + void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) { auto resp = std::make_shared(); resp->id = req.id; diff --git a/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp b/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp index 170f90593b9281..b7cab9c550e8dc 100644 --- a/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp +++ b/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp @@ -62,6 +62,7 @@ std::unique_ptr Request::fromJsonThrowOnError(const std::string &str) { makeUnique}, {"Runtime.callFunctionOn", makeUnique}, {"Runtime.evaluate", makeUnique}, + {"Runtime.getHeapUsage", makeUnique}, {"Runtime.getProperties", makeUnique}, {"Runtime.runIfWaitingForDebugger", makeUnique}, @@ -503,12 +504,22 @@ debugger::ResumeRequest::ResumeRequest(const dynamic &obj) : Request("Debugger.resume") { assign(id, obj, "id"); assign(method, obj, "method"); + + auto it = obj.find("params"); + if (it != obj.items().end()) { + dynamic params = it->second; + assign(terminateOnResume, params, "terminateOnResume"); + } } dynamic debugger::ResumeRequest::toDynamic() const { + dynamic params = dynamic::object; + put(params, "terminateOnResume", terminateOnResume); + dynamic obj = dynamic::object; put(obj, "id", id); put(obj, "method", method); + put(obj, "params", std::move(params)); return obj; } @@ -817,8 +828,11 @@ heapProfiler::StartSamplingRequest::StartSamplingRequest(const dynamic &obj) assign(id, obj, "id"); assign(method, obj, "method"); - dynamic params = obj.at("params"); - assign(samplingInterval, params, "samplingInterval"); + auto it = obj.find("params"); + if (it != obj.items().end()) { + dynamic params = it->second; + assign(samplingInterval, params, "samplingInterval"); + } } dynamic heapProfiler::StartSamplingRequest::toDynamic() const { @@ -845,8 +859,11 @@ heapProfiler::StartTrackingHeapObjectsRequest::StartTrackingHeapObjectsRequest( assign(id, obj, "id"); assign(method, obj, "method"); - dynamic params = obj.at("params"); - assign(trackAllocations, params, "trackAllocations"); + auto it = obj.find("params"); + if (it != obj.items().end()) { + dynamic params = it->second; + assign(trackAllocations, params, "trackAllocations"); + } } dynamic heapProfiler::StartTrackingHeapObjectsRequest::toDynamic() const { @@ -894,15 +911,20 @@ heapProfiler::StopTrackingHeapObjectsRequest::StopTrackingHeapObjectsRequest( assign(id, obj, "id"); assign(method, obj, "method"); - dynamic params = obj.at("params"); - assign(reportProgress, params, "reportProgress"); - assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots"); + auto it = obj.find("params"); + if (it != obj.items().end()) { + dynamic params = it->second; + assign(reportProgress, params, "reportProgress"); + assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots"); + assign(captureNumericValue, params, "captureNumericValue"); + } } dynamic heapProfiler::StopTrackingHeapObjectsRequest::toDynamic() const { dynamic params = dynamic::object; put(params, "reportProgress", reportProgress); put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots); + put(params, "captureNumericValue", captureNumericValue); dynamic obj = dynamic::object; put(obj, "id", id); @@ -925,15 +947,20 @@ heapProfiler::TakeHeapSnapshotRequest::TakeHeapSnapshotRequest( assign(id, obj, "id"); assign(method, obj, "method"); - dynamic params = obj.at("params"); - assign(reportProgress, params, "reportProgress"); - assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots"); + auto it = obj.find("params"); + if (it != obj.items().end()) { + dynamic params = it->second; + assign(reportProgress, params, "reportProgress"); + assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots"); + assign(captureNumericValue, params, "captureNumericValue"); + } } dynamic heapProfiler::TakeHeapSnapshotRequest::toDynamic() const { dynamic params = dynamic::object; put(params, "reportProgress", reportProgress); put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots); + put(params, "captureNumericValue", captureNumericValue); dynamic obj = dynamic::object; put(obj, "id", id); @@ -1030,6 +1057,26 @@ void runtime::EvaluateRequest::accept(RequestHandler &handler) const { handler.handle(*this); } +runtime::GetHeapUsageRequest::GetHeapUsageRequest() + : Request("Runtime.getHeapUsage") {} + +runtime::GetHeapUsageRequest::GetHeapUsageRequest(const dynamic &obj) + : Request("Runtime.getHeapUsage") { + assign(id, obj, "id"); + assign(method, obj, "method"); +} + +dynamic runtime::GetHeapUsageRequest::toDynamic() const { + dynamic obj = dynamic::object; + put(obj, "id", id); + put(obj, "method", method); + return obj; +} + +void runtime::GetHeapUsageRequest::accept(RequestHandler &handler) const { + handler.handle(*this); +} + runtime::GetPropertiesRequest::GetPropertiesRequest() : Request("Runtime.getProperties") {} @@ -1284,6 +1331,25 @@ dynamic runtime::EvaluateResponse::toDynamic() const { return obj; } +runtime::GetHeapUsageResponse::GetHeapUsageResponse(const dynamic &obj) { + assign(id, obj, "id"); + + dynamic res = obj.at("result"); + assign(usedSize, res, "usedSize"); + assign(totalSize, res, "totalSize"); +} + +dynamic runtime::GetHeapUsageResponse::toDynamic() const { + dynamic res = dynamic::object; + put(res, "usedSize", usedSize); + put(res, "totalSize", totalSize); + + dynamic obj = dynamic::object; + put(obj, "id", id); + put(obj, "result", std::move(res)); + return obj; +} + runtime::GetPropertiesResponse::GetPropertiesResponse(const dynamic &obj) { assign(id, obj, "id"); diff --git a/ReactCommon/hermes/inspector/chrome/MessageTypes.h b/ReactCommon/hermes/inspector/chrome/MessageTypes.h index 78468d6fb11db6..10ff9e4ca32c9d 100644 --- a/ReactCommon/hermes/inspector/chrome/MessageTypes.h +++ b/ReactCommon/hermes/inspector/chrome/MessageTypes.h @@ -59,6 +59,8 @@ struct ExceptionDetails; struct ExecutionContextCreatedNotification; struct ExecutionContextDescription; using ExecutionContextId = int; +struct GetHeapUsageRequest; +struct GetHeapUsageResponse; struct GetPropertiesRequest; struct GetPropertiesResponse; struct InternalPropertyDescriptor; @@ -127,6 +129,7 @@ struct RequestHandler { virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0; virtual void handle(const runtime::CallFunctionOnRequest &req) = 0; virtual void handle(const runtime::EvaluateRequest &req) = 0; + virtual void handle(const runtime::GetHeapUsageRequest &req) = 0; virtual void handle(const runtime::GetPropertiesRequest &req) = 0; virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0; }; @@ -162,6 +165,7 @@ struct NoopRequestHandler : public RequestHandler { void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {} void handle(const runtime::CallFunctionOnRequest &req) override {} void handle(const runtime::EvaluateRequest &req) override {} + void handle(const runtime::GetHeapUsageRequest &req) override {} void handle(const runtime::GetPropertiesRequest &req) override {} void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {} }; @@ -400,6 +404,8 @@ struct debugger::ResumeRequest : public Request { folly::dynamic toDynamic() const override; void accept(RequestHandler &handler) const override; + + folly::Optional terminateOnResume; }; struct debugger::SetBreakpointRequest : public Request { @@ -548,6 +554,7 @@ struct heapProfiler::StopTrackingHeapObjectsRequest : public Request { folly::Optional reportProgress; folly::Optional treatGlobalObjectsAsRoots; + folly::Optional captureNumericValue; }; struct heapProfiler::TakeHeapSnapshotRequest : public Request { @@ -559,6 +566,7 @@ struct heapProfiler::TakeHeapSnapshotRequest : public Request { folly::Optional reportProgress; folly::Optional treatGlobalObjectsAsRoots; + folly::Optional captureNumericValue; }; struct runtime::CallFunctionOnRequest : public Request { @@ -596,6 +604,14 @@ struct runtime::EvaluateRequest : public Request { folly::Optional awaitPromise; }; +struct runtime::GetHeapUsageRequest : public Request { + GetHeapUsageRequest(); + explicit GetHeapUsageRequest(const folly::dynamic &obj); + + folly::dynamic toDynamic() const override; + void accept(RequestHandler &handler) const override; +}; + struct runtime::GetPropertiesRequest : public Request { GetPropertiesRequest(); explicit GetPropertiesRequest(const folly::dynamic &obj); @@ -709,6 +725,15 @@ struct runtime::EvaluateResponse : public Response { folly::Optional exceptionDetails; }; +struct runtime::GetHeapUsageResponse : public Response { + GetHeapUsageResponse() = default; + explicit GetHeapUsageResponse(const folly::dynamic &obj); + folly::dynamic toDynamic() const override; + + double usedSize{}; + double totalSize{}; +}; + struct runtime::GetPropertiesResponse : public Response { GetPropertiesResponse() = default; explicit GetPropertiesResponse(const folly::dynamic &obj); diff --git a/ReactCommon/hermes/inspector/chrome/tests/MessageTests.cpp b/ReactCommon/hermes/inspector/chrome/tests/MessageTests.cpp index 2b433f33aea5fe..dae6513a04b902 100644 --- a/ReactCommon/hermes/inspector/chrome/tests/MessageTests.cpp +++ b/ReactCommon/hermes/inspector/chrome/tests/MessageTests.cpp @@ -692,7 +692,10 @@ TEST(MessageTests, testResumeRequest) { std::string message = R"( { "id": 10, - "method": "Debugger.resume" + "method": "Debugger.resume", + "params": { + "terminateOnResume": false + } } )"; diff --git a/ReactCommon/hermes/inspector/tools/message_types.txt b/ReactCommon/hermes/inspector/tools/message_types.txt index 8921a8292561cc..d2868e6ab3c331 100644 --- a/ReactCommon/hermes/inspector/tools/message_types.txt +++ b/ReactCommon/hermes/inspector/tools/message_types.txt @@ -32,5 +32,6 @@ Runtime.callFunctionOn Runtime.consoleAPICalled Runtime.evaluate Runtime.executionContextCreated +Runtime.getHeapUsage Runtime.getProperties Runtime.runIfWaitingForDebugger diff --git a/ReactCommon/hermes/inspector/tools/msggen/package.json b/ReactCommon/hermes/inspector/tools/msggen/package.json index 6e42007bf68bfb..b3dcba4544fbe1 100644 --- a/ReactCommon/hermes/inspector/tools/msggen/package.json +++ b/ReactCommon/hermes/inspector/tools/msggen/package.json @@ -12,7 +12,7 @@ "test": "jest" }, "dependencies": { - "devtools-protocol": "0.0.730699", + "devtools-protocol": "0.0.959523", "yargs": "^14.2.0" }, "devDependencies": { diff --git a/ReactCommon/hermes/inspector/tools/msggen/src/ImplementationWriter.js b/ReactCommon/hermes/inspector/tools/msggen/src/ImplementationWriter.js index 5e2b690771409b..e2ff75628271b9 100644 --- a/ReactCommon/hermes/inspector/tools/msggen/src/ImplementationWriter.js +++ b/ReactCommon/hermes/inspector/tools/msggen/src/ImplementationWriter.js @@ -266,13 +266,26 @@ export function emitRequestDef(stream: Writable, command: Command) { assign(method, obj, "method");\n\n`); if (props.length > 0) { - stream.write('dynamic params = obj.at("params");\n'); + const optionalParams = props.every(p => p.optional); + if (optionalParams) { + stream.write(` + auto it = obj.find("params"); + if (it != obj.items().end()) { + dynamic params = it->second; + `); + } else { + stream.write('dynamic params = obj.at("params");\n'); + } for (const prop of props) { const id = prop.getCppIdentifier(); const name = prop.name; stream.write(`assign(${id}, params, "${name}");\n`); } + + if (optionalParams) { + stream.write('}'); + } } stream.write('}\n\n'); diff --git a/ReactCommon/hermes/inspector/tools/msggen/src/index.js b/ReactCommon/hermes/inspector/tools/msggen/src/index.js index cf6f3d881ec6ca..eb9a4f3ba96501 100644 --- a/ReactCommon/hermes/inspector/tools/msggen/src/index.js +++ b/ReactCommon/hermes/inspector/tools/msggen/src/index.js @@ -41,6 +41,7 @@ const proto = mergeDomains(standard, custom); function parseDomains( domainObjs: Array, ignoreExperimental: boolean, + includeExperimental: Set, ): Descriptor { const desc = { types: [], @@ -59,7 +60,12 @@ function parseDomains( } for (const commandObj of obj.commands || []) { - const command = Command.create(domain, commandObj, ignoreExperimental); + const command = Command.create( + domain, + commandObj, + !includeExperimental.has(`${domain}.${commandObj.name}`) && + ignoreExperimental, + ); if (command) { desc.commands.push(command); } @@ -199,18 +205,27 @@ function main() { .boolean('e') .alias('e', 'ignore-experimental') .describe('e', 'ignore experimental commands, props, and types') + .alias('i', 'include-experimental') + .describe('i', 'experimental commands to include') .alias('r', 'roots') .describe('r', 'path to a file listing root types, events, and commands') .nargs('r', 1) .demandCommand(2, 2).argv; const ignoreExperimental = !!args.e; + const includeExperimental = new Set( + typeof args.i === 'string' ? args.i.split(',') : [], + ); const [headerPath, implPath] = args._; const headerStream = fs.createWriteStream(headerPath); const implStream = fs.createWriteStream(implPath); - const desc = parseDomains(proto.domains, ignoreExperimental); + const desc = parseDomains( + proto.domains, + ignoreExperimental, + includeExperimental, + ); const graph = buildGraph(desc); const roots = parseRoots(desc, String(args.roots)); diff --git a/ReactCommon/hermes/inspector/tools/msggen/yarn.lock b/ReactCommon/hermes/inspector/tools/msggen/yarn.lock index b6b1be6b96f535..40a02746282e98 100644 --- a/ReactCommon/hermes/inspector/tools/msggen/yarn.lock +++ b/ReactCommon/hermes/inspector/tools/msggen/yarn.lock @@ -2434,10 +2434,10 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -devtools-protocol@0.0.730699: - version "0.0.730699" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.730699.tgz#4d18f6a9b7fb7cf3f1ffe73bfe14aad66cf3b2ef" - integrity sha512-dprBpuPzVIIXXL6GevzhvWe2wg836h3d5hY+n6IzzHbKLsUh6QlVmcIy15za0J3MhDFbmEH60s6uYsrw/tgBbw== +devtools-protocol@0.0.959523: + version "0.0.959523" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.959523.tgz#a7ce62c6b88876081fe5bec866f70e467bc021ba" + integrity sha512-taOcAND/oJA5FhJD2I3RA+I8RPdrpPJWwvMBPzTq7Sugev1xTOG3lgtlSfkh5xkjTYw0Ti2CRQq016goFHMoPQ== diff-sequences@^26.6.2: version "26.6.2" diff --git a/ReactCommon/hermes/inspector/tools/run_msggen b/ReactCommon/hermes/inspector/tools/run_msggen index 053cb3673727e5..c349b70be6c9e7 100755 --- a/ReactCommon/hermes/inspector/tools/run_msggen +++ b/ReactCommon/hermes/inspector/tools/run_msggen @@ -2,24 +2,25 @@ set -e -DIR=$(dirname "${BASH_SOURCE[0]}") +DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) cd "${DIR}/msggen" yarn install yarn build -FBSOURCE=$(hg root) -MSGTYPES_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/tools/message_types.txt" -HEADER_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/chrome/MessageTypes.h" -CPP_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp" +MSGTYPES_PATH="${DIR}/message_types.txt" +HEADER_PATH="${DIR}/../chrome/MessageTypes.h" +CPP_PATH="${DIR}/../chrome/MessageTypes.cpp" node bin/index.js \ --ignore-experimental \ + --include-experimental=Runtime.getHeapUsage \ --roots "$MSGTYPES_PATH" \ "$HEADER_PATH" "$CPP_PATH" clang-format -i --style=file "$HEADER_PATH" clang-format -i --style=file "$CPP_PATH" +FBSOURCE=$(hg root) "${FBSOURCE}/tools/signedsource" sign "$HEADER_PATH" "${FBSOURCE}/tools/signedsource" sign "$CPP_PATH"