[VM] Experimental flags in the dart CLI

Blocked on https://dart-review.googlesource.com/c/sdk/+/88840

Bug: https://github.com/dart-lang/sdk/issues/35602
Change-Id: I72b1cf574c9cb3d1dac2fbd8dfeb0f3fd80e330e
Reviewed-on: https://dart-review.googlesource.com/c/89042
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Liam Appelbe <liama@google.com>
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 30c3b6c..e1e6bc8 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -37,6 +37,8 @@
 import 'package:vm/kernel_front_end.dart' show runWithFrontEndCompilerContext;
 import 'package:vm/http_filesystem.dart';
 import 'package:vm/target/vm.dart' show VmTarget;
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+    show CompilerOptions, parseExperimentalFlags;
 
 final bool verbose = new bool.fromEnvironment('DFE_VERBOSE');
 const String platformKernelFile = 'virtual_platform_kernel.dill';
@@ -67,6 +69,7 @@
   final FileSystem fileSystem;
   final Uri platformKernelPath;
   bool suppressWarnings;
+  List<String> experimentalFlags;
   bool bytecode;
   String packageConfig;
 
@@ -76,6 +79,7 @@
 
   Compiler(this.fileSystem, this.platformKernelPath,
       {this.suppressWarnings: false,
+      this.experimentalFlags: null,
       this.bytecode: false,
       this.packageConfig: null}) {
     Uri packagesUri = null;
@@ -92,6 +96,13 @@
       print("DFE: platformKernelPath: ${platformKernelPath}");
     }
 
+    var expFlags = List<String>();
+    if (experimentalFlags != null) {
+      for (String flag in experimentalFlags) {
+        expFlags.addAll(flag.split(","));
+      }
+    }
+
     options = new CompilerOptions()
       ..fileSystem = fileSystem
       ..target = new VmTarget(new TargetFlags())
@@ -99,6 +110,8 @@
       ..sdkSummary = platformKernelPath
       ..verbose = verbose
       ..bytecode = bytecode
