Skip to content

Commit cff9590

Browse files
janicduplessisfacebook-github-bot
authored andcommitted
Implement Runtime.getHeapUsage for hermes chrome inspector (#33173)
Summary: Reland of #32895 with fix for optional params object. Original description: I was looking at the hermes chrome devtools integration and noticed requests to `Runtime.getHeapUsage` which was not implemented. When implemented it will show a summary of memory usage of the javascript instance in devtools. <img width="325" alt="image" src="https://user-images.githubusercontent.com/2677334/149637113-e1d95d26-9e26-46c2-9be6-47d22284f15f.png"> ## Changelog [General] [Added] - Implement Runtime.getHeapUsage for hermes chrome inspector Pull Request resolved: #33173 Test Plan: I was able to reproduce the issue that caused the initial PR to be reverted using the resume request in Flipper. Pausing JS execution then resuming it will cause it to crash before this change, and works fine after. Before <img width="912" alt="image" src="https://user-images.githubusercontent.com/2677334/149637073-15f4e1fa-8183-42dc-8673-d4371731415c.png"> After <img width="1076" alt="image" src="https://user-images.githubusercontent.com/2677334/149637085-579dee8f-5efb-4658-b0a8-2400bd119924.png"> Reviewed By: jpporto Differential Revision: D34446672 Pulled By: ShikaSD fbshipit-source-id: 6e26b8d53cd88cddded36437c72a01822551b9d0
1 parent 46bc521 commit cff9590

File tree

10 files changed

+166
-24
lines changed

10 files changed

+166
-24
lines changed

ReactCommon/hermes/inspector/chrome/Connection.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class Connection::Impl : public inspector::InspectorObserver,
103103
void handle(const m::heapProfiler::GetHeapObjectIdRequest &req) override;
104104
void handle(const m::runtime::CallFunctionOnRequest &req) override;
105105
void handle(const m::runtime::EvaluateRequest &req) override;
106+
void handle(const m::runtime::GetHeapUsageRequest &req) override;
106107
void handle(const m::runtime::GetPropertiesRequest &req) override;
107108
void handle(const m::runtime::RunIfWaitingForDebuggerRequest &req) override;
108109

@@ -1348,6 +1349,23 @@ Connection::Impl::makePropsFromValue(
13481349
return result;
13491350
}
13501351

1352+
void Connection::Impl::handle(const m::runtime::GetHeapUsageRequest &req) {
1353+
auto resp = std::make_shared<m::runtime::GetHeapUsageResponse>();
1354+
resp->id = req.id;
1355+
1356+
inspector_
1357+
->executeIfEnabled(
1358+
"Runtime.getHeapUsage",
1359+
[this, req, resp](const debugger::ProgramState &state) {
1360+
auto heapInfo = getRuntime().instrumentation().getHeapInfo(false);
1361+
resp->usedSize = heapInfo["hermes_allocatedBytes"];
1362+
resp->totalSize = heapInfo["hermes_heapSize"];
1363+
})
1364+
.via(executor_.get())
1365+
.thenValue([this, resp](auto &&) { sendResponseToClient(*resp); })
1366+
.thenError<std::exception>(sendErrorToClient(req.id));
1367+
}
1368+
13511369
void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) {
13521370
auto resp = std::make_shared<m::runtime::GetPropertiesResponse>();
13531371
resp->id = req.id;

ReactCommon/hermes/inspector/chrome/MessageTypes.cpp

+76-10
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
6262
makeUnique<heapProfiler::TakeHeapSnapshotRequest>},
6363
{"Runtime.callFunctionOn", makeUnique<runtime::CallFunctionOnRequest>},
6464
{"Runtime.evaluate", makeUnique<runtime::EvaluateRequest>},
65+
{"Runtime.getHeapUsage", makeUnique<runtime::GetHeapUsageRequest>},
6566
{"Runtime.getProperties", makeUnique<runtime::GetPropertiesRequest>},
6667
{"Runtime.runIfWaitingForDebugger",
6768
makeUnique<runtime::RunIfWaitingForDebuggerRequest>},
@@ -503,12 +504,22 @@ debugger::ResumeRequest::ResumeRequest(const dynamic &obj)
503504
: Request("Debugger.resume") {
504505
assign(id, obj, "id");
505506
assign(method, obj, "method");
507+
508+
auto it = obj.find("params");
509+
if (it != obj.items().end()) {
510+
dynamic params = it->second;
511+
assign(terminateOnResume, params, "terminateOnResume");
512+
}
506513
}
507514

508515
dynamic debugger::ResumeRequest::toDynamic() const {
516+
dynamic params = dynamic::object;
517+
put(params, "terminateOnResume", terminateOnResume);
518+
509519
dynamic obj = dynamic::object;
510520
put(obj, "id", id);
511521
put(obj, "method", method);
522+
put(obj, "params", std::move(params));
512523
return obj;
513524
}
514525

