Assign auto-incrementing execution context IDs (#43064)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/43064

Changelog: [Internal]

Aligns React Native's CDP backend with V8's behaviour of assigning a sequential ID (here unique within a given PageTarget) to each execution context.

Reviewed By: huntie

Differential Revision: D53776531

fbshipit-source-id: 950599c323f416e8180e42281d94ae9c00f15fb0
This commit is contained in:
Moti Zilberman
2024-02-16 11:16:41 -08:00
committed by Facebook GitHub Bot
parent e34e7d75b3
commit 828ad04cef
7 changed files with 74 additions and 15 deletions
@@ -0,0 +1,19 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "ExecutionContextManager.h"
#include <cassert>
namespace facebook::react::jsinspector_modern {
int32_t ExecutionContextManager::allocateExecutionContextId() {
assert(nextExecutionContextId_ != INT32_MAX);
return nextExecutionContextId_++;
}
} // namespace facebook::react::jsinspector_modern
@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cinttypes>
namespace facebook::react::jsinspector_modern {
/**
* Generates unique execution context IDs.
*/
class ExecutionContextManager {
public:
int32_t allocateExecutionContextId();
private:
int32_t nextExecutionContextId_{1};
};
} // namespace facebook::react::jsinspector_modern
@@ -13,15 +13,20 @@
namespace facebook::react::jsinspector_modern {
std::shared_ptr<InstanceTarget> InstanceTarget::create(
std::shared_ptr<ExecutionContextManager> executionContextManager,
InstanceTargetDelegate& delegate,
VoidExecutor executor) {
std::shared_ptr<InstanceTarget> instanceTarget{new InstanceTarget(delegate)};
std::shared_ptr<InstanceTarget> instanceTarget{
new InstanceTarget(executionContextManager, delegate)};
instanceTarget->setExecutor(executor);
return instanceTarget;
}
InstanceTarget::InstanceTarget(InstanceTargetDelegate& delegate)
: delegate_(delegate) {
InstanceTarget::InstanceTarget(
std::shared_ptr<ExecutionContextManager> executionContextManager,
InstanceTargetDelegate& delegate)
: delegate_(delegate),
executionContextManager_(std::move(executionContextManager)) {
(void)delegate_;
}
@@ -51,8 +56,7 @@ RuntimeTarget& InstanceTarget::registerRuntime(
assert(!currentRuntime_ && "Only one Runtime allowed");
currentRuntime_ = RuntimeTarget::create(
ExecutionContextDescription{
// TODO: IDs should be unique within the current Page.
.id = 1,
.id = executionContextManager_->allocateExecutionContextId(),
.origin = "",
.name = "main",
.uniqueId = std::nullopt},
@@ -7,6 +7,7 @@
#pragma once
#include "ExecutionContextManager.h"
#include "RuntimeTarget.h"
#include "ScopedExecutor.h"
#include "SessionState.h"
@@ -46,6 +47,7 @@ class InstanceTarget : public EnableExecutorFromThis<InstanceTarget> {
public:
/**
* Constructs a new InstanceTarget.
* \param executionContextManager Assigns unique execution context IDs.
* \param delegate The object that will receive events from this target.
* The caller is responsible for ensuring that the delegate outlives this
* object.
@@ -54,6 +56,7 @@ class InstanceTarget : public EnableExecutorFromThis<InstanceTarget> {
* executor will not be called after the InstanceTarget is destroyed.
*/
static std::shared_ptr<InstanceTarget> create(
std::shared_ptr<ExecutionContextManager> executionContextManager,
InstanceTargetDelegate& delegate,
VoidExecutor executor);
@@ -76,15 +79,19 @@ class InstanceTarget : public EnableExecutorFromThis<InstanceTarget> {
/**
* Constructs a new InstanceTarget. The caller must call setExecutor
* immediately afterwards.
* \param executionContextManager Assigns unique execution context IDs.
* \param delegate The object that will receive events from this target.
* The caller is responsible for ensuring that the delegate outlives this
* object.
*/
InstanceTarget(InstanceTargetDelegate& delegate);
InstanceTarget(
std::shared_ptr<ExecutionContextManager> executionContextManager,
InstanceTargetDelegate& delegate);
InstanceTargetDelegate& delegate_;
std::shared_ptr<RuntimeTarget> currentRuntime_{nullptr};
WeakList<InstanceAgent> agents_;
std::shared_ptr<ExecutionContextManager> executionContextManager_;
};
} // namespace facebook::react::jsinspector_modern
@@ -107,7 +107,9 @@ std::shared_ptr<PageTarget> PageTarget::create(
return pageTarget;
}
PageTarget::PageTarget(PageTargetDelegate& delegate) : delegate_(delegate) {}
PageTarget::PageTarget(PageTargetDelegate& delegate)
: delegate_(delegate),
executionContextManager_{std::make_shared<ExecutionContextManager>()} {}
std::unique_ptr<ILocalConnection> PageTarget::connect(
std::unique_ptr<IRemoteConnection> connectionToFrontend,
@@ -132,8 +134,8 @@ PageTargetDelegate::~PageTargetDelegate() {}
InstanceTarget& PageTarget::registerInstance(InstanceTargetDelegate& delegate) {
assert(!currentInstance_ && "Only one instance allowed");
currentInstance_ =
InstanceTarget::create(delegate, makeVoidExecutor(executorFromThis()));
currentInstance_ = InstanceTarget::create(
executionContextManager_, delegate, makeVoidExecutor(executorFromThis()));
sessions_.forEach(
[currentInstance = &*currentInstance_](PageTargetSession& session) {
session.setCurrentInstance(currentInstance);
@@ -7,6 +7,7 @@
#pragma once
#include "ExecutionContextManager.h"
#include "ScopedExecutor.h"
#include "WeakList.h"
@@ -166,6 +167,10 @@ class JSINSPECTOR_EXPORT PageTarget
PageTargetDelegate& delegate_;
WeakList<PageTargetSession> sessions_;
PageTargetController controller_{*this};
// executionContextManager_ is a shared_ptr to guarantee its validity while
// the InstanceTarget is alive (just in case the InstanceTarget ends up
// briefly outliving the PageTarget, which it generally shouldn't).
std::shared_ptr<ExecutionContextManager> executionContextManager_;
std::shared_ptr<InstanceTarget> currentInstance_{nullptr};
inline PageTargetDelegate& getDelegate() {
@@ -211,12 +211,11 @@ TYPED_TEST(JsiIntegrationPortableTest, ExecutionContextNotifications) {
})")))
.RetiresOnSaturation();
// TODO: Each new execution context should receive a new ID.
EXPECT_CALL(this->fromPage(), onMessage(JsonEq(R"({
"method": "Runtime.executionContextCreated",
"params": {
"context": {
"id": 1,
"id": 2,
"origin": "",
"name": "main"
}
@@ -226,11 +225,10 @@ TYPED_TEST(JsiIntegrationPortableTest, ExecutionContextNotifications) {
// Simulate a reload triggered by the app (not by the debugger).
this->reload();
// TODO: Each new execution context should receive a new ID.
EXPECT_CALL(this->fromPage(), onMessage(JsonEq(R"({
"method": "Runtime.executionContextDestroyed",
"params": {
"executionContextId": 1
"executionContextId": 2
}
})")))
.RetiresOnSaturation();
@@ -239,12 +237,11 @@ TYPED_TEST(JsiIntegrationPortableTest, ExecutionContextNotifications) {
"method": "Runtime.executionContextsCleared"
})")))
.RetiresOnSaturation();
// TODO: Each new execution context should receive a new ID.
EXPECT_CALL(this->fromPage(), onMessage(JsonEq(R"({
"method": "Runtime.executionContextCreated",
"params": {
"context": {
"id": 1,
"id": 3,
"origin": "",
"name": "main"
}