Version 3.7.0-263.0.dev

Merge 57c4da6911dcbf22224e0fce055f2c72248fdb11 into dev
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index a07ee20..75f1684 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -141,9 +141,7 @@
   DetachableFileSystemManager? detachableFileSystemManager;
 
   /// The instrumentation service that is to be used by the analysis server.
-  InstrumentationService? instrumentationService;
-
-  HttpAnalysisServer? httpServer;
+  late final InstrumentationService _instrumentationService;
 
   /// Use the given command-line [arguments] to start this server.
   ///
@@ -272,10 +270,7 @@
     var logFilePath =
         results.option(PROTOCOL_TRAFFIC_LOG) ??
         results.option(PROTOCOL_TRAFFIC_LOG_ALIAS);
-    var allInstrumentationServices =
-        this.instrumentationService == null
-            ? <InstrumentationService>[]
-            : [this.instrumentationService!];
+    var allInstrumentationServices = <InstrumentationService>[];
     if (logFilePath != null) {
       _rollLogFiles(logFilePath, 5);
       allInstrumentationServices.add(
@@ -291,21 +286,20 @@
     allInstrumentationServices.add(
       CrashReportingInstrumentation(crashReportSender),
     );
-    var instrumentationService = MulticastInstrumentationService(
+    _instrumentationService = MulticastInstrumentationService(
       allInstrumentationServices,
     );
-    this.instrumentationService = instrumentationService;
 
-    instrumentationService.logVersion(
+    _instrumentationService.logVersion(
       results.option(TRAIN_USING) != null
           ? 'training-0'
-          : _readUuid(instrumentationService),
+          : _readUuid(_instrumentationService),
       analysisServerOptions.clientId ?? '',
       analysisServerOptions.clientVersion ?? '',
       PROTOCOL_VERSION,
       defaultSdk.languageVersion.toString(),
     );
-    AnalysisEngine.instance.instrumentationService = instrumentationService;
+    AnalysisEngine.instance.instrumentationService = _instrumentationService;
 
     int? diagnosticServerPort;
     var portValue =
@@ -337,7 +331,7 @@
         analysisServerOptions,
         dartSdkManager,
         analyticsManager,
-        instrumentationService,
+        _instrumentationService,
         diagnosticServerPort,
         errorNotifier,
       );
@@ -349,7 +343,7 @@
         dartSdkManager,
         analyticsManager,
         crashReportingAttachmentsBuilder,
-        instrumentationService,
+        _instrumentationService,
         RequestStatisticsHelper(),
         diagnosticServerPort,
         errorNotifier,
@@ -406,9 +400,8 @@
       analyticsManager,
       detachableFileSystemManager,
     );
-    httpServer = HttpAnalysisServer(socketServer);
 
-    diagnosticServer.httpServer = httpServer!;
+    diagnosticServer.httpServer = HttpAnalysisServer(socketServer);
     if (diagnosticServerPort != null) {
       diagnosticServer.startOnPort(diagnosticServerPort);
     }
@@ -440,18 +433,14 @@
         exitCode = await devServer.processDirectories([trainDirectory]);
         if (exitCode != 0) exit(exitCode);
 
-        var httpServer = this.httpServer;
-        if (httpServer != null) {
-          httpServer.close();
-        }
+        diagnosticServer.httpServer.close();
         await instrumentationService.shutdown();
-
         unawaited(socketServer.analysisServer!.shutdown());
 
         try {
           tempDriverDir.deleteSync(recursive: true);
         } catch (_) {
-          // ignore any exception
+          // Ignore any exception.
         }
 
         exit(exitCode);
@@ -473,10 +462,7 @@
             errorNotifier.sendSilentExceptionsToClient = true;
           }
           serveResult.then((_) async {
-            var httpServer = this.httpServer;
-            if (httpServer != null) {
-              httpServer.close();
-            }
+            diagnosticServer.httpServer.close();
             await instrumentationService.shutdown();
             unawaited(socketServer.analysisServer!.shutdown());
             if (sendPort == null) exit(0);
@@ -485,7 +471,7 @@
         print:
             results.flag(INTERNAL_PRINT_TO_CONSOLE)
                 ? null
-                : httpServer!.recordPrint,
+                : diagnosticServer.httpServer.recordPrint,
       );
     }
   }
@@ -518,8 +504,7 @@
       detachableFileSystemManager,
     );
     errorNotifier.server = socketServer.analysisServer;