@@ -817,8 +828,11 @@ heapProfiler::StartSamplingRequest::StartSamplingRequest(const dynamic &obj)
817828
assign(id, obj, "id");
818829
assign(method, obj, "method");
819830

820-
dynamic params = obj.at("params");
821-
assign(samplingInterval, params, "samplingInterval");
831+
auto it = obj.find("params");
832+
if (it != obj.items().end()) {
833+
dynamic params = it->second;
834+
assign(samplingInterval, params, "samplingInterval");
835+
}
822836
}
823837

824838
dynamic heapProfiler::StartSamplingRequest::toDynamic() const {
@@ -845,8 +859,11 @@ heapProfiler::StartTrackingHeapObjectsRequest::StartTrackingHeapObjectsRequest(
845859
assign(id, obj, "id");
846860
assign(method, obj, "method");
847861

848-
dynamic params = obj.at("params");
849-
assign(trackAllocations, params, "trackAllocations");
862+
auto it = obj.find("params");
863+
if (it != obj.items().end()) {
864+
dynamic params = it->second;
865+
assign(trackAllocations, params, "trackAllocations");
866+
}
850867
}
851868

852869
dynamic heapProfiler::StartTrackingHeapObjectsRequest::toDynamic() const {
@@ -894,15 +911,20 @@ heapProfiler::StopTrackingHeapObjectsRequest::StopTrackingHeapObjectsRequest(
894911
assign(id, obj, "id");
895912
assign(method, obj, "method");
896913

897-
dynamic params = obj.at("params");
898-
assign(reportProgress, params, "reportProgress");
899-
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
914+
auto it = obj.find("params");
915+
if (it != obj.items().end()) {
916+
dynamic params = it->second;
917+
assign(reportProgress, params, "reportProgress");
918+
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
919+
assign(captureNumericValue, params, "captureNumericValue");
920+
}
900921
}
901922

902923
dynamic heapProfiler::StopTrackingHeapObjectsRequest::toDynamic() const {
903924
dynamic params = dynamic::object;
904925
put(params, "reportProgress", reportProgress);
905926
put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots);
927+
put(params, "captureNumericValue", captureNumericValue);
906928

907929
dynamic obj = dynamic::object;
908930
put(obj, "id", id);
@@ -925,15 +947,20 @@ heapProfiler::TakeHeapSnapshotRequest::TakeHeapSnapshotRequest(
925947
assign(id, obj, "id");
926948
assign(method, obj, "method");
927949

928-
dynamic params = obj.at("params");
929-
assign(reportProgress, params, "reportProgress");
930-
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
950+
auto it = obj.find("params");
951+
if (it != obj.items().end()) {
952+
dynamic params = it->second;
953+
assign(reportProgress, params, "reportProgress");
954+
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
955+
assign(captureNumericValue, params, "captureNumericValue");
956+
}
931957
}
932958

933959
dynamic heapProfiler::TakeHeapSnapshotRequest::toDynamic() const {
934960
dynamic params = dynamic::object;
935961
put(params, "reportProgress", reportProgress);
936962
put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots);
963+
put(params, "captureNumericValue", captureNumericValue);
937964

938965
dynamic obj = dynamic::object;
939966
put(obj, "id", id);
@@ -1030,6 +1057,26 @@ void runtime::EvaluateRequest::accept(RequestHandler &handler) const {
10301057
handler.handle(*this);
10311058
}
10321059

1060+
runtime::GetHeapUsageRequest::GetHeapUsageRequest()
1061+
: Request("Runtime.getHeapUsage") {}
1062+
1063+
runtime::GetHeapUsageRequest::GetHeapUsageRequest(const dynamic &obj)
1064+
: Request("Runtime.getHeapUsage") {
1065+
assign(id, obj, "id");
1066+
assign(method, obj, "method");
1067+
}
1068+
1069+
dynamic runtime::GetHeapUsageRequest::toDynamic() const {
1070+
dynamic obj = dynamic::object;
1071+
put(obj, "id", id);
1072+
put(obj, "method", method);
1073+
return obj;
1074+
}
1075+
1076+
void runtime::GetHeapUsageRequest::accept(RequestHandler &handler) const {
1077+
handler.handle(*this);
1078+
}
1079+
10331080
runtime::GetPropertiesRequest::GetPropertiesRequest()
10341081
: Request("Runtime.getProperties") {}
10351082

@@ -1284,6 +1331,25 @@ dynamic runtime::EvaluateResponse::toDynamic() const {
12841331
return obj;
12851332
}
12861333

1334+
runtime::GetHeapUsageResponse::GetHeapUsageResponse(const dynamic &obj) {
1335+
assign(id, obj, "id");
1336+
1337+
dynamic res = obj.at("result");
1338+
assign(usedSize, res, "usedSize");
1339+
assign(totalSize, res, "totalSize");
1340+
}
1341+
1342+
dynamic runtime::GetHeapUsageResponse::toDynamic() const {
1343+
dynamic res = dynamic::object;
1344+
put(res, "usedSize", usedSize);
1345+
put(res, "totalSize", totalSize);
1346+
1347+
dynamic obj = dynamic::object;
1348+
put(obj, "id", id);
1349+
put(obj, "result", std::move(res));
1350+
return obj;
1351+
}
1352+
12871353
runtime::GetPropertiesResponse::GetPropertiesResponse(const dynamic &obj) {
12881354
assign(id, obj, "id");
12891355

ReactCommon/hermes/inspector/chrome/MessageTypes.h

+25
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ struct ExceptionDetails;
5959
struct ExecutionContextCreatedNotification;
6060
struct ExecutionContextDescription;
6161
using ExecutionContextId = int;
62+
struct GetHeapUsageRequest;
63+
struct GetHeapUsageResponse;
6264
struct GetPropertiesRequest;
6365
struct GetPropertiesResponse;
6466
struct InternalPropertyDescriptor;
@@ -127,6 +129,7 @@ struct RequestHandler {
127129
virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0;
128130
virtual void handle(const runtime::CallFunctionOnRequest &req) = 0;
129131
virtual void handle(const runtime::EvaluateRequest &req) = 0;
132+
virtual void handle(const runtime::GetHeapUsageRequest &req) = 0;
130133
virtual void handle(const runtime::GetPropertiesRequest &req) = 0;
131134
virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0;
132135
};
@@ -162,6 +165,7 @@ struct NoopRequestHandler : public RequestHandler {
162165
void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {}
163166
void handle(const runtime::CallFunctionOnRequest &req) override {}
164167
void handle(const runtime::EvaluateRequest &req) override {}
168+
void handle(const runtime::GetHeapUsageRequest &req) override {}
165169
void handle(const runtime::GetPropertiesRequest &req) override {}
166170
void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {}
167171
};
@@ -400,6 +404,8 @@ struct debugger::ResumeRequest : public Request {
400404

401405
folly::dynamic toDynamic() const override;
402406
void accept(RequestHandler &handler) const override;
407+
408+
folly::Optional<bool> terminateOnResume;
403409
};
404410

405411
struct debugger::SetBreakpointRequest : public Request {
@@ -548,6 +554,7 @@ struct heapProfiler::StopTrackingHeapObjectsRequest : public Request {
548554

549555
folly::Optional<bool> reportProgress;
550556
folly::Optional<bool> treatGlobalObjectsAsRoots;
557+
folly::Optional<bool> captureNumericValue;
551558
};
552559

553560
struct heapProfiler::TakeHeapSnapshotRequest : public Request {
@@ -559,6 +566,7 @@ struct heapProfiler::TakeHeapSnapshotRequest : public Request {
559566

560567
folly::Optional<bool> reportProgress;
561568
folly::Optional<bool> treatGlobalObjectsAsRoots;
569+
folly::Optional<bool> captureNumericValue;
562570
};
563571

564572
struct runtime::CallFunctionOnRequest : public Request {
@@ -596,6 +604,14 @@ struct runtime::EvaluateRequest : public Request {
596604
folly::Optional<bool> awaitPromise;
597605
};
598606

607+
struct runtime::GetHeapUsageRequest : public Request {
608+
GetHeapUsageRequest();
609+
explicit GetHeapUsageRequest(const folly::dynamic &obj);
610+
611+
folly::dynamic toDynamic() const override;
612+
void accept(RequestHandler &handler) const override;
613+
};
614+
599615
struct runtime::GetPropertiesRequest : public Request {
600616
GetPropertiesRequest();
601617
explicit GetPropertiesRequest(const folly::dynamic &obj);
@@ -709,6 +725,15 @@ struct runtime::EvaluateResponse : public Response {
709725
folly::Optional<runtime::ExceptionDetails> exceptionDetails;
710726
};
711727

728+
struct runtime::GetHeapUsageResponse : public Response {
729+
GetHeapUsageResponse() = default;
730+
explicit GetHeapUsageResponse(const folly::dynamic &obj);
731+
folly::dynamic toDynamic() const override;
732+
733+
double usedSize{};
734+
double totalSize{};
735+
};
736+
712737
struct runtime::GetPropertiesResponse : public Response {
713738
GetPropertiesResponse() = default;
714739
explicit GetPropertiesResponse(const folly::dynamic &obj);

ReactCommon/hermes/inspector/chrome/tests/MessageTests.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,10 @@ TEST(MessageTests, testResumeRequest) {
692692
std::string message = R"(
693693
{
694694
"id": 10,
695-
"method": "Debugger.resume"
695+
"method": "Debugger.resume",
696+
"params": {
697+
"terminateOnResume": false
698+
}
696699
}
697700
)";
698701

ReactCommon/hermes/inspector/tools/message_types.txt

+1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ Runtime.callFunctionOn
3232
Runtime.consoleAPICalled
3333
Runtime.evaluate
3434
Runtime.executionContextCreated
35+
Runtime.getHeapUsage
3536
Runtime.getProperties
3637
Runtime.runIfWaitingForDebugger

ReactCommon/hermes/inspector/tools/msggen/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"test": "jest"
1313
},
1414
"dependencies": {
15-
"devtools-protocol": "0.0.730699",
15+
"devtools-protocol": "0.0.959523",
1616
"yargs": "^14.2.0"
1717
},
1818
"devDependencies": {

ReactCommon/hermes/inspector/tools/msggen/src/ImplementationWriter.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,26 @@ export function emitRequestDef(stream: Writable, command: Command) {
266266
assign(method, obj, "method");\n\n`);
267267

268268
if (props.length > 0) {
269-
stream.write('dynamic params = obj.at("params");\n');
269+
const optionalParams = props.every(p => p.optional);
270+
if (optionalParams) {
271+
stream.write(`
272+
auto it = obj.find("params");
273+
if (it != obj.items().end()) {
274+
dynamic params = it->second;
275+
`);
276+
} else {
277+
stream.write('dynamic params = obj.at("params");\n');
278+
}
270279

271280
for (const prop of props) {
272281
const id = prop.getCppIdentifier();
273282
const name = prop.name;
274283
stream.write(`assign(${id}, params, "${name}");\n`);
275284
}
285+
286+
if (optionalParams) {
287+
stream.write('}');
288+
}
276289
}
277290

278291
stream.write('}\n\n');

ReactCommon/hermes/inspector/tools/msggen/src/index.js

+17-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const proto = mergeDomains(standard, custom);
4141
function parseDomains(
4242
domainObjs: Array<any>,
4343
ignoreExperimental: boolean,
44+
includeExperimental: Set<string>,
4445
): Descriptor {
4546
const desc = {
4647
types: [],
@@ -59,7 +60,12 @@ function parseDomains(
5960
}
6061

6162
for (const commandObj of obj.commands || []) {
62-
const command = Command.create(domain, commandObj, ignoreExperimental);
63+
const command = Command.create(
64+
domain,
65+
commandObj,
66+
!includeExperimental.has(`${domain}.${commandObj.name}`) &&
67+
ignoreExperimental,
68+
);
6369
if (command) {
6470
desc.commands.push(command);
6571
}
@@ -199,18 +205,27 @@ function main() {
199205
.boolean('e')
200206
.alias('e', 'ignore-experimental')
201207
.describe('e', 'ignore experimental commands, props, and types')
208+
.alias('i', 'include-experimental')
209+
.describe('i', 'experimental commands to include')
202210
.alias('r', 'roots')
203211
.describe('r', 'path to a file listing root types, events, and commands')
204212
.nargs('r', 1)
205213
.demandCommand(2, 2).argv;
206214

207215
const ignoreExperimental = !!args.e;
216+
const includeExperimental = new Set(
217+
typeof args.i === 'string' ? args.i.split(',') : [],
218+
);
208219
const [headerPath, implPath] = args._;
209220

210221
const headerStream = fs.createWriteStream(headerPath);
211222
const implStream = fs.createWriteStream(implPath);
212223

213-
const desc = parseDomains(proto.domains, ignoreExperimental);
224+
const desc = parseDomains(
225+
proto.domains,
226+
ignoreExperimental,
227+
includeExperimental,
228+
);
214229
const graph = buildGraph(desc);
215230
const roots = parseRoots(desc, String(args.roots));
216231

ReactCommon/hermes/inspector/tools/msggen/yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -2434,10 +2434,10 @@ detect-newline@^3.0.0:
24342434
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
24352435
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
24362436

2437-
2438-
version "0.0.730699"
2439-
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.730699.tgz#4d18f6a9b7fb7cf3f1ffe73bfe14aad66cf3b2ef"
2440-
integrity sha512-dprBpuPzVIIXXL6GevzhvWe2wg836h3d5hY+n6IzzHbKLsUh6QlVmcIy15za0J3MhDFbmEH60s6uYsrw/tgBbw==
2437+
2438+
version "0.0.959523"
2439+
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.959523.tgz#a7ce62c6b88876081fe5bec866f70e467bc021ba"
2440+
integrity sha512-taOcAND/oJA5FhJD2I3RA+I8RPdrpPJWwvMBPzTq7Sugev1xTOG3lgtlSfkh5xkjTYw0Ti2CRQq016goFHMoPQ==
24412441

24422442
diff-sequences@^26.6.2:
24432443
version "26.6.2"

0 commit comments

Comments
 (0)