+      ..experimentalFlags =
+          parseExperimentalFlags(expFlags, (msg) => errors.add(msg))
       ..onDiagnostic = (DiagnosticMessage message) {
         bool printMessage;
         switch (message.severity) {
@@ -163,10 +176,12 @@
 
   IncrementalCompilerWrapper(FileSystem fileSystem, Uri platformKernelPath,
       {bool suppressWarnings: false,
+      List<String> experimentalFlags: null,
       bool bytecode: false,
       String packageConfig: null})
       : super(fileSystem, platformKernelPath,
             suppressWarnings: suppressWarnings,
+            experimentalFlags: experimentalFlags,
             bytecode: bytecode,
             packageConfig: packageConfig);
 
@@ -186,6 +201,7 @@
     IncrementalCompilerWrapper clone = IncrementalCompilerWrapper(
         fileSystem, platformKernelPath,
         suppressWarnings: suppressWarnings,
+        experimentalFlags: experimentalFlags,
         bytecode: bytecode,
         packageConfig: packageConfig);
 
@@ -213,10 +229,12 @@
   SingleShotCompilerWrapper(FileSystem fileSystem, Uri platformKernelPath,
       {this.requireMain: false,
       bool suppressWarnings: false,
+      List<String> experimentalFlags: null,
       bool bytecode: false,
       String packageConfig: null})
       : super(fileSystem, platformKernelPath,
             suppressWarnings: suppressWarnings,
+            experimentalFlags: experimentalFlags,
             bytecode: bytecode,
             packageConfig: packageConfig);
 
@@ -240,6 +258,7 @@
 Future<Compiler> lookupOrBuildNewIncrementalCompiler(int isolateId,
     List sourceFiles, Uri platformKernelPath, List<int> platformKernel,
     {bool suppressWarnings: false,
+    List<String> experimentalFlags: null,
     bool bytecode: false,
     String packageConfig: null,
     String multirootFilepaths,
@@ -268,6 +287,7 @@
       // isolate was shut down. Message should be handled here in this script.
       compiler = new IncrementalCompilerWrapper(fileSystem, platformKernelPath,
           suppressWarnings: suppressWarnings,
+          experimentalFlags: experimentalFlags,
           bytecode: bytecode,
           packageConfig: packageConfig);
     }
@@ -445,10 +465,12 @@
   final int isolateId = request[6];
   final List sourceFiles = request[7];
   final bool suppressWarnings = request[8];
-  final bool bytecode = request[9];
-  final String packageConfig = request[10];
-  final String multirootFilepaths = request[11];
-  final String multirootScheme = request[12];
+  final List<String> experimentalFlags =
+      request[9] != null ? request[9].cast<String>() : null;
+  final bool bytecode = request[10];
+  final String packageConfig = request[11];
+  final String multirootFilepaths = request[12];
+  final String multirootScheme = request[13];
 
   if (bytecode) {
     // Bytecode generator is hooked into kernel service after kernel component
@@ -507,6 +529,7 @@
     compiler = await lookupOrBuildNewIncrementalCompiler(
         isolateId, sourceFiles, platformKernelPath, platformKernel,
         suppressWarnings: suppressWarnings,
+        experimentalFlags: experimentalFlags,
         bytecode: bytecode,
         packageConfig: packageConfig,
         multirootFilepaths: multirootFilepaths,
@@ -517,6 +540,7 @@
     compiler = new SingleShotCompilerWrapper(fileSystem, platformKernelPath,
         requireMain: false,
         suppressWarnings: suppressWarnings,
+        experimentalFlags: experimentalFlags,
         bytecode: bytecode,
         packageConfig: packageConfig);
   }
@@ -641,6 +665,7 @@
     1 /* isolateId chosen randomly */,
     [] /* source files */,
     false /* suppress warnings */,
+    null /* experimental_flags */,
     false /* generate bytecode */,
     null /* package_config */,
     null /* multirootFilepaths */,
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index d629c76..693078c 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -9,6 +9,7 @@
 #include "vm/compiler/jit/compiler.h"
 #include "vm/dart_api_impl.h"
 #include "vm/dart_entry.h"
+#include "vm/flags.h"
 #include "vm/isolate.h"
 #include "vm/lockers.h"
 #include "vm/message.h"
@@ -343,6 +344,17 @@
                                  Dart_WeakPersistentHandle handle,
                                  void* peer) {}
 
+MallocGrowableArray<char*>* KernelIsolate::experimental_flags_ =
+    new MallocGrowableArray<char*>();
+
+void KernelIsolate::AddExperimentalFlag(const char* value) {
+  experimental_flags_->Add(strdup(value));
+}
+
+DEFINE_OPTION_HANDLER(KernelIsolate::AddExperimentalFlag,
+                      enable_experiment,
+                      "Comma separated list of experimental features.");
+
 class KernelCompilationRequest : public ValueObject {
  public:
   KernelCompilationRequest()
@@ -373,7 +385,8 @@
       const Array& type_definitions,
       char const* library_uri,
       char const* klass,
-      bool is_static) {
+      bool is_static,
+      const MallocGrowableArray<char*>* experimental_flags) {
     Thread* thread = Thread::Current();
     TransitionNativeToVM transition(thread);
     Dart_CObject tag;
@@ -443,12 +456,25 @@
     isolate_id.value.as_int64 =
         isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
 
-    Dart_CObject message;
-    message.type = Dart_CObject_kArray;
     Dart_CObject suppress_warnings;
     suppress_warnings.type = Dart_CObject_kBool;
     suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
 
+    intptr_t num_experimental_flags = experimental_flags->length();
+    Dart_CObject** experimental_flags_array =
+        new Dart_CObject*[num_experimental_flags];
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      experimental_flags_array[i] = new Dart_CObject;
+      experimental_flags_array[i]->type = Dart_CObject_kString;
+      experimental_flags_array[i]->value.as_string = (*experimental_flags)[i];
+    }
+    Dart_CObject experimental_flags_object;
+    experimental_flags_object.type = Dart_CObject_kArray;
+    experimental_flags_object.value.as_array.values = experimental_flags_array;
+    experimental_flags_object.value.as_array.length = num_experimental_flags;
+
+    Dart_CObject message;
+    message.type = Dart_CObject_kArray;
     Dart_CObject* message_arr[] = {&tag,
                                    &send_port,
                                    &isolate_id,
@@ -458,7 +484,8 @@
                                    &library_uri_object,
                                    &class_object,
                                    &is_static_object,
-                                   &suppress_warnings};
+                                   &suppress_warnings,
+                                   &experimental_flags_object};
     message.value.as_array.values = message_arr;
     message.value.as_array.length = ARRAY_SIZE(message_arr);
 
@@ -486,6 +513,11 @@
     }
     delete[] type_definitions_array;
 
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      delete experimental_flags_array[i];
+    }
+    delete[] experimental_flags_array;
+
     return result_;
   }
 
