[VM/Service] Use the resident frontend server for expression evaluation when it's available

TEST=tests added to pkg/vm_service/test

CoreLibraryReviewExempt: This CL does not include any core library API
changes, only VM Service implementation changes within
sdk/lib/vmservice/.
Change-Id: I191bb7f3ec3abf1f42405a43ce72016796bc43f9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394523
Reviewed-by: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index 3bcc305..e2df849 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -1018,6 +1018,20 @@
     });
   });
 
+  test('running dartdev is a prerequisite for passing --resident', () async {
+    p = project(mainSrc: 'void main() {}');
+    final result = await p.run(['--resident', p.relativeFilePath]);
+
+    expect(result.exitCode, 255);
+    expect(
+      result.stderr,
+      contains(
+        'Passing the `--resident` flag to `dart` is invalid. It must be passed '
+        'to `dart run`.',
+      ),
+    );
+  });
+
   test(
       'passing --resident is a prerequisite for passing --resident-compiler-info-file',
       () async {
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 2b1387c..c699f7f 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -115,6 +115,7 @@
     bool pauseOnUnhandledExceptions,
     bool testeeControlsServer,
     bool useAuthToken,
+    bool shouldTesteeBeLaunchedWithDartRunResident,
     List<String>? experiments,
     List<String>? extraArgs,
   ) {
@@ -124,6 +125,7 @@
       pauseOnUnhandledExceptions,
       testeeControlsServer,
       useAuthToken,
+      shouldTesteeBeLaunchedWithDartRunResident,
       experiments,
       extraArgs,
     );
@@ -135,6 +137,7 @@
     bool pauseOnUnhandledExceptions,
     bool testeeControlsServer,
     bool useAuthToken,
+    bool shouldTesteeBeLaunchedWithDartRunResident,
     List<String>? experiments,
     List<String>? extraArgs,
   ) {
@@ -165,7 +168,12 @@
     if (!testeeControlsServer) {
       fullArgs.add('--enable-vm-service:0');
     }
+
+    if (shouldTesteeBeLaunchedWithDartRunResident) {
+      fullArgs.addAll(['run', '--resident']);
+    }
     fullArgs.addAll(args);
+
     return _spawnCommon(dartExecutable, fullArgs, <String, String>{});
   }
 
@@ -194,6 +202,7 @@
     bool pauseOnUnhandledExceptions,
     bool testeeControlsServer,
     bool useAuthToken,
+    bool shouldTesteeBeLaunchedWithDartRunResident,
     List<String>? experiments,
     List<String>? extraArgs,
   ) {
@@ -203,6 +212,7 @@
       pauseOnUnhandledExceptions,
       testeeControlsServer,
       useAuthToken,
+      shouldTesteeBeLaunchedWithDartRunResident,
       experiments,
       extraArgs,
     ).then((p) {
@@ -272,6 +282,7 @@
     bool pauseOnUnhandledExceptions = false,
     bool testeeControlsServer = false,
     bool useAuthToken = false,
+    bool shouldTesteeBeLaunchedWithDartRunResident = false,
     bool allowForNonZeroExitCode = false,
     VmServiceFactory serviceFactory = VmService.defaultFactory,
   }) async {
@@ -286,6 +297,7 @@
         pauseOnUnhandledExceptions,
         testeeControlsServer,
         useAuthToken,
+        shouldTesteeBeLaunchedWithDartRunResident,
         experiments,
         extraArgs,
       )
@@ -410,6 +422,9 @@
   bool pauseOnUnhandledExceptions = false,
   bool testeeControlsServer = false,
   bool useAuthToken = false,
+
+  /// If [true], `dart run --resident` will be used to launch the testee.
+  bool shouldTesteeBeLaunchedWithDartRunResident = false,
   bool allowForNonZeroExitCode = false,
   List<String>? experiments,
   List<String>? extraArgs,
@@ -435,6 +450,8 @@
       pauseOnUnhandledExceptions: pauseOnUnhandledExceptions,
       testeeControlsServer: testeeControlsServer,
       useAuthToken: useAuthToken,
+      shouldTesteeBeLaunchedWithDartRunResident:
+          shouldTesteeBeLaunchedWithDartRunResident,
       allowForNonZeroExitCode: allowForNonZeroExitCode,
     );
   }
diff --git a/pkg/vm_service/test/eval_test.dart b/pkg/vm_service/test/eval_test.dart
index 798ef56..60c65fb 100644
--- a/pkg/vm_service/test/eval_test.dart
+++ b/pkg/vm_service/test/eval_test.dart
@@ -2,118 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:developer';
-import 'package:test/test.dart';
-import 'package:vm_service/vm_service.dart';
-import 'common/service_test_common.dart';
 import 'common/test_helper.dart';