-
-    diagnosticServer.httpServer = httpServer = HttpAnalysisServer(socketServer);
+    diagnosticServer.httpServer = HttpAnalysisServer(socketServer);
 
     if (diagnosticServerPort != null) {
       diagnosticServer.startOnPort(diagnosticServerPort);
@@ -948,8 +933,6 @@
 class _DiagnosticServerImpl extends DiagnosticServer {
   late HttpAnalysisServer httpServer;
 
-  _DiagnosticServerImpl();
-
   @override
   Future<int> getServerPort() async => (await httpServer.serveHttp())!;
 
diff --git a/pkg/analysis_server/lib/starter.dart b/pkg/analysis_server/lib/starter.dart
index 8414612..826d468 100644
--- a/pkg/analysis_server/lib/starter.dart
+++ b/pkg/analysis_server/lib/starter.dart
@@ -7,7 +7,6 @@
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/server/detachable_filesystem_manager.dart';
 import 'package:analysis_server/src/server/driver.dart';
-import 'package:analyzer/instrumentation/instrumentation.dart';
 
 /// An object that can be used to start an analysis server. This class exists so
 /// that clients can configure an analysis server before starting it.
@@ -27,10 +26,6 @@
   /// available.
   set detachableFileSystemManager(DetachableFileSystemManager manager);
 
-  /// Set the instrumentation [service] that is to be used by the analysis
-  /// server.
-  set instrumentationService(InstrumentationService service);
-
   /// Use the given command-line [arguments] to start this server.
   void start(
     List<String> arguments, {
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 1727928..62b208a 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -43,8 +43,7 @@
   final int hashCode;
 
   @override
-  bool operator ==(other) =>
-      identical(this, other) || other is Selector && hashCode == other.hashCode;
+  bool operator ==(other) => identical(this, other);
 
   int get argumentCount => callStructure.argumentCount;
   int get namedArgumentCount => callStructure.namedArgumentCount;
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index b15b5f0..bdea89f 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -2001,9 +2001,10 @@
   w.ValueType visitStaticSet(StaticSet node, w.ValueType expectedType) {
     bool preserved = expectedType != voidMarker;
     Member target = node.target;
-    w.ValueType paramType = target is Field
-        ? translator.globals.getGlobalForStaticField(target).type.type
-        : translator.signatureForDirectCall(target.reference).inputs.single;
+    final reference =
+        target is Field ? target.setterReference! : target.reference;
+    w.ValueType paramType =
+        translator.signatureForDirectCall(reference).inputs.single;
     translateExpression(node.value, paramType);
     if (!preserved) {
       call(node.targetReference);
@@ -2012,7 +2013,7 @@
     w.Local temp = addLocal(paramType);
     b.local_tee(temp);
 
-    call(node.targetReference);
+    call(reference);
     b.local_get(temp);
     return temp.type;
   }
diff --git a/pkg/dart2wasm/lib/functions.dart b/pkg/dart2wasm/lib/functions.dart
index 4b93afc..bcc96f5 100644
--- a/pkg/dart2wasm/lib/functions.dart
+++ b/pkg/dart2wasm/lib/functions.dart
@@ -478,12 +478,11 @@
     final isGetter = target.isImplicitGetter;
     final isSetter = target.isImplicitSetter;
     if (isGetter || isSetter) {
-      final global = translator.globals.getGlobalForStaticField(member);
-      final globalType = global.type.type;
+      final fieldType = translator.translateTypeOfField(member);
       if (isGetter) {
-        return translator.typesBuilder.defineFunction(const [], [globalType]);
+        return translator.typesBuilder.defineFunction(const [], [fieldType]);
       }
-      return translator.typesBuilder.defineFunction([globalType], const []);
+      return translator.typesBuilder.defineFunction([fieldType], const []);
     }
   }
 
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 54ad454..75f113c 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -17,6 +17,7 @@
 import '../native_assets.dart';
 import '../sdk.dart';
 import '../utils.dart';
+import '../vm_interop_handler.dart';
 
 const int genericErrorExitCode = 255;
 const int compileErrorExitCode = 254;
@@ -93,17 +94,18 @@
     final args = argResults!;
     var snapshot = sdk.dart2jsAotSnapshot;
     var runtime = sdk.dartAotRuntime;
+    var isAOT = true;
     if (!Sdk.checkArtifactExists(snapshot, logError: false)) {
       // AOT snapshots cannot be generated on IA32, so we need this fallback
       // branch until support for IA32 is dropped (https://dartbug.com/49969).
       snapshot = sdk.dart2jsSnapshot;
-      runtime = sdk.dart;
       if (!Sdk.checkArtifactExists(snapshot)) {
         return genericErrorExitCode;
       }
+      runtime = sdk.dart;
+      isAOT = false;
     }
     final dart2jsCommand = [
-      runtime,
       snapshot,
       '--libraries-spec=${sdk.librariesJson}',
       '--cfe-invocation-modes=compile',
@@ -112,8 +114,13 @@
       if (args.rest.isNotEmpty) ...args.rest.sublist(0),
     ];
     try {
-      final exitCode = await runProcessInheritStdio(dart2jsCommand);
-      return exitCode;
+      VmInteropHandler.run(
+        runtime,
+        dart2jsCommand,
+        packageConfigOverride: null,
+        isAOT : isAOT,
+      );
+      return 0;
     } catch (e, st) {
       log.stderr('Error: JS compilation failed');
       log.stderr(e.toString());
diff --git a/pkg/dartdev/lib/src/vm_interop_handler.dart b/pkg/dartdev/lib/src/vm_interop_handler.dart
index 37eed1d..43bd647 100644
--- a/pkg/dartdev/lib/src/vm_interop_handler.dart
+++ b/pkg/dartdev/lib/src/vm_interop_handler.dart
@@ -18,6 +18,9 @@
   ///
   /// If [markMainIsolateAsSystemIsolate] is given and set to true, the spawned
   /// isolate will run with `--mark-main-isolate-as-system-isolate` enabled.
+  ///
+  /// If [isAOT] is given and set to true, the script is executed by
+  /// execing the dartaotruntime.
   static void run(
     String script,
     List<String> args, {
@@ -27,11 +30,12 @@
     //
     // See https://github.com/dart-lang/sdk/issues/53576
     bool markMainIsolateAsSystemIsolate = false,
+    bool isAOT = false,
   }) {
     final port = _port;
     if (port == null) return;
     final message = <dynamic>[
-      _kResultRun,
+      isAOT ? _kResultRunAOT : _kResultRunJIT,
       script,
       packageConfigOverride,
       markMainIsolateAsSystemIsolate,
@@ -51,8 +55,9 @@
   }
 
   // Note: keep in sync with runtime/bin/dartdev_isolate.h
-  static const int _kResultRun = 1;
-  static const int _kResultExit = 2;
+  static const int _kResultRunJIT = 1;
+  static const int _kResultRunAOT = 2;
+  static const int _kResultExit = 3;
 
   static SendPort? _port;
 }
diff --git a/runtime/bin/dartdev_isolate.cc b/runtime/bin/dartdev_isolate.cc
index c7aab45..95c9fd5 100644
--- a/runtime/bin/dartdev_isolate.cc
+++ b/runtime/bin/dartdev_isolate.cc
@@ -38,6 +38,7 @@
     DartDevIsolate::DartDevRunner();
 bool DartDevIsolate::should_run_dart_dev_ = false;
 bool DartDevIsolate::print_usage_error_ = false;
+CommandLineOptions* DartDevIsolate::vm_options_ = nullptr;
 Monitor* DartDevIsolate::DartDevRunner::monitor_ = new Monitor();
 DartDevIsolate::DartDev_Result DartDevIsolate::DartDevRunner::result_ =
     DartDevIsolate::DartDev_Result_Unknown;
@@ -138,7 +139,7 @@
   Thread::Start("DartDev Runner", RunCallback, reinterpret_cast<uword>(this));
   monitor_->WaitMicros(Monitor::kNoTimeout);
 
-  if (result_ == DartDevIsolate::DartDev_Result_Run) {
+  if (result_ == DartDevIsolate::DartDev_Result_RunJIT) {
     // Clear the DartDev dart_options and replace them with the processed
     // options provided by DartDev.
     dart_options_->Reset();
@@ -157,8 +158,8 @@
   ASSERT(message->type == Dart_CObject_kArray);
   int32_t type = GetArrayItem(message, 0)->value.as_int32;
   switch (type) {
-    case DartDevIsolate::DartDev_Result_Run: {
-      result_ = DartDevIsolate::DartDev_Result_Run;
+    case DartDevIsolate::DartDev_Result_RunJIT: {
+      result_ = DartDevIsolate::DartDev_Result_RunJIT;
       ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
       auto item2 = GetArrayItem(message, 2);
 
@@ -204,6 +205,86 @@
       }
       break;
     }
+    case DartDevIsolate::DartDev_Result_RunAOT: {
+      result_ = DartDevIsolate::DartDev_Result_RunAOT;
+      ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
+      auto item2 = GetArrayItem(message, 2);
+
+      ASSERT(item2->type == Dart_CObject_kString ||
+             item2->type == Dart_CObject_kNull);
+
+      auto item3 = GetArrayItem(message, 3);
+
+      ASSERT(item3->type == Dart_CObject_kBool);
+      const bool mark_main_isolate_as_system_isolate = item3->value.as_bool;
+      if (mark_main_isolate_as_system_isolate) {
+        Options::set_mark_main_isolate_as_system_isolate(true);
+      }
+
+      if (*script_ != nullptr) {
+        free(*script_);
+      }
+      if (*package_config_override_ != nullptr) {
+        free(*package_config_override_);
+        *package_config_override_ = nullptr;
+      }
+      *script_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
+
+      if (item2->type == Dart_CObject_kString) {
+        *package_config_override_ = Utils::StrDup(item2->value.as_string);
+      }
+
+      intptr_t num_vm_options = 0;
+      const char** vm_options = nullptr;
+      ASSERT(GetArrayItem(message, 4)->type == Dart_CObject_kArray);
+      Dart_CObject* args = GetArrayItem(message, 4);
+      intptr_t argc = args->value.as_array.length;
+      Dart_CObject** dart_args = args->value.as_array.values;
+
+      if (vm_options_ != nullptr) {
+        num_vm_options = vm_options_->count();
+        vm_options = vm_options_->arguments();
+      }
+      auto deleter = [](char** args) {
+        for (intptr_t i = 0; i < argc_; ++i) {
+          free(args[i]);
+        }
+        delete[] args;
+      };
+      // Total count of arguments to be passed to the script being execed.
+      argc_ = argc + num_vm_options + 1;
+
+      // Array of arguments to be passed to the script being execed.
+      argv_ = std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_ + 1],
+                                                         deleter);
+
+      intptr_t idx = 0;
+      // Copy in name of the script to run (dartaotruntime).
+      argv_[0] = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
+      idx += 1;
+      // Copy in any vm options that need to be passed to the execed process.
+      for (intptr_t i = 0; i < num_vm_options; ++i) {
+        argv_[i + idx] = Utils::StrDup(vm_options[i]);
+      }
+      idx += num_vm_options;
+      // Copy in the dart options that need to be passed to the command.
+      for (intptr_t i = 0; i < argc; ++i) {
+        argv_[i + idx] = Utils::StrDup(dart_args[i]->value.as_string);
+      }
+      // Null terminate the argv array.
+      argv_[argc + idx] = nullptr;
+
+      // Exec the script to be run and pass the arguments.
+      char err_msg[256];
+      err_msg[0] = '\0';
+      int ret = Process::Exec(nullptr, *script_,
+                              const_cast<const char**>(argv_.get()), argc_,
+                              nullptr, err_msg, sizeof(err_msg));
+      if (ret != 0) {
+        ProcessError(err_msg, kErrorExitCode);
+      }
+      break;
+    }
     case DartDevIsolate::DartDev_Result_Exit: {
       ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32);
       int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;
@@ -314,7 +395,9 @@
     Dart_IsolateGroupCreateCallback create_isolate,
     char** packages_file,
     char** script,
+    CommandLineOptions* vm_options,
     CommandLineOptions* dart_options) {
+  vm_options_ = vm_options;
   runner_.Run(create_isolate, packages_file, script, dart_options);
   return runner_.result();
 }
diff --git a/runtime/bin/dartdev_isolate.h b/runtime/bin/dartdev_isolate.h
index 79566c6..ed997cc 100644
--- a/runtime/bin/dartdev_isolate.h
+++ b/runtime/bin/dartdev_isolate.h
@@ -27,8 +27,9 @@
   // Note: keep in sync with pkg/dartdev/lib/vm_interop_handler.dart
   typedef enum {
     DartDev_Result_Unknown = -1,
-    DartDev_Result_Run = 1,
-    DartDev_Result_Exit = 2,
+    DartDev_Result_RunJIT = 1,
+    DartDev_Result_RunAOT = 2,
+    DartDev_Result_Exit = 3,
   } DartDev_Result;
 
   // Returns true if there does not exist a file at |script_uri| or the URI is
@@ -58,6 +59,7 @@
       Dart_IsolateGroupCreateCallback create_isolate,
       char** packages_file,
       char** script,
+      CommandLineOptions* vm_options,
       CommandLineOptions* dart_options);
 
  protected:
@@ -83,11 +85,11 @@
     static char** package_config_override_;
     static std::unique_ptr<char*[], void (*)(char**)> argv_;
     static intptr_t argc_;
+    static Monitor* monitor_;
 
     Dart_IsolateGroupCreateCallback create_isolate_;
     CommandLineOptions* dart_options_;
     const char* packages_file_;
-    static Monitor* monitor_;
 
     DISALLOW_ALLOCATION();
   };
@@ -98,6 +100,7 @@
   static DartDevRunner runner_;
   static bool should_run_dart_dev_;
   static bool print_usage_error_;
+  static CommandLineOptions* vm_options_;
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(DartDevIsolate);
diff --git a/runtime/bin/main_impl.cc b/runtime/bin/main_impl.cc
index 9e3aa8c..49522df 100644
--- a/runtime/bin/main_impl.cc
+++ b/runtime/bin/main_impl.cc
@@ -1417,11 +1417,11 @@
       Options::gen_snapshot_kind() == SnapshotKind::kNone) {
     DartDevIsolate::DartDev_Result dartdev_result = DartDevIsolate::RunDartDev(
         CreateIsolateGroupAndSetup, &package_config_override, &script_name,
-        &dart_options);
+        &vm_options, &dart_options);
     ASSERT(dartdev_result != DartDevIsolate::DartDev_Result_Unknown);
     ran_dart_dev = true;
     should_run_user_program =
-        (dartdev_result == DartDevIsolate::DartDev_Result_Run);
+        (dartdev_result == DartDevIsolate::DartDev_Result_RunJIT);
     if (should_run_user_program) {
       try_load_snapshots_lambda();
     }
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index f990e80..dfb0b77 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -114,9 +114,9 @@
   const char* path = DartUtils::GetStringValue(path_handle);
   Dart_Handle arguments = Dart_GetNativeArgument(args, 3);
   intptr_t args_length = 0;
-  char** string_args =
+  const char** string_args = const_cast<const char**>(
       ExtractCStringList(arguments, status_handle,
-                         "Arguments must be builtin strings", &args_length);
+                         "Arguments must be builtin strings", &args_length));
   if (string_args == nullptr) {
     Dart_SetBooleanReturnValue(args, false);
     return;
diff --git a/runtime/bin/process.h b/runtime/bin/process.h
index 9bd547c..2aa40cd 100644
--- a/runtime/bin/process.h
+++ b/runtime/bin/process.h
@@ -94,7 +94,7 @@
   // process exit streams.
   static int Start(Namespace* namespc,
                    const char* path,
-                   char* arguments[],
+                   const char* arguments[],
                    intptr_t arguments_length,
                    const char* working_directory,
                    char* environment[],
@@ -114,6 +114,23 @@
                    intptr_t exit_handler,
                    ProcessResult* result);
 
+  // Exec process.
+  // On systems that support 'exec' it will use it to replace
+  // the current process image with the image corresponding to 'path'
+  // On systems that do not support it (Windows) it will start in a
+  // child process in the same group as the parent so that when the parent
+  // is killed the child also dies.
+  // Returns 0 if the process could be execed successfully
+  // Returns -1 if the exec could not be done successfully and 'errmsg'
+  // points to the error message
+  static int Exec(Namespace* namespc,
+                  const char* path,
+                  const char* arguments[],
+                  intptr_t arguments_length,
+                  const char* working_directory,
+                  char* errmsg,
+                  intptr_t errmsg_len);
+
   // Kill a process with a given pid.
   static bool Kill(intptr_t id, int signal);
 
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
index eed2af0..4c6a168 100644
--- a/runtime/bin/process_fuchsia.cc
+++ b/runtime/bin/process_fuchsia.cc
@@ -511,7 +511,7 @@
  public:
   ProcessStarter(Namespace* namespc,
                  const char* path,
-                 char* arguments[],
+                 const char* arguments[],
                  intptr_t arguments_length,
                  const char* working_directory,
                  char* environment[],
@@ -540,7 +540,7 @@
     read_err_ = -1;
     write_out_ = -1;
 
-    program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
+    program_arguments_ = reinterpret_cast<const char**>(Dart_ScopeAllocate(
         (arguments_length + 2) * sizeof(*program_arguments_)));
     program_arguments_[0] = const_cast<char*>(path_);
     for (int i = 0; i < arguments_length; i++) {
@@ -795,7 +795,7 @@
   int read_err_;   // Pipe for stderr to child process.
   int write_out_;  // Pipe for stdin to child process.
 
-  char** program_arguments_;
+  const char** program_arguments_;
   char** program_environment_;
 
   Namespace* namespc_;
@@ -815,7 +815,7 @@
 
 int Process::Start(Namespace* namespc,
                    const char* path,
-                   char* arguments[],
+                   const char* arguments[],
                    intptr_t arguments_length,
                    const char* working_directory,
                    char* environment[],
@@ -838,6 +838,20 @@
   return starter.Start();
 }
 
+// The command line dart utility does not run on Fuchsia, this functionality
+// is not supported on that platform.
+int Process::Exec(Namespace* namespc,
+                  const char* path,
+                  const char** arguments,
+                  intptr_t arguments_length,
+                  const char* working_directory,
+                  char* errmsg,
+                  intptr_t errmsg_len) {
+  snprintf(errmsg, errmsg_len,
+           "Process::Exec is not supported on this platform");
+  return -1;
+}
+
 intptr_t Process::SetSignalHandler(intptr_t signal) {
   errno = ENOSYS;
   return -1;
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 64e74fc..da95e5a 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -246,11 +246,47 @@
 bool ExitCodeHandler::terminate_done_ = false;
 Monitor* ExitCodeHandler::monitor_ = nullptr;
 
+// Tries to find path relative to the current namespace unless it should be
+// searched in the PATH environment variable.
+// The path that should be passed to exec is returned in realpath.
+// Returns true on success, and false if there was an error that should
+// be reported to the parent.
+static bool PathInNamespace(char* realpath,
+                            intptr_t realpath_size,
+                            Namespace* namespc,
+                            const char* path) {
+  // Perform a PATH search if there's no slash in the path.
+  if (Namespace::IsDefault(namespc) || strchr(path, '/') == nullptr) {
+    // TODO(zra): If there is a non-default namespace, the entries in PATH
+    // should be treated as relative to the namespace.
+    strncpy(realpath, path, realpath_size);
+    realpath[realpath_size - 1] = '\0';
+    return true;
+  }
+  NamespaceScope ns(namespc, path);
+  const int fd =
+      TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_RDONLY | O_CLOEXEC));
+  if (fd == -1) {
+    return false;
+  }
+  char procpath[PATH_MAX];
+  snprintf(procpath, PATH_MAX, "/proc/self/fd/%d", fd);
+  const intptr_t length =
+      TEMP_FAILURE_RETRY(readlink(procpath, realpath, realpath_size));
+  if (length < 0) {
+    FDUtils::SaveErrorAndClose(fd);
+    return false;
+  }
+  realpath[length] = '\0';
+  FDUtils::SaveErrorAndClose(fd);
+  return true;
+}
+
 class ProcessStarter {
  public:
   ProcessStarter(Namespace* namespc,
                  const char* path,
-                 char* arguments[],
+                 const char* arguments[],
                  intptr_t arguments_length,
                  const char* working_directory,
                  char* environment[],
@@ -281,7 +317,7 @@
     exec_control_[0] = -1;
     exec_control_[1] = -1;
 
-    program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
+    program_arguments_ = reinterpret_cast<const char**>(Dart_ScopeAllocate(
         (arguments_length + 2) * sizeof(*program_arguments_)));
     program_arguments_[0] = const_cast<char*>(path_);
     for (int i = 0; i < arguments_length; i++) {
@@ -447,31 +483,7 @@
   // Returns true on success, and false if there was an error that should
   // be reported to the parent.
   bool FindPathInNamespace(char* realpath, intptr_t realpath_size) {
-    // Perform a PATH search if there's no slash in the path.
-    if (Namespace::IsDefault(namespc_) || strchr(path_, '/') == nullptr) {
-      // TODO(zra): If there is a non-default namespace, the entries in PATH
-      // should be treated as relative to the namespace.
-      strncpy(realpath, path_, realpath_size);
-      realpath[realpath_size - 1] = '\0';
-      return true;
-    }
-    NamespaceScope ns(namespc_, path_);
-    const int fd =
-        TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_RDONLY | O_CLOEXEC));
-    if (fd == -1) {
-      return false;
-    }
-    char procpath[PATH_MAX];
-    snprintf(procpath, PATH_MAX, "/proc/self/fd/%d", fd);
-    const intptr_t length =
-        TEMP_FAILURE_RETRY(readlink(procpath, realpath, realpath_size));
-    if (length < 0) {
-      FDUtils::SaveErrorAndClose(fd);
-      return false;
-    }
-    realpath[length] = '\0';
-    FDUtils::SaveErrorAndClose(fd);
-    return true;
+    return PathInNamespace(realpath, realpath_size, namespc_, path_);
   }
 
   void ExecProcess() {
@@ -772,7 +784,7 @@
   int write_out_[2];     // Pipe for stdin to child process.
   int exec_control_[2];  // Pipe to get the result from exec.
 
-  char** program_arguments_;
+  const char** program_arguments_;
   char** program_environment_;
 
   Namespace* namespc_;
@@ -792,7 +804,7 @@
 
 int Process::Start(Namespace* namespc,
                    const char* path,
-                   char* arguments[],
+                   const char* arguments[],
                    intptr_t arguments_length,
                    const char* working_directory,
                    char* environment[],
@@ -914,6 +926,31 @@
   return true;
 }
 
+int Process::Exec(Namespace* namespc,
+                  const char* path,
+                  const char* arguments[],
+                  intptr_t arguments_length,
+                  const char* working_directory,
+                  char* errmsg,
+                  intptr_t errmsg_len) {
+  if (working_directory != nullptr &&
+      !Directory::SetCurrent(namespc, working_directory)) {
+    Utils::StrError(errno, errmsg, errmsg_len);
+    return -1;
+  }
+
+  char realpath[PATH_MAX];
+  if (!PathInNamespace(realpath, PATH_MAX, namespc, path)) {
+    Utils::StrError(errno, errmsg, errmsg_len);
+    return -1;
+  }
+  // TODO(dart:io) Test for the existence of execveat, and use it instead.
+  execvp(const_cast<const char*>(realpath),
+         const_cast<char* const*>(arguments));
+  Utils::StrError(errno, errmsg, errmsg_len);
+  return -1;
+}
+
 bool Process::Kill(intptr_t id, int signal) {
   return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
 }
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index d7eb45e..94568e3 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -249,7 +249,7 @@
 class ProcessStarter {
  public:
   ProcessStarter(const char* path,
-                 char* arguments[],
+                 const char* arguments[],
                  intptr_t arguments_length,
                  const char* working_directory,
                  char* environment[],
@@ -279,7 +279,7 @@
     exec_control_[0] = -1;
     exec_control_[1] = -1;
 
-    program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate(
+    program_arguments_ = reinterpret_cast<const char**>(Dart_ScopeAllocate(
         (arguments_length + 2) * sizeof(*program_arguments_)));
     program_arguments_[0] = const_cast<char*>(path_);
     for (int i = 0; i < arguments_length; i++) {
@@ -740,7 +740,7 @@
   int write_out_[2];     // Pipe for stdin to child process.
   int exec_control_[2];  // Pipe to get the result from exec.
 
-  char** program_arguments_;
+  const char** program_arguments_;
   char** program_environment_;
 
   const char* path_;
@@ -760,7 +760,7 @@
 
 int Process::Start(Namespace* namespc,
                    const char* path,
-                   char* arguments[],
+                   const char* arguments[],
                    intptr_t arguments_length,
                    const char* working_directory,
                    char* environment[],
@@ -898,6 +898,24 @@
 #endif  // defined(DART_HOST_OS_IOS)
 }
 
+int Process::Exec(Namespace* namespc,
+                  const char* path,
+                  const char* arguments[],
+                  intptr_t arguments_length,
+                  const char* working_directory,
+                  char* errmsg,
+                  intptr_t errmsg_len) {
+  if (working_directory != nullptr &&
+      TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) {
+    Utils::StrError(errno, errmsg, errmsg_len);
+    return -1;
+  }
+
+  execvp(const_cast<const char*>(path), const_cast<char* const*>(arguments));
+  Utils::StrError(errno, errmsg, errmsg_len);
+  return -1;
+}
+
 static int SignalMap(intptr_t id) {
   switch (static_cast<ProcessSignals>(id)) {
     case kSighup:
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index e9a353b..b9949c9 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -20,6 +20,7 @@
 #include "bin/utils.h"
 #include "bin/utils_win.h"
 #include "platform/syslog.h"
+#include "platform/text_buffer.h"
 
 namespace dart {
 namespace bin {
@@ -344,7 +345,7 @@
 class ProcessStarter {
  public:
   ProcessStarter(const char* path,
-                 char* arguments[],
+                 const char* arguments[],
                  intptr_t arguments_length,
                  const char* working_directory,
                  char* environment[],
@@ -373,11 +374,12 @@
     stderr_handles_[kWriteHandle] = INVALID_HANDLE_VALUE;
     exit_handles_[kReadHandle] = INVALID_HANDLE_VALUE;
     exit_handles_[kWriteHandle] = INVALID_HANDLE_VALUE;
+    child_process_handle_ = INVALID_HANDLE_VALUE;
 
     // Transform input strings to system format.
     const wchar_t* system_path = StringUtilsWin::Utf8ToWide(path_);
-    wchar_t** system_arguments;
-    system_arguments = reinterpret_cast<wchar_t**>(
+    const wchar_t** system_arguments;
+    system_arguments = reinterpret_cast<const wchar_t**>(
         Dart_ScopeAllocate(arguments_length * sizeof(*system_arguments)));
     for (int i = 0; i < arguments_length; i++) {
       system_arguments[i] = StringUtilsWin::Utf8ToWide(arguments[i]);
@@ -562,7 +564,42 @@
         *exit_handler_ = reinterpret_cast<intptr_t>(exit_handle);
       }
     }
+    child_process_handle_ = process_info.hProcess;
+    CloseHandle(process_info.hThread);
 
+    // Return process id.
+    *id_ = process_info.dwProcessId;
+    return 0;
+  }
+
+  int StartForExec() {
+    // Setup info
+    STARTUPINFOEXW startup_info;
+    ZeroMemory(&startup_info, sizeof(startup_info));
+    startup_info.StartupInfo.cb = sizeof(startup_info);
+    ASSERT(mode_ == kInheritStdio);
+    ASSERT(Process::ModeIsAttached(mode_));
+    ASSERT(!Process::ModeHasStdio(mode_));
+
+    PROCESS_INFORMATION process_info;
+    ZeroMemory(&process_info, sizeof(process_info));
+
+    // Create process.
+    DWORD creation_flags =
+        EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT;
+    BOOL result = CreateProcessW(
+        nullptr,  // ApplicationName
+        command_line_,
+        nullptr,  // ProcessAttributes
+        nullptr,  // ThreadAttributes
+        TRUE,     // InheritHandles
+        creation_flags, environment_block_, system_working_directory_,
+        reinterpret_cast<STARTUPINFOW*>(&startup_info), &process_info);
+
+    if (result == 0) {
+      return SetOsErrorMessage(os_error_message_);
+    }
+    child_process_handle_ = process_info.hProcess;
     CloseHandle(process_info.hThread);
 
     // Return process id.
@@ -627,6 +664,7 @@
   HANDLE stdout_handles_[2];
   HANDLE stderr_handles_[2];
   HANDLE exit_handles_[2];
+  HANDLE child_process_handle_;
 
   const wchar_t* system_working_directory_;
   wchar_t* command_line_;
@@ -651,7 +689,7 @@
 
 int Process::Start(Namespace* namespc,
                    const char* path,
-                   char* arguments[],
+                   const char* arguments[],
                    intptr_t arguments_length,
                    const char* working_directory,
                    char* environment[],
@@ -880,6 +918,92 @@
   return true;
 }
 
+int Process::Exec(Namespace* namespc,
+                  const char* path,
+                  const char* arguments[],
+                  intptr_t arguments_length,
+                  const char* working_directory,
+                  char* errmsg,
+                  intptr_t errmsg_len) {
+  // Create a Job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
+  HANDLE hjob = CreateJobObject(nullptr, nullptr);
+  if (hjob == nullptr) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - CreateJobObject failed %d\n", GetLastError());
+    return -1;
+  }
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+  DWORD qresult;
+  if (!QueryInformationJobObject(hjob, JobObjectExtendedLimitInformation, &info,
+                                 sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
+                                 &qresult)) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - QueryInformationJobObject failed %d\n",
+             GetLastError());
+    return -1;
+  }
+  info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+  if (!SetInformationJobObject(hjob, JobObjectExtendedLimitInformation, &info,
+                               sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - SetInformationJobObject failed %d\n",
+             GetLastError());
+    return -1;
+  }
+
+  // Put the current process into the job object (there is a race here
+  // as the process can crash before it is in the Job object, but since
+  // we haven't spawned any children yet this race is harmless)
+  if (!AssignProcessToJobObject(hjob, GetCurrentProcess())) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - AssignProcessToJobObject failed %d\n",
+             GetLastError());
+    return -1;
+  }
+
+  // Spawn the new child process (this child will automatically get
+  // added to the Job object).
+  // If the parent process is killed or it crashes the Job object
+  // will get destroyed and all the child processes will also get killed.
+  // arguments includes the name of the executable to run which is the same
+  // as the value passed in 'path', we strip that off when starting the
+  // process.
+  intptr_t pid = -1;
+  char* os_error_message = nullptr;  // Scope allocated by Process::Start.
+  ProcessStarter starter(path, &(arguments[1]), (arguments_length - 1),
+                         working_directory, nullptr, 0, kInheritStdio, nullptr,
+                         nullptr, nullptr, &pid, nullptr, &os_error_message);
+  int result = starter.StartForExec();
+  if (result != 0) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - %s\n", os_error_message);
+    return -1;
+  }
+
+  // Now wait for this child process to terminate (normal exit or crash).
+  HANDLE child_process = starter.child_process_handle_;
+  ASSERT(child_process != INVALID_HANDLE_VALUE);
+  DWORD wait_result = WaitForSingleObject(child_process, INFINITE);
+  if (wait_result != WAIT_OBJECT_0) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - WaitForSingleObject failed %d\n", GetLastError());
+    CloseHandle(child_process);
+    return -1;
+  }
+  int retval;
+  if (!GetExitCodeProcess(child_process, reinterpret_cast<DWORD*>(&retval))) {
+    BufferFormatter f(errmsg, errmsg_len);
+    f.Printf("Process::Exec - GetExitCodeProcess failed %d\n", GetLastError());
+    CloseHandle(child_process);
+    return -1;
+  }
+  CloseHandle(child_process);
+  // We exit the process here to simulate the same behaviour as exec on systems
+  // that support it.
+  ExitProcess(retval);
+  return 0;
+}
+
 bool Process::Kill(intptr_t id, int signal) {
   USE(signal);  // signal is not used on Windows.
   HANDLE process_handle;
diff --git a/runtime/observatory/tests/service/uri_mappings_lookup_test.dart b/runtime/observatory/tests/service/uri_mappings_lookup_test.dart
index 43a5fed..e29cf98 100644
--- a/runtime/observatory/tests/service/uri_mappings_lookup_test.dart
+++ b/runtime/observatory/tests/service/uri_mappings_lookup_test.dart
@@ -30,7 +30,7 @@
     expect(uris[0], isNull);
     expect(uris[1], 'org-dartlang-sdk:///sdk/lib/io/io.dart');
     expect(uris[2], startsWith('file:///'));
-    expect(uris[2], endsWith('third_party/pkg/pool/lib/pool.dart'));
+    expect(uris[2], endsWith('pool/lib/pool.dart'));
     expect(uris[3], scriptUri);
     if (Platform.isWindows || Platform.isMacOS) {
       expect(uris[4], scriptUri);
diff --git a/tools/VERSION b/tools/VERSION
index 404e011..2435522 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 7
 PATCH 0
-PRERELEASE 262
+PRERELEASE 263
 PRERELEASE_PATCH 0