[ VM / dartdev ] Fix issue where hard-coded false value for 'null_safety' flag in dartdev's Dart_IsolateFlags
was overwritten by isolate initialization code

Fixes situation where the following command would fail due to the
dartdev kernel not being compiled with null-safety:

dart --strong-null-safety --enable-experiment=non-nullable run foo.dart

Change-Id: I7e7c980eb3274a51e64c031e6bfef8650b897b8b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158345
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/dartdev/test/smoke/smoke.dart b/pkg/dartdev/test/smoke/smoke.dart
index a6a5181..003118f 100644
--- a/pkg/dartdev/test/smoke/smoke.dart
+++ b/pkg/dartdev/test/smoke/smoke.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// @dart=2.10
+
 void main() {
   print('Smoke test!');
 }
diff --git a/pkg/dartdev/test/smoke/smoke_test.dart b/pkg/dartdev/test/smoke/smoke_test.dart
index 336db24..5f9c604 100644
--- a/pkg/dartdev/test/smoke/smoke_test.dart
+++ b/pkg/dartdev/test/smoke/smoke_test.dart
@@ -50,6 +50,23 @@
           expect(result.stderr, isEmpty);
         }
       });
+
+      test(
+          'dart --sound-null-safety --enable-experiment=non-nullable run smoke.dart',
+          () async {
+        final result = await Process.run(
+          Platform.executable,
+          [
+            '--sound-null-safety',
+            '--enable-experiment=non-nullable',
+            'run',
+            script,
+          ],
+        );
+        expect(result.exitCode, 0);
+        expect(result.stdout, contains('Smoke test!'));
+        expect(result.stderr, isEmpty);
+      });
     },
     timeout: Timeout.none,
   );
diff --git a/runtime/bin/dartdev_isolate.cc b/runtime/bin/dartdev_isolate.cc
index bf3a311..b85f8c3 100644
--- a/runtime/bin/dartdev_isolate.cc
+++ b/runtime/bin/dartdev_isolate.cc
@@ -75,8 +75,6 @@
     return Utils::CreateCStringUniquePtr(snapshot_path);
   }
   free(snapshot_path);
-
-  Syslog::PrintErr("Could not find DartDev snapshot.\n");
   return Utils::CreateCStringUniquePtr(nullptr);
 }
 
@@ -171,14 +169,6 @@
   MonitorLocker locker_(DartDevRunner::monitor_);
   DartDevRunner* runner = reinterpret_cast<DartDevRunner*>(args);
 
-  // TODO(bkonyi): bring up DartDev from kernel instead of a app-jit snapshot.
-  // See https://github.com/dart-lang/sdk/issues/42804
-  auto dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath();
-  if (dartdev_path == nullptr) {
-    ProcessError("Failed to find DartDev snapshot.", kErrorExitCode);
-    return;
-  }
-
   // Hardcode flags to match those used to generate the DartDev snapshot.
   Dart_IsolateFlags flags;
   Dart_IsolateFlagsInitialize(&flags);
@@ -189,11 +179,13 @@
 
   char* error;
   Dart_Isolate dartdev_isolate = runner->create_isolate_(
-      dartdev_path.get(), "dartdev", nullptr, runner->packages_file_, &flags,
-      NULL /* callback_data */, const_cast<char**>(&error));
+      DART_DEV_ISOLATE_NAME, DART_DEV_ISOLATE_NAME, nullptr,
+      runner->packages_file_, &flags, /* callback_data */ nullptr,
+      const_cast<char**>(&error));
 
   if (dartdev_isolate == nullptr) {
     ProcessError(error, kErrorExitCode);
+    free(error);
     return;
   }
 
@@ -216,7 +208,8 @@
   }
 
   // Create a SendPort that DartDev can use to communicate its results over.
-  send_port_id = Dart_NewNativePort("dartdev", DartDevResultCallback, false);
+  send_port_id =
+      Dart_NewNativePort(DART_DEV_ISOLATE_NAME, DartDevResultCallback, false);
   ASSERT(send_port_id != ILLEGAL_PORT);
   Dart_Handle send_port = Dart_NewSendPort(send_port_id);
   CHECK_RESULT(send_port);