-
-int globalVar = 100;
-
-class MyClass {
-  static int staticVar = 1000;
-
-  static void method(int value) {
-    debugger();
-  }
-}
-
-class _MyClass {
-  void foo() {
-    debugger();
-  }
-}
-
-void testFunction() {
-  int i = 0;
-  while (true) {
-    if (++i % 100000000 == 0) {
-      MyClass.method(10000);
-      _MyClass().foo();
-    }
-  }
-}
-
-final tests = <IsolateTest>[
-  hasStoppedAtBreakpoint,
-
-// Evaluate against library, class, and instance.
-  (VmService service, IsolateRef isolateRef) async {
-    final isolateId = isolateRef.id!;
-    final isolate = await service.getIsolate(isolateId);
-    final stack = await service.getStack(isolateId);
-
-    // Make sure we are in the right place.
-    expect(stack.frames!.length, greaterThanOrEqualTo(2));
-    expect(stack.frames![0].function!.name, 'method');
-    expect((stack.frames![0].function!.owner as ClassRef).name, 'MyClass');
-
-    final LibraryRef lib = isolate.rootLib!;
-    final ClassRef cls = stack.frames![0].function!.owner;
-    final InstanceRef instance = stack.frames![0].vars![0].value;
-
-    dynamic result =
-        await service.evaluate(isolateId, lib.id!, 'globalVar + 5');
-    print(result);
-    expect(result.valueAsString, '105');
-
-    await expectError(
-      () => service.evaluate(isolateId, lib.id!, 'globalVar + staticVar + 5'),
-    );
-
-    result =
-        await service.evaluate(isolateId, cls.id!, 'globalVar + staticVar + 5');
-    print(result);
-    expect(result.valueAsString, '1105');
-
-    await expectError(() => service.evaluate(isolateId, cls.id!, 'this + 5'));
-
-    result = await service.evaluate(isolateId, instance.id!, 'this + 5');
-    print(result);
-    expect(result.valueAsString, '10005');
-
-    await expectError(
-      () => service.evaluate(isolateId, instance.id!, 'this + frog'),
-    );
-  },
-  resumeIsolate,
-  hasStoppedAtBreakpoint,
-  (VmService service, IsolateRef isolate) async {
-    final isolateId = isolate.id!;
-    final stack = await service.getStack(isolateId);
-
-    // Make sure we are in the right place.
-    expect(stack.frames!.length, greaterThanOrEqualTo(2));
-    expect(stack.frames![0].function!.name, 'foo');
-    expect((stack.frames![0].function!.owner as ClassRef).name, '_MyClass');
-
-    final ClassRef cls = stack.frames![0].function!.owner;
-
-    final InstanceRef result =
-        await service.evaluate(isolateId, cls.id!, '1+1') as InstanceRef;
-    print(result);
-    expect(result.valueAsString, '2');
-  }
-];
-
-Future<void> expectError(func) async {
-  bool gotException = false;
-  dynamic result;
-  try {
-    result = await func();
-    fail('Failed to throw');
-  } on RPCError catch (e) {
-    expect(e.code, 113); // Compile time error.
-    gotException = true;
-  }
-  if (result?.type != 'Error') {
-    expect(gotException, true); // dart2 semantics
-  }
-}
+import 'eval_test_common.dart';
 
 void main([args = const <String>[]]) => runIsolateTests(
       args,
-      tests,
+      evalTests,
       'eval_test.dart',
-      testeeConcurrent: testFunction,
+      testeeConcurrent: testeeMain,
     );
diff --git a/pkg/vm_service/test/eval_test_common.dart b/pkg/vm_service/test/eval_test_common.dart
new file mode 100644
index 0000000..7b3b33a
--- /dev/null
+++ b/pkg/vm_service/test/eval_test_common.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/service_test_common.dart';
+
+int globalVar = 100;
+
+class MyClass {
+  static int staticVar = 1000;
+
+  static void method(int value) {
+    debugger();
+  }
+}
+
+class _MyClass {
+  void foo() {
+    debugger();
+  }
+}
+
+void testeeMain() {
+  int i = 0;
+  while (true) {
+    if (++i % 100000000 == 0) {
+      MyClass.method(10000);
+      _MyClass().foo();
+    }
+  }
+}
+
+final evalTests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+
+  // Evaluate against library, class, and instance.
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final stack = await service.getStack(isolateId);
+
+    // Make sure we are in the right place.
+    expect(stack.frames!.length, greaterThanOrEqualTo(2));
+    expect(stack.frames![0].function!.name, 'method');
+    expect((stack.frames![0].function!.owner as ClassRef).name, 'MyClass');
+
+    final LibraryRef lib = isolate.rootLib!;
+    final ClassRef cls = stack.frames![0].function!.owner;
+    final InstanceRef instance = stack.frames![0].vars![0].value;
+
+    dynamic result =
+        await service.evaluate(isolateId, lib.id!, 'globalVar + 5');
+    print(result);
+    expect(result.valueAsString, '105');
+
+    await expectError(
+      () => service.evaluate(isolateId, lib.id!, 'globalVar + staticVar + 5'),
+    );
+
+    result =
+        await service.evaluate(isolateId, cls.id!, 'globalVar + staticVar + 5');
+    print(result);
+    expect(result.valueAsString, '1105');
+
+    await expectError(() => service.evaluate(isolateId, cls.id!, 'this + 5'));
+
+    result = await service.evaluate(isolateId, instance.id!, 'this + 5');
+    print(result);
+    expect(result.valueAsString, '10005');
+
+    await expectError(
+      () => service.evaluate(isolateId, instance.id!, 'this + frog'),
+    );
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolate) async {
+    final isolateId = isolate.id!;
+    final stack = await service.getStack(isolateId);
+
+    // Make sure we are in the right place.
+    expect(stack.frames!.length, greaterThanOrEqualTo(2));
+    expect(stack.frames![0].function!.name, 'foo');
+    expect((stack.frames![0].function!.owner as ClassRef).name, '_MyClass');
+
+    final ClassRef cls = stack.frames![0].function!.owner;
+
+    final InstanceRef result =
+        await service.evaluate(isolateId, cls.id!, '1+1') as InstanceRef;
+    print(result);
+    expect(result.valueAsString, '2');
+  }
+];
+
+Future<void> expectError(Future<Response> Function() func) async {
+  try {
+    await func();
+    fail('Failed to throw');
+  } on RPCError catch (e) {
+    expect(e.code, 113); // Compile time error.
+  }
+}
diff --git a/pkg/vm_service/test/eval_with_resident_compiler_test.dart b/pkg/vm_service/test/eval_with_resident_compiler_test.dart
new file mode 100644
index 0000000..e09565a
--- /dev/null
+++ b/pkg/vm_service/test/eval_with_resident_compiler_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common/test_helper.dart';
+import 'eval_test_common.dart';
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      evalTests,
+      'eval_with_resident_compiler_test.dart',
+      testeeConcurrent: testeeMain,
+      shouldTesteeBeLaunchedWithDartRunResident: true,
+    );
diff --git a/pkg/vm_service/test/evaluate_in_frame_rpc_test.dart b/pkg/vm_service/test/evaluate_in_frame_rpc_test.dart
index f6a68a4..4287d6f 100644
--- a/pkg/vm_service/test/evaluate_in_frame_rpc_test.dart
+++ b/pkg/vm_service/test/evaluate_in_frame_rpc_test.dart
@@ -2,48 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:developer';
-
-import 'package:vm_service/vm_service.dart';
-
-import 'common/service_test_common.dart';
 import 'common/test_helper.dart';