@@ -500,7 +532,8 @@
       bool incremental_compile,
       const char* package_config,
       const char* multiroot_filepaths,
-      const char* multiroot_scheme) {
+      const char* multiroot_scheme,
+      const MallocGrowableArray<char*>* experimental_flags) {
     // Build the [null, send_port, script_uri, platform_kernel,
     // incremental_compile, isolate_id, [files]] message for the Kernel isolate.
     // tag is used to specify which operation the frontend should perform.
@@ -570,6 +603,19 @@
     suppress_warnings.type = Dart_CObject_kBool;
     suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
 
+    intptr_t num_experimental_flags = experimental_flags->length();
+    Dart_CObject** experimental_flags_array =
+        new Dart_CObject*[num_experimental_flags];
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      experimental_flags_array[i] = new Dart_CObject;
+      experimental_flags_array[i]->type = Dart_CObject_kString;
+      experimental_flags_array[i]->value.as_string = (*experimental_flags)[i];
+    }
+    Dart_CObject experimental_flags_object;
+    experimental_flags_object.type = Dart_CObject_kArray;
+    experimental_flags_object.value.as_array.values = experimental_flags_array;
+    experimental_flags_object.value.as_array.length = num_experimental_flags;
+
     Dart_CObject bytecode;
     bytecode.type = Dart_CObject_kBool;
     // Interpreter is supported only on x64 and arm64.
@@ -625,6 +671,7 @@
                                    &isolate_id,
                                    &files,
                                    &suppress_warnings,
+                                   &experimental_flags_object,
                                    &bytecode,
                                    &package_config_uri,
                                    &multiroot_filepaths_object,
@@ -643,6 +690,11 @@
       ml.Wait();
     }
 
+    for (intptr_t i = 0; i < num_experimental_flags; ++i) {
+      delete experimental_flags_array[i];
+    }
+    delete[] experimental_flags_array;
+
     return result_;
   }
 
@@ -774,11 +826,11 @@
   }
 
   KernelCompilationRequest request;
-  return request.SendAndWaitForResponse(kCompileTag, kernel_port, script_uri,
-                                        platform_kernel, platform_kernel_size,
-                                        source_file_count, source_files,
-                                        incremental_compile, package_config,
-                                        multiroot_filepaths, multiroot_scheme);
+  return request.SendAndWaitForResponse(
+      kCompileTag, kernel_port, script_uri, platform_kernel,
+      platform_kernel_size, source_file_count, source_files,
+      incremental_compile, package_config, multiroot_filepaths,
+      multiroot_scheme, experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::ListDependencies() {
@@ -793,7 +845,7 @@
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
                                         NULL, 0, 0, NULL, false, NULL, NULL,
-                                        NULL);
+                                        NULL, experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
@@ -809,7 +861,8 @@
 
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0,
-                                        0, NULL, true, NULL, NULL, NULL);
+                                        0, NULL, true, NULL, NULL, NULL,
+                                        experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
@@ -831,7 +884,7 @@
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(kernel_port, expression, definitions,
                                         type_definitions, library_url, klass,
-                                        is_static);
+                                        is_static, experimental_flags_);
 }
 
 Dart_KernelCompilationResult KernelIsolate::UpdateInMemorySources(
@@ -848,9 +901,9 @@
   }
 
   KernelCompilationRequest request;