@@ -247,7 +240,7 @@
 
 void DartDevIsolate::DartDevRunner::ProcessError(const char* msg,
                                                  int32_t exit_code) {
-  Syslog::PrintErr("%s\n", msg);
+  Syslog::PrintErr("%s.\n", msg);
   Process::SetGlobalExitCode(exit_code);
   result_ = DartDevIsolate::DartDev_Result_Exit;
   DartDevRunner::monitor_->Notify();
diff --git a/runtime/bin/dartdev_isolate.h b/runtime/bin/dartdev_isolate.h
index ef6c780..7145c9b 100644
--- a/runtime/bin/dartdev_isolate.h
+++ b/runtime/bin/dartdev_isolate.h
@@ -15,6 +15,8 @@
 #include "platform/globals.h"
 #include "platform/utils.h"
 
+#define DART_DEV_ISOLATE_NAME "dartdev"
+
 namespace dart {
 namespace bin {
 
@@ -39,6 +41,10 @@
 
   static bool should_run_dart_dev() { return should_run_dart_dev_; }
 
+  // Attempts to find the DartDev snapshot. If the snapshot cannot be found,
+  // the VM will shutdown.
+  static Utils::CStringUniquePtr TryResolveDartDevSnapshotPath();
+
   // Starts a DartDev instance in a new isolate and runs it to completion.
   //
   // Returns true if the VM should run the result in `script`, in which case
@@ -82,10 +88,6 @@
   };
 
  private:
-  // Attempts to find the DartDev snapshot. If the snapshot cannot be found,
-  // the VM will shutdown.
-  static Utils::CStringUniquePtr TryResolveDartDevSnapshotPath();
-
   static DartDevRunner runner_;
   static bool should_run_dart_dev_;
 
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 69d82b0..9457dcd 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -382,10 +382,12 @@
   const char* isolate_name = nullptr;
   result = Dart_StringToCString(Dart_DebugName(), &isolate_name);
   CHECK_RESULT(result);
-  if (strstr(isolate_name, "dartdev") != nullptr) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  if (strstr(isolate_name, DART_DEV_ISOLATE_NAME) != nullptr) {
     Dart_SetShouldPauseOnStart(false);
     Dart_SetShouldPauseOnExit(false);
   }
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   // Make the isolate runnable so that it is ready to handle messages.
   Dart_ExitScope();
@@ -565,6 +567,59 @@
 #endif  // !defined(PRODUCT)
 }
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+static Dart_Isolate CreateAndSetupDartDevIsolate(const char* script_uri,
+                                                 const char* packages_config,
+                                                 Dart_IsolateFlags* flags,
+                                                 char** error,
+                                                 int* exit_code) {
+  int64_t start = Dart_TimelineGetMicros();
+
+  auto dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath();
+  if (dartdev_path == nullptr) {
+    *error = Utils::StrDup("Unable to find DartDev snapshot");
+    return nullptr;
+  }
+
+  const uint8_t* isolate_snapshot_data = core_isolate_snapshot_data;
+  const uint8_t* isolate_snapshot_instructions =
+      core_isolate_snapshot_instructions;
+
+  auto isolate_group_data =
+      new IsolateGroupData(DART_DEV_ISOLATE_NAME, packages_config, nullptr,
+                           /*isolate_run_app_snapshot*/ false);
+  uint8_t* application_kernel_buffer = NULL;
+  intptr_t application_kernel_buffer_size = 0;
+  dfe.ReadScript(dartdev_path.get(), &application_kernel_buffer,
+                 &application_kernel_buffer_size);
+  isolate_group_data->SetKernelBufferNewlyOwned(application_kernel_buffer,
+                                                application_kernel_buffer_size);
+
+  auto isolate_data = new IsolateData(isolate_group_data);
+  Dart_Isolate isolate = nullptr;
+  isolate = Dart_CreateIsolateGroup(
+      DART_DEV_ISOLATE_NAME, DART_DEV_ISOLATE_NAME, isolate_snapshot_data,
+      isolate_snapshot_instructions, flags, isolate_group_data, isolate_data,
+      error);
+
+  Dart_Isolate created_isolate = nullptr;
+  if (isolate == nullptr) {
+    delete isolate_data;
+    delete isolate_group_data;
+  } else {
+    created_isolate = IsolateSetupHelper(
+        isolate, false, DART_DEV_ISOLATE_NAME, packages_config,
+        /*isolate_run_app_snapshot*/ false, flags, error, exit_code);
+  }
+  int64_t end = Dart_TimelineGetMicros();
+  Dart_TimelineEvent("CreateAndSetupDartDevIsolate", start, end,
+                     Dart_Timeline_Event_Duration, 0, NULL, NULL);
+  return created_isolate;
+}
+
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
 // Returns newly created Isolate on success, NULL on failure.
 static Dart_Isolate CreateIsolateGroupAndSetupHelper(
     bool is_main_isolate,
@@ -722,10 +777,19 @@
                                        &exit_code);
   }
 #endif  // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  if (strcmp(script_uri, DART_DEV_ISOLATE_NAME) == 0) {
+    return CreateAndSetupDartDevIsolate(script_uri, package_config, flags,
+                                        error, &exit_code);
+  }
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
   if (strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
     return CreateAndSetupServiceIsolate(script_uri, package_config, flags,
                                         error, &exit_code);
   }
+
   bool is_main_isolate = false;
   return CreateIsolateGroupAndSetupHelper(is_main_isolate, script_uri, main,
                                           package_config, flags, callback_data,
@@ -832,14 +896,13 @@
   // Call CreateIsolateGroupAndSetup which creates an isolate and loads up
   // the specified application script.
   char* error = NULL;
-  bool is_main_isolate = true;
   int exit_code = 0;
   Dart_IsolateFlags flags;
   Dart_IsolateFlagsInitialize(&flags);
 
   Dart_Isolate isolate = CreateIsolateGroupAndSetupHelper(
-      is_main_isolate, script_name, "main", Options::packages_file(), &flags,
-      NULL /* callback_data */, &error, &exit_code);
+      /* is_main_isolate */ true, script_name, "main", Options::packages_file(),
+      &flags, NULL /* callback_data */, &error, &exit_code);
 
   if (isolate == NULL) {
     Syslog::PrintErr("%s\n", error);