+import 'evaluate_in_frame_rpc_test_common.dart';
 
-void method(int value, _) {
-  debugger();
-}
-
-void testFunction() {
-  int i = 0;
-  while (true) {
-    if (++i % 100000000 == 0) {
-      method(10000, 50);
-    }
-  }
-}
-
-final tests = <IsolateTest>[
-  hasStoppedAtBreakpoint,
-
-// Evaluate against library, class, and instance.
-  (VmService service, IsolateRef isolateRef) async {
-    final isolateId = isolateRef.id!;
-    await evaluateInFrameAndExpect(service, isolateId, 'value', '10000');
-    await evaluateInFrameAndExpect(service, isolateId, '_', '50');
-    await evaluateInFrameAndExpect(service, isolateId, 'value + _', '10050');
-    await evaluateInFrameAndExpect(
-      service,
-      isolateId,
-      'i',
-      '100000000',
-      topFrame: 1,
-    );
-  },
-];
-
-void main([args = const <String>[]]) => runIsolateTests(
+Future<void> main([args = const <String>[]]) => runIsolateTests(
       args,
-      tests,
+      evaluateInFrameRpcTests,
       'evaluate_in_frame_rpc_test.dart',
-      testeeConcurrent: testFunction,
+      testeeConcurrent: testeeMain,
     );
diff --git a/pkg/vm_service/test/evaluate_in_frame_rpc_test_common.dart b/pkg/vm_service/test/evaluate_in_frame_rpc_test_common.dart
new file mode 100644
index 0000000..7f4c01b
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_in_frame_rpc_test_common.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+
+void method(int value, _) {
+  debugger();
+}
+
+void testeeMain() {
+  int i = 0;
+  while (true) {
+    if (++i % 100000000 == 0) {
+      method(10000, 50);
+    }
+  }
+}
+
+final evaluateInFrameRpcTests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+
+// Evaluate against library, class, and instance.
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    await evaluateInFrameAndExpect(service, isolateId, 'value', '10000');
+    await evaluateInFrameAndExpect(service, isolateId, '_', '50');
+    await evaluateInFrameAndExpect(service, isolateId, 'value + _', '10050');
+    await evaluateInFrameAndExpect(
+      service,
+      isolateId,
+      'i',
+      '100000000',
+      topFrame: 1,
+    );
+  },
+];
diff --git a/pkg/vm_service/test/evaluate_in_frame_rpc_with_resident_compiler_test.dart b/pkg/vm_service/test/evaluate_in_frame_rpc_with_resident_compiler_test.dart
new file mode 100644
index 0000000..57f9623
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_in_frame_rpc_with_resident_compiler_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common/test_helper.dart';
+import 'evaluate_in_frame_rpc_test_common.dart';
+
+Future<void> main([args = const <String>[]]) => runIsolateTests(
+      args,
+      evaluateInFrameRpcTests,
+      'evaluate_in_frame_rpc_with_resident_compiler_test.dart',
+      testeeConcurrent: testeeMain,
+      shouldTesteeBeLaunchedWithDartRunResident: true,
+    );
diff --git a/pkg/vm_service/test/evaluate_in_frame_with_scope_test.dart b/pkg/vm_service/test/evaluate_in_frame_with_scope_test.dart
index 80a3243..02eddd4 100644
--- a/pkg/vm_service/test/evaluate_in_frame_with_scope_test.dart
+++ b/pkg/vm_service/test/evaluate_in_frame_with_scope_test.dart
@@ -2,140 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:developer';
-
-import 'package:test/test.dart';
-import 'package:vm_service/vm_service.dart';
-
-import 'common/service_test_common.dart';
 import 'common/test_helper.dart';
