Version 2.15.0-137.0.dev

Merge commit '63932dc7d3f4a25d5ca1794c68fbe523f38868a4' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fee0ec7..199c8f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -95,10 +95,35 @@
 
 #### Dart VM
 
-- **Breaking Change** [#45451](https://github.com/dart-lang/sdk/issues/45451) :
+- **Breaking Change** [#45451](https://github.com/dart-lang/sdk/issues/45451):
   Support for `dart-ext:`-style native extensions has been removed as previously
   announced. Use `dart:ffi` to bind to native libraries instead.
 
+- **Breaking Change** [#46754](https://github.com/dart-lang/sdk/issues/46754):
+  Isolates spawned via the `Isolate.spawn()` API are now grouped, operate on the
+  same managed heap and can therefore share various VM-internal data structures.
+
+  This leads to ~100x faster isolate startup latency, ~10-100x lower
+  per-isolate base memory overhead and ~8x faster inter-isolate communication.
+
+  Making isolates operate on the same heap will also make them collaborate on
+  garbage collections, which changes performance characteristics for GC-heavy
+  applications that may - in rare cases - negatively affect pause times or
+  throughput.
+
+- Allow closures both in inter-isolate messages as well as as entrypoints in
+  `Isolate.spawn(<entrypoint>, ...)` calls. Closures and their enclosing context
+  may need to be copied in this process. The enclosing context is - as with
+  normal messages - verified to only contain objects that are sendable.
+
+  Note of caution: The Dart VM's current representation of enclosing variables
+  in closures can make closures hang on to more variables than strictly needed.
+  Using such closures in inter-isolate communication can therefore lead to
+  copying of larger transitive object graphs. If the extended transitive
+  closure includes objects that are illegal to send, the sending will fail.
+  See [#36983](https://github.com/dart-lang/sdk/issues/36983), which tracks this
+  existing memory leak issue.
+
 #### Linter
 
 Updated the Linter to `1.12.0`, which includes changes that
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 2989528..ae9b857 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -90,6 +90,11 @@
 
 /// Parses command line arguments and produces a test runner configuration.
 class OptionsParser {
+  /// Allows tests to specify a custom test matrix.
+  final String _testMatrixFile;
+
+  OptionsParser([this._testMatrixFile = 'tools/bots/test_matrix.json']);
+
   static final List<_Option> _options = [
     _Option('mode', 'Mode in which to run the tests.',
         abbr: 'm', values: ['all', ...Mode.names]),
@@ -799,7 +804,7 @@
 
       if (configuration.validate()) {
         result.add(configuration);
-      } else if (namedConfiguration == null) {
+      } else if (namedConfiguration != null) {
         _fail('The named configuration "$namedConfiguration" is invalid.');
       }
     }
@@ -807,8 +812,7 @@
     var namedConfigurationOption = data["named_configuration"] as String;
     if (namedConfigurationOption != null) {
       var namedConfigurations = namedConfigurationOption.split(',');
-      var testMatrixFile = "tools/bots/test_matrix.json";
-      var testMatrix = TestMatrix.fromPath(testMatrixFile);
+      var testMatrix = TestMatrix.fromPath(_testMatrixFile);
       for (var namedConfiguration in namedConfigurations) {
         var configuration = testMatrix.configurations.singleWhere(
             (c) => c.name == namedConfiguration,
@@ -822,7 +826,7 @@
               ' The following configurations are available:\n'
               '  * ${names.join('\n  * ')}');
         }
-        addConfiguration(configuration);
+        addConfiguration(configuration, namedConfiguration);
       }
       return result;
     }
diff --git a/pkg/test_runner/test/options_test.dart b/pkg/test_runner/test/options_test.dart
index cf1b98e..147c3e1 100644
--- a/pkg/test_runner/test/options_test.dart
+++ b/pkg/test_runner/test/options_test.dart
@@ -28,6 +28,10 @@
 
   var configuration = parseConfiguration(['--nnbd=weak']);
   Expect.equals(NnbdMode.weak, configuration.nnbdMode);
+
+  // Filter invalid configurations when not passing a named configuration.
+  configurations = parseConfigurations(['--arch=simarm', '--system=android']);
+  Expect.isEmpty(configurations);
 }
 
 void testValidation() {
@@ -48,6 +52,10 @@
   // Don't allow multiple.
   expectValidationError(['--nnbd=weak,strong'],
       'Only a single value is allowed for option "--nnbd".');
+
+  // Don't allow invalid named configurations.
+  expectValidationError(['-ninvalid-vm-android-simarm'],
+      'The named configuration "invalid-vm-android-simarm" is invalid.');
 }
 
 TestConfiguration parseConfiguration(List<String> arguments) {
@@ -57,7 +65,7 @@
 }
 
 List<TestConfiguration> parseConfigurations(List<String> arguments) {
-  var parser = OptionsParser();
+  var parser = OptionsParser('pkg/test_runner/test/test_matrix.json');
   var configurations = parser.parse(arguments);
 
   // By default, without an explicit selector, you get two configurations, one
@@ -70,7 +78,7 @@
 
 void expectValidationError(List<String> arguments, String error) {
   try {
-    OptionsParser().parse(arguments);
+    OptionsParser('pkg/test_runner/test/test_matrix.json').parse(arguments);
     Expect.fail('Should have thrown an exception, but did not.');
   } on OptionParseException catch (exception) {
     Expect.equals(error, exception.message);
diff --git a/pkg/test_runner/test/test_matrix.json b/pkg/test_runner/test/test_matrix.json
new file mode 100644
index 0000000..778f215
--- /dev/null
+++ b/pkg/test_runner/test/test_matrix.json
@@ -0,0 +1,5 @@
+{
+  "configurations": {
+    "invalid-vm-android-simarm": {}
+  }
+}
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index 24ddf59..2b2499a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 136
+PRERELEASE 137
 PRERELEASE_PATCH 0
\ No newline at end of file