Skip to content

Commit

Permalink
Implement Runtime.releaseObject and releaseObjectGroup (#46032)
Browse files Browse the repository at this point in the history
Summary:

Changelog: [Internal]

Implements the [`Runtime.releaseObject`](https://cdpstatus.reactnative.dev/devtools-protocol/tot/Runtime#method-releaseObject) and [`Runtime.releaseObjectGroup`](https://cdpstatus.reactnative.dev/devtools-protocol/tot/Runtime#method-releaseObjectGroup) CDP methods. These are used by CDT in a few places to release inspected objects (e.g. as part of the [popover](https://github.com/facebookexperimental/rn-chrome-devtools-frontend/blob/7b143e5d05a102c8c9cc7e282bab7b0751f75d61/front_end/panels/sources/DebuggerPlugin.ts#L766) feature), which is important to prevent memory leaks in long-running Fusebox sessions.

Reviewed By: dannysu, robhogan

Differential Revision: D61280394
  • Loading branch information
hoxyq authored and facebook-github-bot committed Oct 9, 2024
1 parent 3102a58 commit 0d84377
Showing 1 changed file with 130 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,136 @@ TYPED_TEST(JsiIntegrationHermesTest, FunctionDescriptionIncludesName) {
})");
}

TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObject) {
this->connect();

InSequence s;

// Create a remote object.
auto objectInfo = this->expectMessageFromPage(JsonParsed(AllOf(
AtJsonPtr("/id", 1),
AtJsonPtr("/result/result/type", "object"),
AtJsonPtr("/result/result/objectId", Not(IsEmpty())))));
this->toPage_->sendMessage(R"({
"id": 1,
"method": "Runtime.evaluate",
"params": {"expression": "[]"}
})");

ASSERT_TRUE(objectInfo->has_value());
auto objectId = objectInfo->value()["result"]["result"]["objectId"];

// Ensure we can get the properties of the object.
this->expectMessageFromPage(JsonParsed(
AllOf(AtJsonPtr("/id", 2), AtJsonPtr("/result/result", SizeIs(Gt(0))))));
this->toPage_->sendMessage(sformat(
R"({{
"id": 2,
"method": "Runtime.getProperties",
"params": {{"objectId": {}, "ownProperties": true}}
}})",
folly::toJson(objectId)));

// Release the object.
this->expectMessageFromPage(JsonEq(R"({
"id": 3,
"result": {}
})"));
this->toPage_->sendMessage(sformat(
R"({{
"id": 3,
"method": "Runtime.releaseObject",
"params": {{"objectId": {}, "ownProperties": true}}
}})",
folly::toJson(objectId)));

// Getting properties for a released object results in an error.
this->expectMessageFromPage(
JsonParsed(AllOf(AtJsonPtr("/id", 4), AtJsonPtr("/error/code", -32000))));
this->toPage_->sendMessage(sformat(
R"({{
"id": 4,
"method": "Runtime.getProperties",
"params": {{"objectId": {}, "ownProperties": true}}
}})",
folly::toJson(objectId)));

// Releasing an already released object is an error.
this->expectMessageFromPage(
JsonParsed(AllOf(AtJsonPtr("/id", 5), AtJsonPtr("/error/code", -32000))));
this->toPage_->sendMessage(sformat(
R"({{
"id": 5,
"method": "Runtime.releaseObject",
"params": {{"objectId": {}, "ownProperties": true}}
}})",
folly::toJson(objectId)));
}

TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObjectGroup) {
this->connect();

InSequence s;

// Create a remote object.
auto objectInfo = this->expectMessageFromPage(JsonParsed(AllOf(
AtJsonPtr("/id", 1),
AtJsonPtr("/result/result/type", "object"),
AtJsonPtr("/result/result/objectId", Not(IsEmpty())))));
this->toPage_->sendMessage(R"({
"id": 1,
"method": "Runtime.evaluate",
"params": {"expression": "[]", "objectGroup": "foo"}
})");

ASSERT_TRUE(objectInfo->has_value());
auto objectId = objectInfo->value()["result"]["result"]["objectId"];

// Ensure we can get the properties of the object.
this->expectMessageFromPage(JsonParsed(
AllOf(AtJsonPtr("/id", 2), AtJsonPtr("/result/result", SizeIs(Gt(0))))));
this->toPage_->sendMessage(sformat(
R"({{
"id": 2,
"method": "Runtime.getProperties",
"params": {{"objectId": {}, "ownProperties": true}}
}})",
folly::toJson(objectId)));

// Release the object group containing our object.
this->expectMessageFromPage(JsonEq(R"({
"id": 3,
"result": {}
})"));
this->toPage_->sendMessage(R"({
"id": 3,
"method": "Runtime.releaseObjectGroup",
"params": {"objectGroup": "foo"}
})");

// Getting properties for a released object results in an error.
this->expectMessageFromPage(
JsonParsed(AllOf(AtJsonPtr("/id", 4), AtJsonPtr("/error/code", -32000))));
this->toPage_->sendMessage(sformat(
R"({{
"id": 4,
"method": "Runtime.getProperties",
"params": {{"objectId": {}, "ownProperties": true}}
}})",
folly::toJson(objectId)));

// Releasing an already released object group is a no-op.
this->expectMessageFromPage(JsonEq(R"({
"id": 5,
"result": {}
})"));
this->toPage_->sendMessage(R"({
"id": 5,
"method": "Runtime.releaseObjectGroup",
"params": {"objectGroup": "foo"}
})");
}

#pragma endregion // AllHermesVariants

} // namespace facebook::react::jsinspector_modern

0 comments on commit 0d84377

Please sign in to comment.