-
-// AUTOGENERATED START
-//
-// Update these constants by running:
-//
-// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
-//
-const LINE_A = 33;
-// AUTOGENERATED END
-
-late int thing1;
-late int thing2;
-
-void testeeMain() {
-  thing1 = 3;
-  thing2 = 4;
-  foo(42, 1984);
-}
-
-int foo(x, y) {
-  final local = x + y;
-  debugger(); // LINE_A
-  return local;
-}
-
-final tests = <IsolateTest>[
-  hasStoppedAtBreakpoint,
-  stoppedAtLine(LINE_A),
-  (VmService service, IsolateRef isolateRef) async {
-    final isolateId = isolateRef.id!;
-    final isolate = await service.getIsolate(isolateId);
-    final rootLibId = isolate.rootLib!.id!;
-    final rootLib = await service.getObject(
-      isolateId,
-      rootLibId,
-    ) as Library;
-
-    Future<Field> findField(String name) async {
-      final fieldRef = rootLib.variables!.singleWhere(
-        (v) => v.name == name,
-      );
-      return await service.getObject(isolateId, fieldRef.id!) as Field;
-    }
-
-    final thing1Field = await findField('thing1');
-    final thing1 = thing1Field.staticValue! as InstanceRef;
-    print(thing1);
-
-    final thing2Field = await findField('thing2');
-    final thing2 = thing2Field.staticValue! as InstanceRef;
-    print(thing2);
-
-    await evaluateInFrameAndExpect(
-      service,
-      isolateId,
-      'x + y + a + b',
-      '2033',
-      scope: {
-        'a': thing1.id!,
-        'b': thing2.id!,
-      },
-    );
-
-    await evaluateInFrameAndExpect(
-      service,
-      isolateId,
-      'local + a + b',
-      '2033',
-      scope: {
-        'a': thing1.id!,
-        'b': thing2.id!,
-      },
-    );
-
-    await evaluateInFrameAndExpect(
-      service,
-      isolateId,
-      'x + y',
-      '7',
-      scope: {
-        'x': thing1.id!,
-        'y': thing2.id!,
-      },
-    );
-
-    try {
-      await service.evaluate(
-        isolateId,
-        rootLibId,
-        'x + y',
-        scope: {
-          'x': rootLibId,
-          'y': rootLibId,
-        },
-      );
-      fail('Evaluated against a VM-internal object');
-    } on RPCError catch (e) {
-      expect(e.code, RPCErrorKind.kExpressionCompilationError.code);
-      expect(
-        e.details,
-        contains('Cannot evaluate against a VM-internal object'),
-      );
-    }
-
-    try {
-      await service.evaluate(
-        isolateId,
-        rootLibId,
-        'x + y',
-        scope: {
-          'not&an&identifier': thing1.id!,
-        },
-      );
-      fail('Evaluated with an invalid identifier');
-    } on RPCError catch (e) {
-      expect(e.code, RPCErrorKind.kExpressionCompilationError.code);
-      expect(
-        e.details,
-        contains("invalid 'scope' parameter"),
-      );
-    }
-  },
-];
+import 'evaluate_in_frame_with_scope_test_common.dart';
 
 void main([args = const <String>[]]) => runIsolateTests(
       args,
-      tests,
+      evaluateInFrameWithScopeTests,
       'evaluate_in_frame_with_scope_test.dart',
       testeeConcurrent: testeeMain,
     );
diff --git a/pkg/vm_service/test/evaluate_in_frame_with_scope_test_common.dart b/pkg/vm_service/test/evaluate_in_frame_with_scope_test_common.dart
new file mode 100644
index 0000000..a39dca3
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_in_frame_with_scope_test_common.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 32;
+// AUTOGENERATED END
+
+late int thing1;
+late int thing2;
+
+void testeeMain() {
+  thing1 = 3;
+  thing2 = 4;
+  foo(42, 1984);
+}
+
+int foo(x, y) {
+  final local = x + y;
+  debugger(); // LINE_A
+  return local;
+}
+
+final evaluateInFrameWithScopeTests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    // [isolate.rootLib] refers to the test entrypoint library, which is a
+    // library that imports this file's library. We want a [Library] object that
+    // refers to this file's library itself.
+    final libId = isolate.libraries!
+        .singleWhere(
+          (l) =>
+              l.uri!.endsWith('evaluate_in_frame_with_scope_test_common.dart'),
+        )
+        .id!;
+    final Library lib = (await service.getObject(isolateId, libId)) as Library;
+
+    Future<Field> findField(String name) async {
+      final fieldRef = lib.variables!.singleWhere(
+        (v) => v.name == name,
+      );
+      return await service.getObject(isolateId, fieldRef.id!) as Field;
+    }
+
+    final thing1Field = await findField('thing1');
+    final thing1 = thing1Field.staticValue! as InstanceRef;
+    print(thing1);
+
+    final thing2Field = await findField('thing2');
+    final thing2 = thing2Field.staticValue! as InstanceRef;
+    print(thing2);
+
+    await evaluateInFrameAndExpect(
+      service,
+      isolateId,
+      'x + y + a + b',
+      '2033',
+      scope: {
+        'a': thing1.id!,
+        'b': thing2.id!,
+      },
+    );
+
+    await evaluateInFrameAndExpect(
+      service,
+      isolateId,
+      'local + a + b',
+      '2033',
+      scope: {
+        'a': thing1.id!,
+        'b': thing2.id!,
+      },
+    );
+
+    await evaluateInFrameAndExpect(
+      service,
+      isolateId,
+      'x + y',
+      '7',
+      scope: {
+        'x': thing1.id!,
+        'y': thing2.id!,
+      },
+    );
+
+    try {
+      await service.evaluate(
+        isolateId,
+        libId,
+        'x + y',
+        scope: {
+          'x': libId,
+          'y': libId,
+        },
+      );
+      fail('Evaluated against a VM-internal object');
+    } on RPCError catch (e) {
+      expect(e.code, RPCErrorKind.kExpressionCompilationError.code);
+      expect(
+        e.details,
+        contains('Cannot evaluate against a VM-internal object'),
+      );
+    }
+
+    try {
+      await service.evaluate(
+        isolateId,
+        libId,
+        'x + y',
+        scope: {
+          'not&an&identifier': thing1.id!,
+        },
+      );
+      fail('Evaluated with an invalid identifier');
+    } on RPCError catch (e) {
+      expect(e.code, RPCErrorKind.kExpressionCompilationError.code);
+      expect(
+        e.details,
+        contains("invalid 'scope' parameter"),
+      );
+    }
+  },
+];
diff --git a/pkg/vm_service/test/evaluate_in_frame_with_scope_with_resident_compiler_test.dart b/pkg/vm_service/test/evaluate_in_frame_with_scope_with_resident_compiler_test.dart
new file mode 100644
index 0000000..23a7163
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_in_frame_with_scope_with_resident_compiler_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common/test_helper.dart';
+import 'evaluate_in_frame_with_scope_test_common.dart';
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      evaluateInFrameWithScopeTests,
+      'evaluate_in_frame_with_scope_with_resident_compiler_test.dart',
+      testeeConcurrent: testeeMain,
+      shouldTesteeBeLaunchedWithDartRunResident: true,
+    );
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
index 126ce0a..cb81c22 100644
--- a/pkg/vm_service/test/evaluate_with_scope_test.dart
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -2,82 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:test/test.dart';
-import 'package:vm_service/vm_service.dart';
-
 import 'common/test_helper.dart';
