[Fasta] Enable running the constant evaluation pass

The experimental flag `constant-update-2018` selects front-end
constant evaluation.  The transformation is run before performing any
backend-specific transformations.

Compiling dart2js in strong mode goes from 12 seconds to between 12.3
and 12.5 (with more variability, apparently).

Change-Id: I279f0e60a3197b4fb077a1e9641ea92cf1409612
Reviewed-on: https://dart-review.googlesource.com/c/88701
Commit-Queue: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
index 3f0c4bc..1441108 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
@@ -4,12 +4,17 @@
 
 // TODO(askesc): Generate this file from a flag specification.
 
-enum ExperimentalFlag { setLiterals }
+enum ExperimentalFlag {
+  setLiterals,
+  constantUpdate2018,
+}
 
 ExperimentalFlag parseExperimentalFlag(String flag) {
   switch (flag) {
     case "set-literals":
       return ExperimentalFlag.setLiterals;
+    case "constant-update-2018":
+      return ExperimentalFlag.constantUpdate2018;
   }
   return null;
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
new file mode 100644
index 0000000..b7372a5
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, 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.
+
+library fasta.kernel_constants;
+
+import 'package:kernel/ast.dart'
+    show
+        Constant,
+        DartType,
+        ListConstant,
+        MapConstant,
+        NullConstant,
+        StaticInvocation,
+        TreeNode;
+
+import 'package:kernel/transformations/constants.dart'
+    show ConstantsBackend, ErrorReporter;
+
+import '../problems.dart' show unimplemented;
+
+class KernelConstantsBackend extends ConstantsBackend {
+  @override
+  Constant lowerListConstant(ListConstant constant) => constant;
+
+  @override
+  Constant lowerMapConstant(MapConstant constant) => constant;
+
+  @override
+  Constant buildConstantForNative(
+      String nativeName,
+      List<DartType> typeArguments,
+      List<Constant> positionalArguments,
+      Map<String, Constant> namedArguments,
+      List<TreeNode> context,
+      StaticInvocation node,
+      ErrorReporter errorReporter,
+      void abortEvaluation()) {
+    // VM-specific names of the fromEnvironment factory constructors.
+    if (nativeName == 'Bool_fromEnvironment' ||
+        nativeName == 'Integer_fromEnvironment' ||
+        nativeName == 'String_fromEnvironment') {
+      return namedArguments['defaultValue'] ?? new NullConstant();
+    }
+    return unimplemented('constant evaluation of ${nativeName}',
+        node.fileOffset, node.location.file);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index e917fb8..39ea072 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -41,6 +41,11 @@
 
 import 'package:kernel/type_algebra.dart' show substitute;
 
+import 'package:kernel/type_environment.dart' show TypeEnvironment;
+
+import 'package:kernel/transformations/constants.dart' as constants
+    show transformLibraries;
+
 import '../../api_prototype/file_system.dart' show FileSystem;
 
 import '../compiler_context.dart' show CompilerContext;
@@ -64,7 +69,7 @@
         templateMissingImplementationCause,
         templateSuperclassHasNoDefaultConstructor;
 
-import '../problems.dart' show unhandled;
+import '../problems.dart' show unhandled, unimplemented;
 
 import '../severity.dart' show Severity;
 
@@ -93,6 +98,8 @@
         TypeBuilder,
         TypeDeclarationBuilder;
 
+import 'kernel_constants.dart' show KernelConstantsBackend;
+
 import 'metadata_collector.dart' show MetadataCollector;
 
 import 'verifier.dart' show verifyComponent;
@@ -741,12 +748,25 @@
   /// Run all transformations that are needed when building a bundle of
   /// libraries for the first time.
   void runBuildTransformations() {
+    if (loader.target.enableConstantUpdate2018) {
+      constants.transformLibraries(
+          loader.libraries,
+          new KernelConstantsBackend(),
+          loader.coreTypes,
+          new TypeEnvironment(loader.coreTypes, loader.hierarchy,
+              legacyMode: false));
+      ticker.logMs("Evaluated constants");
+    }
     backendTarget.performModularTransformationsOnLibraries(
         component, loader.coreTypes, loader.hierarchy, loader.libraries,
         logger: (String msg) => ticker.logMs(msg));
   }
 
   void runProcedureTransformations(Procedure procedure) {
+    if (loader.target.enableConstantUpdate2018) {
+      unimplemented('constant evaluation during expression evaluation',
+          procedure.fileOffset, procedure.fileUri);
+    }
     backendTarget.performTransformationsOnProcedure(
         loader.coreTypes, loader.hierarchy, procedure,
         logger: (String msg) => ticker.logMs(msg));
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
index 6c8f046..2705f16 100644
--- a/pkg/front_end/lib/src/fasta/target_implementation.dart
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -36,10 +36,13 @@
   Declaration cachedNativeExtensionAnnotation;
 
   bool enableSetLiterals;
+  bool enableConstantUpdate2018;
 
   TargetImplementation(Ticker ticker, this.uriTranslator, this.backendTarget)
       : enableSetLiterals = CompilerContext.current.options
             .isExperimentEnabled(ExperimentalFlag.setLiterals),
+        enableConstantUpdate2018 = CompilerContext.current.options
+            .isExperimentEnabled(ExperimentalFlag.constantUpdate2018),
         super(ticker);
 
   /// Creates a [LibraryBuilder] corresponding to [uri], if one doesn't exist