[vm/bytecode] Avoid sorting named parameters in kernel AST when generating bytecode

When generating bytecode, kernel AST was modifed to sort optional named
parameters. This has unfortunate side-effect of breaking default
(non-interpreter) mode if it uses platform.dill with bytecode.

Bytecode generator is changed to avoid modifications to kernel AST.
Instead, sorted named parameters are kept on a side.

Fixes https://github.com/dart-lang/sdk/issues/34305

Change-Id: Iba473f09af0af515b2117e39d63363412433d538
Reviewed-on: https://dart-review.googlesource.com/72546
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 0ec28f7..62fa462 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -741,7 +741,7 @@
       } else {
         assert(numOptionalNamed != 0);
         for (int i = 0; i < numOptionalNamed; i++) {
-          final param = function.namedParameters[i];
+          final param = locals.sortedNamedParameters[i];
           asm.emitLoadConstant(
               numFixed + i, cp.add(new ConstantString(param.name)));
           asm.emitLoadConstant(numFixed + i, _getDefaultParamConstIndex(param));
@@ -867,7 +867,7 @@
         }
       }
       function.positionalParameters.forEach(_copyParamIfCaptured);
-      function.namedParameters.forEach(_copyParamIfCaptured);
+      locals.sortedNamedParameters.forEach(_copyParamIfCaptured);
     }
   }
 
@@ -893,7 +893,7 @@
       }
     }
     function.positionalParameters.forEach(_genArgumentTypeCheck);
-    function.namedParameters.forEach(_genArgumentTypeCheck);
+    locals.sortedNamedParameters.forEach(_genArgumentTypeCheck);
   }
 
   void _genArgumentTypeCheck(VariableDeclaration variable) {
@@ -956,7 +956,7 @@
     // as default value expressions could use local const variables which
     // are not available in bytecode.
     function.positionalParameters.forEach(_evaluateDefaultParameterValue);
-    function.namedParameters.forEach(_evaluateDefaultParameterValue);
+    locals.sortedNamedParameters.forEach(_evaluateDefaultParameterValue);
 
     final int closureFunctionIndex =
         cp.add(new ConstantClosureFunction(name, function));
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 1a780646..45d8351 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -165,6 +165,8 @@
 
   List<VariableDeclaration> get originalNamedParameters =>
       _currentFrame.originalNamedParameters;
+  List<VariableDeclaration> get sortedNamedParameters =>
+      _currentFrame.sortedNamedParameters;
 
   LocalVariables(Member node) {
     final scopeBuilder = new _ScopeBuilder(this);
@@ -214,6 +216,7 @@
   Scope topScope;
 
   List<VariableDeclaration> originalNamedParameters;
+  List<VariableDeclaration> sortedNamedParameters;
   int numParameters = 0;
   int numTypeArguments = 0;
   bool hasOptionalParameters = false;
@@ -271,10 +274,11 @@
 
   _ScopeBuilder(this.locals);
 
-  void _sortNamedParameters(FunctionNode function) {
-    function.namedParameters.sort(
-        (VariableDeclaration a, VariableDeclaration b) =>
-            a.name.compareTo(b.name));
+  List<VariableDeclaration> _sortNamedParameters(FunctionNode function) {
+    final params = function.namedParameters.toList();
+    params.sort((VariableDeclaration a, VariableDeclaration b) =>
+        a.name.compareTo(b.name));
+    return params;
   }
 
   void _visitFunction(TreeNode node) {
@@ -337,11 +341,11 @@
         _declareVariable(_currentFrame.closureVar);
       }
 
-      _currentFrame.originalNamedParameters = function.namedParameters.toList();
-      _sortNamedParameters(function);
+      _currentFrame.originalNamedParameters = function.namedParameters;
+      _currentFrame.sortedNamedParameters = _sortNamedParameters(function);
 
       visitList(function.positionalParameters, this);
-      visitList(function.namedParameters, this);
+      visitList(_currentFrame.sortedNamedParameters, this);
 
       if (_currentFrame.isSyncYielding) {
         // The following variables from parent frame are used implicitly and need
@@ -903,7 +907,7 @@
     for (var param in function.positionalParameters) {
       _allocateParameter(param, count++);
     }
-    for (var param in function.namedParameters) {
+    for (var param in _currentFrame.sortedNamedParameters) {
       _allocateParameter(param, count++);
     }
     assert(count == _currentFrame.numParameters);
diff --git a/pkg/vm/testcases/bytecode/optional_params.dart.expect b/pkg/vm/testcases/bytecode/optional_params.dart.expect
index a8ae7f0..306a642 100644
--- a/pkg/vm/testcases/bytecode/optional_params.dart.expect
+++ b/pkg/vm/testcases/bytecode/optional_params.dart.expect
@@ -214,7 +214,7 @@
   [25] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#12
   [26] = StaticICData target 'dart.core::print', arg-desc CP#12
 }
-]static method foo2(dynamic y, dynamic z, {dynamic a = 42, dynamic b = const <core::String>["default_b"], dynamic c = "default_c"}) → void {
+]static method foo2(dynamic y, dynamic z, {dynamic c = "default_c", dynamic a = 42, dynamic b = const <core::String>["default_b"]}) → void {
   core::print("y = ${y}");
   core::print("z = ${z}");
   core::print("a = ${a}");