-
-int? thing1;
-int? thing2;
-
-void testeeMain() {
-  thing1 = 3;
-  thing2 = 4;
-}
-
-Future<InstanceRef> evaluate(VmService service, isolate, target, x, y) async =>
-    await service.evaluate(
-      isolate!.id!!,
-      target.id!,
-      'x + y',
-      scope: {'x': x.id!, 'y': y.id!},
-    ) as InstanceRef;
-
-final tests = <IsolateTest>[
-  (VmService service, IsolateRef isolateRef) async {
-    final isolateId = isolateRef.id!;
-    final isolate = await service.getIsolate(isolateId);
-    final Library lib =
-        (await service.getObject(isolateId, isolate.rootLib!.id!)) as Library;
-
-    final Field field1 = (await service.getObject(
-      isolateId,
-      lib.variables!.singleWhere((v) => v.name == 'thing1').id!,
-    )) as Field;
-    final thing1 = await service.getObject(isolateId, field1.staticValue!.id!);
-
-    final Field field2 = (await service.getObject(
-      isolateId,
-      lib.variables!.singleWhere((v) => v.name == 'thing2').id!,
-    )) as Field;
-    final thing2 = await service.getObject(isolateId, field2.staticValue!.id!);
-
-    var result = await evaluate(service, isolate, lib, thing1, thing2);
-    expect(result.valueAsString, equals('7'));
-
-    bool didThrow = false;
-    try {
-      result = await evaluate(service, isolate, lib, lib, lib);
-      print(result);
-    } catch (e) {
-      didThrow = true;
-      expect(
-        e.toString(),
-        contains('Cannot evaluate against a VM-internal object'),
-      );
-    }
-    expect(didThrow, isTrue);
-
-    didThrow = false;
-    try {
-      result = await service.evaluate(
-        isolateId,
-        lib.id!,
-        'x + y',
-        scope: <String, String>{'not&an&id!entifier': thing1.id!},
-      ) as InstanceRef;
-      print(result);
-    } catch (e) {
-      didThrow = true;
-      expect(e.toString(), contains("invalid 'scope' parameter"));
-    }
-    expect(didThrow, isTrue);
-  }
-];
+import 'evaluate_with_scope_test_common.dart';
 
 Future<void> main([args = const <String>[]]) => runIsolateTests(
       args,
-      tests,
+      evaluteWithScopeTests,
       'evaluate_with_scope_test.dart',
       testeeBefore: testeeMain,
     );
diff --git a/pkg/vm_service/test/evaluate_with_scope_test_common.dart b/pkg/vm_service/test/evaluate_with_scope_test_common.dart
new file mode 100644
index 0000000..cf4afde
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_with_scope_test_common.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/test_helper.dart';
+
+int? thing1;
+int? thing2;
+
+void testeeMain() {
+  thing1 = 3;
+  thing2 = 4;
+}
+
+Future<InstanceRef> evaluate(VmService service, isolate, target, x, y) async =>
+    await service.evaluate(
+      isolate!.id!!,
+      target.id!,
+      'x + y',
+      scope: {'x': x.id!, 'y': y.id!},
+    ) as InstanceRef;
+
+final evaluteWithScopeTests = <IsolateTest>[
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    // [isolate.rootLib] refers to the test entrypoint library, which is a
+    // library that imports this file's library. We want a [Library] object that
+    // refers to this file's library itself.
+    final libId = isolate.libraries!
+        .singleWhere(
+          (l) => l.uri!.endsWith('evaluate_with_scope_test_common.dart'),
+        )
+        .id!;
+    final Library lib = (await service.getObject(isolateId, libId)) as Library;
+
+    final Field field1 = (await service.getObject(
+      isolateId,
+      lib.variables!.singleWhere((v) => v.name == 'thing1').id!,
+    )) as Field;
+    final thing1 = await service.getObject(isolateId, field1.staticValue!.id!);
+
+    final Field field2 = (await service.getObject(
+      isolateId,
+      lib.variables!.singleWhere((v) => v.name == 'thing2').id!,
+    )) as Field;
+    final thing2 = await service.getObject(isolateId, field2.staticValue!.id!);
+
+    var result = await evaluate(service, isolate, lib, thing1, thing2);
+    expect(result.valueAsString, equals('7'));
+
+    bool didThrow = false;
+    try {
+      result = await evaluate(service, isolate, lib, lib, lib);
+      print(result);
+    } catch (e) {
+      didThrow = true;
+      expect(
+        e.toString(),
+        contains('Cannot evaluate against a VM-internal object'),
+      );
+    }
+    expect(didThrow, isTrue);
+
+    didThrow = false;
+    try {
+      result = await service.evaluate(
+        isolateId,
+        lib.id!,
+        'x + y',
+        scope: <String, String>{'not&an&id!entifier': thing1.id!},
+      ) as InstanceRef;
+      print(result);
+    } catch (e) {
+      didThrow = true;
+      expect(e.toString(), contains("invalid 'scope' parameter"));
+    }
+    expect(didThrow, isTrue);
+  }
+];
diff --git a/pkg/vm_service/test/evaluate_with_scope_with_resident_compiler_test.dart b/pkg/vm_service/test/evaluate_with_scope_with_resident_compiler_test.dart
new file mode 100644
index 0000000..a7eb33f
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_with_scope_with_resident_compiler_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common/test_helper.dart';
+import 'evaluate_with_scope_test_common.dart';
+
+Future<void> main([args = const <String>[]]) => runIsolateTests(
+      args,
+      evaluteWithScopeTests,
+      'evaluate_with_scope_with_resident_compiler_test.dart',
+      testeeBefore: testeeMain,
+      shouldTesteeBeLaunchedWithDartRunResident: true,
+    );
diff --git a/runtime/bin/dart_embedder_api_impl.cc b/runtime/bin/dart_embedder_api_impl.cc
index 496ab23..a9d666b 100644
--- a/runtime/bin/dart_embedder_api_impl.cc
+++ b/runtime/bin/dart_embedder_api_impl.cc
@@ -102,15 +102,16 @@
 
   Dart_EnterScope();
   // Load embedder specific bits and return.
