[ Service ] Add support for isolate-based RPCs to dart_runtime_service_vm

This change adds initial support for working with isolates in the Dart
Runtime Service and its backends.

The new `IsolateManager` base class tracks the set of active isolates
and their lifecycle events. The `VmIsolateManager` extends this class,
adding support specific to interacting with isolates within the Dart VM.

TEST=vm/cc/DartAPI_InvokeVMServiceMethod*_Exp

Change-Id: I3dfa298722c40dbdfdd58105cc78f31d058dd7a2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/486560
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Jessy Yameogo <yjessy@google.com>
This commit is contained in:
Ben Konyi
2026-03-12 09:08:14 -07:00
committed by Commit Queue
parent b54f4b718e
commit a8aba7fab8
22 changed files with 902 additions and 75 deletions
+50 -15
View File
@@ -110,8 +110,14 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri,
// vm/cc tests to randomly time out due to inability to shut service-isolate
// down.
// Issue(https://dartbug.com/37741):
if ((strcmp(run_filter, "DartAPI_InvokeVMServiceMethod") != 0) &&
(strcmp(run_filter, "DartAPI_InvokeVMServiceMethod_Loop") != 0)) {
const bool is_service_test =
(strcmp(run_filter, "DartAPI_InvokeVMServiceMethod") == 0) ||
(strcmp(run_filter, "DartAPI_InvokeVMServiceMethod_Loop") == 0);
const bool is_exp_service_test =
(strcmp(run_filter, "DartAPI_InvokeVMServiceMethod_Exp") == 0) ||
(strcmp(run_filter, "DartAPI_InvokeVMServiceMethod_Loop_Exp") == 0);
if (!is_service_test && !is_exp_service_test) {
return nullptr;
}
@@ -122,21 +128,50 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri,
packages_config, /*app_snapshot=*/nullptr,
/*isolate_run_app_snapshot=*/false);
const uint8_t* kernel_buffer = nullptr;
intptr_t kernel_buffer_size = 0;
bin::dfe.Init();
bin::dfe.LoadPlatform(&kernel_buffer, &kernel_buffer_size);
RELEASE_ASSERT(kernel_buffer != nullptr);
flags->load_vmservice_library = true;
flags->is_service_isolate = true;
isolate_group_data->SetKernelBufferUnowned(
const_cast<uint8_t*>(kernel_buffer), kernel_buffer_size);
isolate = Dart_CreateIsolateGroupFromKernel(
script_uri, DART_VM_SERVICE_ISOLATE_NAME, kernel_buffer,
kernel_buffer_size, flags, isolate_group_data, /*isolate_data=*/nullptr,
error);
#if defined(EXPERIMENTAL_VM_SERVICE)
if (is_exp_service_test) {
ASSERT(!is_service_test);
const uint8_t* isolate_snapshot_data = nullptr;
const uint8_t* isolate_snapshot_instructions = nullptr;
bin::VmService::enable_experimental_vm_service = true;
auto [app_snapshot, script_name] = bin::Snapshot::TryReadSDKSnapshot(
"dart_runtime_service_vm.dart.snapshot");
if (app_snapshot == nullptr) {
return nullptr;
}
const uint8_t* ignore_vm_snapshot_data;
const uint8_t* ignore_vm_snapshot_instructions;
app_snapshot->SetBuffers(
&ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions,
&isolate_snapshot_data, &isolate_snapshot_instructions);
isolate = Dart_CreateIsolateGroup(
script_uri, DART_VM_SERVICE_ISOLATE_NAME, isolate_snapshot_data,
isolate_snapshot_instructions, flags, isolate_group_data,
/*isolate_data=*/nullptr, error);
}
#endif // defined(EXPERIMENTAL_VM_SERVICE)
if (is_service_test) {
ASSERT(!is_exp_service_test);
const uint8_t* kernel_buffer = nullptr;
intptr_t kernel_buffer_size = 0;
bin::dfe.Init();
bin::dfe.LoadPlatform(&kernel_buffer, &kernel_buffer_size);
RELEASE_ASSERT(kernel_buffer != nullptr);
isolate_group_data->SetKernelBufferUnowned(
const_cast<uint8_t*>(kernel_buffer), kernel_buffer_size);
isolate = Dart_CreateIsolateGroupFromKernel(
script_uri, DART_VM_SERVICE_ISOLATE_NAME, kernel_buffer,
kernel_buffer_size, flags, isolate_group_data, /*isolate_data=*/nullptr,
error);
}
if (isolate == nullptr) {
delete isolate_group_data;
return nullptr;
+24 -4
View File
@@ -10559,11 +10559,11 @@ TEST_CASE(DartAPI_InvokeImportedFunction) {
"NoSuchMethodError: No top-level method 'getCurrentTag' declared.");
}
TEST_CASE(DartAPI_InvokeVMServiceMethod) {
static void InvokeVMServiceMethodCommon() {
char buffer[1024];
Utils::SNPrint(buffer, sizeof(buffer),
R"({
"jsonrpc": 2.0,
"jsonrpc": "2.0",
"id": "foo",
"method": "getVM",
"params": { }
@@ -10618,6 +10618,16 @@ TEST_CASE(DartAPI_InvokeVMServiceMethod) {
EXPECT(result == Dart_True());
}
TEST_CASE(DartAPI_InvokeVMServiceMethod) {
InvokeVMServiceMethodCommon();
}
#if defined(EXPERIMENTAL_VM_SERVICE)
TEST_CASE(DartAPI_InvokeVMServiceMethod_Exp) {
InvokeVMServiceMethodCommon();
}
#endif // defined(EXPERIMENTAL_VM_SERVICE)
static Monitor* loop_test_lock = new Monitor();
static bool loop_test_exit = false;
static bool loop_reset_count = false;
@@ -10630,7 +10640,7 @@ static void InvokeServiceMessages(uword param) {
char buffer[1024];
Utils::SNPrint(buffer, sizeof(buffer),
R"({
"jsonrpc": 2.0,
"jsonrpc": "2.0",
"id": "foo",
"method": "getVM",
"params": { }
@@ -10661,7 +10671,7 @@ static void InvokeServiceMessages(uword param) {
} while (count < 100);
}
TEST_CASE(DartAPI_InvokeVMServiceMethod_Loop) {
static void InvokeVMServiceMethodLoopCommon() {
{
MonitorLocker ml(loop_test_lock);
loop_test_exit = false;
@@ -10673,6 +10683,16 @@ TEST_CASE(DartAPI_InvokeVMServiceMethod_Loop) {
}
OSThread::Join(loop_test_join_id);
}
TEST_CASE(DartAPI_InvokeVMServiceMethod_Loop) {
InvokeVMServiceMethodLoopCommon();
}
#if defined(EXPERIMENTAL_VM_SERVICE)
TEST_CASE(DartAPI_InvokeVMServiceMethod_Loop_Exp) {
InvokeVMServiceMethodLoopCommon();
}
#endif // defined(EXPERIMENTAL_VM_SERVICE)
#endif // !defined(PRODUCT)
static void HandleResponse(Dart_Port dest_port_id, Dart_CObject* message) {
+23 -15
View File
@@ -578,12 +578,18 @@ void ServiceIsolate::Shutdown() {
void ServiceIsolate::BootVmServiceLibrary() {
Thread* thread = Thread::Current();
const Library& vmservice_library =
Library::Handle(Library::LookupLibrary(thread, Symbols::DartVMService()));
ASSERT(!vmservice_library.IsNull());
Library& lib =
Library::Handle(thread->isolate_group()->object_store()->root_library());
const String& boot_function_name = String::Handle(String::New("boot"));
const Function& boot_function = Function::Handle(
vmservice_library.LookupFunctionAllowPrivate(boot_function_name));
Function& boot_function =
Function::Handle(lib.LookupFunctionAllowPrivate(boot_function_name));
if (boot_function.IsNull()) {
lib ^= Library::LookupLibrary(thread, Symbols::DartVMService());
ASSERT(!lib.IsNull());
boot_function ^= lib.LookupFunctionAllowPrivate(boot_function_name);
}
ASSERT(!boot_function.IsNull());
const Object& result = Object::Handle(
DartEntry::InvokeFunction(boot_function, Object::empty_array()));
@@ -608,16 +614,18 @@ void ServiceIsolate::RegisterRunningIsolates(
ASSERT(thread->isolate()->is_service_isolate());
// Obtain "_registerIsolate" function to call.
const String& library_url = Symbols::DartVMService();
ASSERT(!library_url.IsNull());
const Library& library =
Library::Handle(zone, Library::LookupLibrary(thread, library_url));
ASSERT(!library.IsNull());
const String& function_name =
String::Handle(zone, String::New("_registerIsolate"));
ASSERT(!function_name.IsNull());
const Function& register_function_ =
Function::Handle(zone, library.LookupFunctionAllowPrivate(function_name));
Library& lib =
Library::Handle(thread->isolate_group()->object_store()->root_library());
const String& function_name = String::Handle(String::New("_registerIsolate"));
Function& register_function_ =
Function::Handle(lib.LookupFunctionAllowPrivate(function_name));
if (register_function_.IsNull()) {
lib ^= Library::LookupLibrary(thread, Symbols::DartVMService());
ASSERT(!lib.IsNull());
register_function_ ^= lib.LookupFunctionAllowPrivate(function_name);
}
ASSERT(!register_function_.IsNull());
Integer& port_int = Integer::Handle(zone);