-  return request.SendAndWaitForResponse(kUpdateSourcesTag, kernel_port, NULL,
-                                        NULL, 0, source_files_count,
-                                        source_files, true, NULL, NULL, NULL);
+  return request.SendAndWaitForResponse(
+      kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count,
+      source_files, true, NULL, NULL, NULL, experimental_flags_);
 }
 
 void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index a271351..284177b 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_KERNEL_ISOLATE_H_
 #define RUNTIME_VM_KERNEL_ISOLATE_H_
 
+#include <vector>
+
 #include "include/dart_api.h"
 #include "include/dart_native_api.h"
 
@@ -65,6 +67,8 @@
 
   static void NotifyAboutIsolateShutdown(const Isolate* isolate);
 
+  static void AddExperimentalFlag(const char* value);
+
  protected:
   static Monitor* monitor_;
   static Dart_IsolateCreateCallback create_callback_;
@@ -82,6 +86,8 @@
     return create_callback_;
   }
 
+  static MallocGrowableArray<char*>* experimental_flags_;
+
   friend class Dart;
   friend class Isolate;
   friend class RunKernelTask;
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index abfd7a6..b620f62 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -817,6 +817,93 @@
 LibTest/isolate/ReceivePort/firstWhere_A02_t01: RuntimeError
 LibTest/isolate/ReceivePort/transform_A01_t01: RuntimeError
 
+[ $runtime == vm && $arch != simdbc64 && ($compiler == dartk || $compiler == dartkb) ]
+LanguageFeatures/Constant_update2018/CastOperator_A01_t01: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A02_t01: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/02: Pass
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/03: Pass
+LanguageFeatures/Constant_update2018/CastOperator_A03_t02/01: DartkCrash
+LanguageFeatures/Constant_update2018/CastOperator_A04_t01: Pass
+LanguageFeatures/Constant_update2018/CastOperator_A04_t02: DartkCrash
+LanguageFeatures/Constant_update2018/EqualityOperator_A01_t03: DartkCrash
+LanguageFeatures/Constant_update2018/EqualityOperator_A01_t04: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A01_t01: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A01_t02: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t01: Fail
+LanguageFeatures/Constant_update2018/NewOperators_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t03: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t04: Fail
+LanguageFeatures/Constant_update2018/NewOperators_A02_t05: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t06: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t07: Fail
+LanguageFeatures/Constant_update2018/NewOperators_A02_t08: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t09: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t05: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t05: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: DartkCrash
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t06: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t01: Pass
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t02: Pass
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/01: DartkCrash
+LanguageFeatures/Constant_update2018/TypeTestOperator_A04_t01: Pass
+LanguageFeatures/Constant_update2018/TypeTestOperator_A04_t02: Pass
+LanguageFeatures/Set-literals/constant_set_literals_A02_t01: Pass
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t02/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t03/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A03_t01: Pass
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/05: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/06: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/07: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/08: MissingCompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A05_t01/09: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t01/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/05: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/06: MissingCompileTimeError
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t02/08: MissingCompileTimeError
+LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: Pass
+LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: RuntimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/09: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A01_t01/10: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A04_t01: Pass
+LanguageFeatures/Set-literals/semantics_A05_t05/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A05_t05/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A05_t05/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/semantics_A05_t01: RuntimeError
+LanguageFeatures/Set-literals/set_literals_A01_t01: Pass
+LanguageFeatures/Set-literals/set_literals_A02_t01: Pass
+LanguageFeatures/Set-literals/set_literals_A04_t02/01: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/02: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/03: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/04: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/05: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/11: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/12: MissingCompileTimeError
+LanguageFeatures/Set-literals/set_literals_A04_t02/13: MissingCompileTimeError
+LanguageFeatures/Set-literals/syntax_compatibility_A01_t01: Pass
+
 [ $runtime != vm && $fasta ]
 Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: MissingCompileTimeError # Issue 34192