-  if (!bin::VmService::Setup(config.ip, config.port, config.dev_mode,
-                             config.disable_auth_codes,
-                             config.write_service_info_filename,
-                             /*trace_loading=*/false, config.deterministic,
-                             /*enable_service_port_fallback=*/false,
-                             /*wait_for_dds_to_advertise_service=*/false,
-                             /*serve_devtools=*/false,
-                             /*serve_observatory=*/true,
-                             /*print_dtd=*/false)) {
+  if (!bin::VmService::Setup(
+          config.ip, config.port, config.dev_mode, config.disable_auth_codes,
+          config.write_service_info_filename,
+          /*trace_loading=*/false, config.deterministic,
+          /*enable_service_port_fallback=*/false,
+          /*wait_for_dds_to_advertise_service=*/false,
+          /*serve_devtools=*/false,
+          /*serve_observatory=*/true,
+          /*print_dtd=*/false, /*should_use_resident_compiler=*/false,
+          /*resident_compiler_info_file_path=*/nullptr)) {
     *error = Utils::StrDup(bin::VmService::GetErrorMessage());
     return nullptr;
   }
@@ -149,7 +150,9 @@
                              /*wait_for_dds_to_advertise_service=*/false,
                              /*serve_devtools=*/false,
                              /*serve_observatory=*/true,
-                             /*print_dtd=*/false)) {
+                             /*print_dtd=*/false,
+                             /*should_use_resident_compiler=*/false,
+                             /*resident_compiler_info_file_path=*/nullptr)) {
     *error = Utils::StrDup(bin::VmService::GetErrorMessage());
     return nullptr;
   }
diff --git a/runtime/bin/main_impl.cc b/runtime/bin/main_impl.cc
index 49522df..cd4fab2 100644
--- a/runtime/bin/main_impl.cc
+++ b/runtime/bin/main_impl.cc
@@ -568,7 +568,11 @@
           Options::vm_write_service_info_filename(), Options::trace_loading(),
           Options::deterministic(), Options::enable_service_port_fallback(),
           wait_for_dds_to_advertise_service, serve_devtools,
-          Options::enable_observatory(), Options::print_dtd())) {
+          Options::enable_observatory(), Options::print_dtd(),
+          Options::resident(),
+          Options::resident_compiler_info_file_path() != nullptr
+              ? Options::resident_compiler_info_file_path()
+              : Options::resident_server_info_file_path())) {
     *error = Utils::StrDup(VmService::GetErrorMessage());
     return nullptr;
   }
@@ -1432,6 +1436,16 @@
         "command.\n");
     Platform::Exit(kErrorExitCode);
   }
+
+  if (!ran_dart_dev &&
+      (Options::resident() ||
+       Options::resident_compiler_info_file_path() != nullptr ||
+       Options::resident_server_info_file_path() != nullptr)) {
+    Syslog::PrintErr(
+        "Passing the `--resident` flag to `dart` is invalid. It must be passed "
+        "to `dart run`.\n");
+    Platform::Exit(kErrorExitCode);
+  }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   if (should_run_user_program) {
diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
index 7478e87..5734a09 100644
--- a/runtime/bin/main_options.h
+++ b/runtime/bin/main_options.h
@@ -26,7 +26,11 @@
   V(root_certs_file, root_certs_file)                                          \
   V(root_certs_cache, root_certs_cache)                                        \
   V(namespace, namespc)                                                        \
-  V(write_service_info, vm_write_service_info_filename)
+  V(write_service_info, vm_write_service_info_filename)                        \
+  /* The purpose of these flags is documented in */                            \
+  /* pkg/dartdev/lib/src/commands/compilation_server.dart. */                  \
+  V(resident_server_info_file, resident_server_info_file_path)                 \
+  V(resident_compiler_info_file, resident_compiler_info_file_path)
 
 // As STRING_OPTIONS_LIST but for boolean valued options. The default value is
 // always false, and the presence of the flag switches the value to true.
@@ -53,7 +57,10 @@
   V(serve_devtools, enable_devtools)                                           \
   V(no_serve_observatory, disable_observatory)                                 \
   V(serve_observatory, enable_observatory)                                     \
-  V(print_dtd, print_dtd)
+  V(print_dtd, print_dtd)                                                      \
+  /* The purpose of this flag is documented in */                              \
+  /* pkg/dartdev/lib/src/commands/run.dart. */                                 \
+  V(resident, resident)
 
 // Boolean flags that have a short form.
 #define SHORT_BOOL_OPTIONS_LIST(V)                                             \
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index ae1fb32..833e62b 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -156,7 +156,9 @@
                              /*wait_for_dds_to_advertise_service=*/false,
                              /*serve_devtools=*/false,
                              /*serve_observatory=*/true,
-                             /*print_dtd=*/false)) {
+                             /*print_dtd=*/false,
+                             /*should_use_resident_compiler=*/false,
+                             /*resident_compiler_info_file_path=*/nullptr)) {
     *error = Utils::StrDup(bin::VmService::GetErrorMessage());
     return nullptr;
   }
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 7b7559b..3d6a0c3 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -125,7 +125,9 @@
                       bool wait_for_dds_to_advertise_service,
                       bool serve_devtools,
                       bool serve_observatory,
-                      bool print_dtd) {
+                      bool print_dtd,
+                      bool should_use_resident_compiler,
+                      const char* resident_compiler_info_file_path) {
   Dart_Isolate isolate = Dart_CurrentIsolate();
   ASSERT(isolate != nullptr);
   SetServerAddress("");
@@ -226,6 +228,20 @@
                          print_dtd ? Dart_True() : Dart_False());
   SHUTDOWN_ON_ERROR(result);
 
+  if (should_use_resident_compiler) {
+    Dart_Handle resident_compiler_info_file_path_dart_string = nullptr;
+    if (resident_compiler_info_file_path == nullptr) {
+      resident_compiler_info_file_path_dart_string = Dart_Null();
+    } else {
+      resident_compiler_info_file_path_dart_string =
+          DartUtils::NewString(resident_compiler_info_file_path);
+    }
+    result = Dart_Invoke(
+        library, DartUtils::NewString("_populateResidentCompilerInfoFile"), 1,
+        &resident_compiler_info_file_path_dart_string);
+    SHUTDOWN_ON_ERROR(result);
+  }
+
 // Are we running on Windows?
 #if defined(DART_HOST_OS_WINDOWS)
   Dart_Handle is_windows = Dart_True();
diff --git a/runtime/bin/vmservice_impl.h b/runtime/bin/vmservice_impl.h
index 76b6e0b..71a3309 100644
--- a/runtime/bin/vmservice_impl.h
+++ b/runtime/bin/vmservice_impl.h
@@ -26,7 +26,9 @@
                     bool wait_for_dds_to_advertise_service,
                     bool serve_devtools,
                     bool serve_observatory,
-                    bool print_dtd) {
+                    bool print_dtd,
+                    bool should_use_resident_compiler,
+                    const char* resident_compiler_info_file_path) {
     return false;
   }
 
@@ -42,18 +44,25 @@
 
  private:
 #else   // defined(PRODUCT)
-  static bool Setup(const char* server_ip,
-                    intptr_t server_port,
-                    bool dev_mode_server,
-                    bool auth_codes_disabled,
-                    const char* write_service_info_filename,
-                    bool trace_loading,
-                    bool deterministic,
-                    bool enable_service_port_fallback,
-                    bool wait_for_dds_to_advertise_service,
-                    bool serve_devtools,
-                    bool serve_observatory,
-                    bool print_dtd);
+  static bool Setup(
+      const char* server_ip,
+      intptr_t server_port,
+      bool dev_mode_server,
+      bool auth_codes_disabled,
+      const char* write_service_info_filename,
+      bool trace_loading,
+      bool deterministic,
+      bool enable_service_port_fallback,
+      bool wait_for_dds_to_advertise_service,
+      bool serve_devtools,
+      bool serve_observatory,
+      bool print_dtd,
+      bool should_use_resident_compiler,
+      // If either --resident-compiler-info-file or --resident-server-info-file
+      // was supplied on the command line, the CLI argument should be forwarded
+      // as the argument to this parameter. If neither option was supplied, the
+      // argument to this parameter should be null.
+      const char* resident_compiler_info_file_path);
 
   static void SetNativeResolver();
 
diff --git a/sdk/lib/_internal/vm/bin/vmservice_io.dart b/sdk/lib/_internal/vm/bin/vmservice_io.dart
index fbc0175..b56a4d1 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_io.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
@@ -69,6 +69,23 @@
 @pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
 bool _printDtd = false;
 
+File? _residentCompilerInfoFile = null;
+
+@pragma('vm:entry-point', !const bool.fromEnvironment('dart.vm.product'))
+void _populateResidentCompilerInfoFile(
+  /// If either `--resident-compiler-info-file` or `--resident-server-info-file`
+  /// was supplied on the command line, the CLI argument should be forwarded as
+  /// the argument to this parameter. If neither option was supplied, the
+  /// argument to this parameter should be [null].
+  final String? residentCompilerInfoFilePathArgumentFromCli,
+) {
+  _residentCompilerInfoFile = getResidentCompilerInfoFileConsideringArgsImpl(
+    residentCompilerInfoFilePathArgumentFromCli,
+  );
+}
+
+File? _getResidentCompilerInfoFile() => _residentCompilerInfoFile;
+
 // HTTP server.
 late final Server server;
 
@@ -270,6 +287,9 @@
   VMServiceEmbedderHooks.acceptNewWebSocketConnections =
       webServerAcceptNewWebSocketConnections;
   VMServiceEmbedderHooks.serveObservatory = serveObservatoryCallback;
+  VMServiceEmbedderHooks.getResidentCompilerInfoFile =
+      _getResidentCompilerInfoFile;
+
   server = Server(
     // Always instantiate the vmservice object so that the exit message
     // can be delivered and waiting loaders can be cancelled.
diff --git a/sdk/lib/vmservice/running_isolates.dart b/sdk/lib/vmservice/running_isolates.dart
index d20cdce..e6b8ca7 100644
--- a/sdk/lib/vmservice/running_isolates.dart
+++ b/sdk/lib/vmservice/running_isolates.dart
@@ -80,6 +80,60 @@
   void routeResponse(Message message) {}
 }
 
+// NOTE: The following class is a duplicate of one in
+// 'package:frontend_server/resident_frontend_server_utils.dart'. We are forced
+// to duplicate it because `dart:_vmservice` is not allowed to import
+// `package:frontend_server`.
+
+final class _ResidentCompilerInfo {
+  final String? _sdkHash;
+  final InternetAddress _address;
+  final int _port;
+
+  /// The SDK hash that kernel files compiled using the Resident Frontend
+  /// Compiler associated with this object will be stamped with.
+  String? get sdkHash => _sdkHash;
+
+  /// The address that the Resident Frontend Compiler associated with this
+  /// object is listening from.
+  InternetAddress get address => _address;
+
+  /// The port number that the Resident Frontend Compiler associated with this
+  /// object is listening on.
+  int get port => _port;
+
+  /// Extracts the value associated with a key from [entries], where [entries]
+  /// is a [String] with the format '$key1:$value1 $key2:$value2 $key3:$value3 ...'.
+  static String _extractValueAssociatedWithKey(String entries, String key) =>
+      RegExp(
+        '$key:'
+        r'(\S+)(\s|$)',
+      ).allMatches(entries).first[1]!;
+
+  static _ResidentCompilerInfo fromFile(File file) {
+    final fileContents = file.readAsStringSync();
+
+    return _ResidentCompilerInfo._(
+      sdkHash:
+          fileContents.contains('sdkHash:')
+              ? _extractValueAssociatedWithKey(fileContents, 'sdkHash')
+              : null,
+      address: InternetAddress(
+        _extractValueAssociatedWithKey(fileContents, 'address'),
+      ),
+      port: int.parse(_extractValueAssociatedWithKey(fileContents, 'port')),
+    );
+  }
+
+  _ResidentCompilerInfo._({
+    required String? sdkHash,
+    required int port,
+    required InternetAddress address,
+  }) : _sdkHash = sdkHash,
+       _port = port,
+       _address = address;
+}
+
 /// Class that knows how to orchestrate expression evaluation in dart2 world.
 class _Evaluator {
   _Evaluator(this._message, this._isolate, this._service);
@@ -156,13 +210,49 @@
     throw _CompileExpressionErrorDetails(data['details']);
   }
 
+  // NOTE: The following function is a duplicate of one in
+  // 'package:frontend_server/resident_frontend_server_utils.dart'. We are
+  // forced to duplicate it because `dart:_vmservice` is not allowed to import
+  // `package:frontend_server`.
+
+  /// Sends a compilation [request] to the resident frontend compiler associated
+  /// with [serverInfoFile], and returns the compiler's JSON response.
+  ///
+  /// Throws a [FileSystemException] if [serverInfoFile] cannot be accessed.
+  static Future<Map<String, dynamic>>
+  _sendRequestToResidentFrontendCompilerAndRecieveResponse(
+    String request,
+    File serverInfoFile,
+  ) async {
+    Socket? client;
+    Map<String, dynamic> jsonResponse;
+    final residentCompilerInfo = _ResidentCompilerInfo.fromFile(serverInfoFile);
+
+    try {
+      client = await Socket.connect(
+        residentCompilerInfo.address,
+        residentCompilerInfo.port,
+      );
+      client.write(request);
+      final data = String.fromCharCodes(await client.first);
+      jsonResponse = jsonDecode(data);
+    } catch (e) {
+      jsonResponse = <String, dynamic>{
+        'success': false,
+        'errorMessage': e.toString(),
+      };
+    }
+    client?.destroy();
+    return jsonResponse;
+  }
+
   /// If compilation fails, this method will throw a
   /// [_CompileExpressionErrorDetails] object that will be used to populate the
   /// 'details' field of the response to the evaluation RPC that requested this
   /// compilation to happen.
   Future<String> _compileExpression(
     Map<String, dynamic> buildScopeResponseResult,
-  ) {
+  ) async {
     Client? externalClient = _service._findFirstClientThatHandlesService(
       'compileExpression',
     );
@@ -192,6 +282,7 @@
       compileParams['method'] = method;
     }
     if (externalClient != null) {
+      // Let the external client handle expression compilation.
       final compileExpression = Message.forMethod('compileExpression');
       compileExpression.client = externalClient;
       compileExpression.params.addAll(compileParams);
@@ -221,6 +312,38 @@
               json as Map<String, dynamic>,
             ),
           );
+    } else if (VMServiceEmbedderHooks.getResidentCompilerInfoFile!() != null) {
+      // Compile the expression using the resident compiler.
+      final response =
+          await _sendRequestToResidentFrontendCompilerAndRecieveResponse(
+            jsonEncode({
+              'command': 'compileExpression',
+              'expression': compileParams['expression'],
+              'definitions': compileParams['definitions'],
+              'definitionTypes': compileParams['definitionTypes'],
+              'typeDefinitions': compileParams['typeDefinitions'],
+              'typeBounds': compileParams['typeBounds'],
+              'typeDefaults': compileParams['typeDefaults'],
+              'libraryUri': compileParams['libraryUri'],
+              'offset': compileParams['tokenPos'],
+              'isStatic': compileParams['isStatic'],
+              'class': compileParams['klass'],
+              'scriptUri': compileParams['scriptUri'],
+              'method': compileParams['method'],
+              'rootLibraryUri': buildScopeResponseResult['rootLibraryUri'],
+            }),
+            VMServiceEmbedderHooks.getResidentCompilerInfoFile!()!,
+          );
+
+      if (response['success'] == true) {
+        return response['kernelBytes'];
+      } else if (response['errorMessage'] != null) {
+        throw _CompileExpressionErrorDetails(response['errorMessage']);
+      } else {
+        final compilerOutputLines =
+            (response['compilerOutputLines'] as List<dynamic>).cast<String>();
+        throw _CompileExpressionErrorDetails(compilerOutputLines.join('\n'));
+      }
     } else {
       // fallback to compile using kernel service
       final compileExpressionParams = <String, dynamic>{
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 5bba53e..d12644f 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 import 'dart:convert';
 import 'dart:isolate';
+import 'dart:io' show File, InternetAddress, Socket;
 import 'dart:math';
 import 'dart:typed_data';
 
@@ -172,6 +173,10 @@
 /// Called when a client wants the service to serve Observatory.
 typedef void ServeObservatoryCallback();
 
+/// Called when we want to get the appropriate resident compiler info file for
+/// the current program execution.
+typedef File? getResidentCompilerInfoFileCallback();
+
 /// Hooks that are setup by the embedder.
 class VMServiceEmbedderHooks {
   static DdsConnectedCallback? ddsConnected;
@@ -188,6 +193,7 @@
   static WebServerAcceptNewWebSocketConnectionsCallback?
   acceptNewWebSocketConnections;
   static ServeObservatoryCallback? serveObservatory;
+  static getResidentCompilerInfoFileCallback? getResidentCompilerInfoFile;
 }
 
 class VMService extends MessageRouter {