Version 2.11.0-274.0.dev

Merge commit 'd5118d5fc83db077f23b8f7dd5d489634199ad1a' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e40af4..2611829 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,14 @@
 
 #### `dart:io`
 
-*   `HttpRequest` will now correctly follow HTTP 308 redirects
-    (`HttpStatus.permanentRedirect`).
+* `HttpRequest` will now correctly follow HTTP 308 redirects
+  (`HttpStatus.permanentRedirect`).
+
+#### `dart:isolate`
+
+* Added `debugName` positional parameter to `ReceivePort` and `RawReceivePort`
+  constructors, a name which can be associated with the port and displayed in
+  tooling.
 
 ### Dart VM
 
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
index 2788422..7ea8635 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -10,6 +10,15 @@
 class TransformSetErrorCode extends ErrorCode {
   /**
    * Parameters:
+   * 0: the conflicting key
+   * 1: the key that it conflicts with
+   */
+  static const TransformSetErrorCode conflictingKey = TransformSetErrorCode(
+      'conflicting_key',
+      "The key '{0}' can't be used when '{1}' is also used.");
+
+  /**
+   * Parameters:
    * 0: the character that is invalid
    */
   static const TransformSetErrorCode invalidCharacter =
@@ -17,9 +26,16 @@
 
   /**
    * Parameters:
+   * 0: the actual type of the key
+   */
+  static const TransformSetErrorCode invalidKey = TransformSetErrorCode(
+      'invalid_key', "Keys must be of type 'String' but found the type '{0}'.");
+
+  /**
+   * Parameters:
    * 0: the key with which the value is associated
    * 1: the expected type of the value
-   * 0: the actual type of the value
+   * 2: the actual type of the value
    */
   static const TransformSetErrorCode invalidValue = TransformSetErrorCode(
       'invalid_value',
@@ -27,6 +43,14 @@
 
   /**
    * Parameters:
+   * 0: the list of valid parameter styles
+   */
+  static const TransformSetErrorCode invalidParameterStyle =
+      TransformSetErrorCode('invalid_parameter_style',
+          "The parameter style must be one of the following: {0}.");
+
+  /**
+   * Parameters:
    * 0: the key with which the value is associated
    * 1: the allowed values as a comma-separated list
    */
@@ -42,6 +66,14 @@
       TransformSetErrorCode('missing_key', "Missing the required key '{0}'.");
 
   /**
+   * Parameters:
+   * 0: the list of valid keys
+   */
+  static const TransformSetErrorCode missingOneOfMultipleKeys =
+      TransformSetErrorCode('missing_one_of_multiple_keys',
+          "Exactly one of the following keys must be provided: {0}.");
+
+  /**
    * No parameters.
    */
   static const TransformSetErrorCode missingTemplateEnd = TransformSetErrorCode(
@@ -55,6 +87,12 @@
       TransformSetErrorCode('missing_token', "Expected to find {0}.");
 
   /**
+   * No parameters.
+   */
+  static const TransformSetErrorCode missingUri = TransformSetErrorCode(
+      'missing_uri', "At least one URI must be provided.");
+
+  /**
    * Parameters:
    * 0: the missing key
    */
@@ -76,6 +114,12 @@
       'unsupported_key', "The key '{0}' isn't supported.");
 
   /**
+   * No parameters.
+   */
+  static const TransformSetErrorCode unsupportedVersion = TransformSetErrorCode(
+      'unsupported_version', "Only version '1' is supported at this time.");
+
+  /**
    * Parameters:
    * 0: a description of the expected kind of token
    * 1: a description of the actial kind of token
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index a525413..f00f631 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -102,6 +102,9 @@
   static const String _openComponent = '{%';
   static const String _closeComponent = '%}';
 
+  /// The lowest file version supported by this parser.
+  static const int oldestVersion = 1;
+
   /// The highest file version supported by this parser. The version needs to be
   /// incremented any time the parser is updated to disallow input that would
   /// have been valid in the most recently published version of server. This
@@ -260,10 +263,12 @@
     }
   }
 
-  /// Given a [map] and a set of [validKeys], ensure that only one of those keys
-  /// is in the map and return it. If more than one of the keys is in the map,
-  /// report a diagnostic.
-  String _singleKey(YamlMap map, List<String> validKeys) {
+  /// Given a [map] and a set of [validKeys], ensure that exactly one of those
+  /// keys is in the map and return it. If more than one of the keys is in the
+  /// map, report a diagnostic for each extra key. If [required] is `true` and
+  /// none of the keys is in the map, report a diagnostic at the [errorNode].
+  String _singleKey(YamlMap map, List<String> validKeys, YamlNode errorNode,
+      {bool required = true}) {
     assert(validKeys != null);
     var foundKeys = <String>[];
     var keyToNodeMap = <String, YamlNode>{};
@@ -277,14 +282,21 @@
       }
     }
     if (foundKeys.isEmpty) {
-      // TODO(brianwilkerson) Report the problem.
+      if (required) {
+        var validKeysList = validKeys.map((key) => "'$key'").join(', ');
+        _reportError(TransformSetErrorCode.missingOneOfMultipleKeys, errorNode,
+            [validKeysList]);
+      }
       return null;
     }
+    var firstKey = foundKeys[0];
     for (var i = 1; i < foundKeys.length; i++) {
-      // var invalidNode = keyToNodeMap[foundKeys[i]];
-      // TODO(brianwilkerson) Report the problem.
+      var foundKey = foundKeys[i];
+      var invalidNode = keyToNodeMap[foundKey];
+      _reportError(TransformSetErrorCode.conflictingKey, invalidNode,
+          [foundKey, firstKey]);
     }
-    return foundKeys[0];
+    return firstKey;
   }
 
   /// Translate the [node] into a add-parameter modification.
@@ -294,19 +306,26 @@
     var index = _translateInteger(node.valueAt(_indexKey),
         ErrorContext(key: _indexKey, parentNode: node));
     if (index == null) {
+      // The error has already been reported.
       return;
     }
     var name = _translateString(
         node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
     if (name == null) {
+      // The error has already been reported.
       return;
     }
-    var style = _translateString(node.valueAt(_styleKey),
-        ErrorContext(key: _styleKey, parentNode: node));
+    var styleNode = node.valueAt(_styleKey);
+    var style = _translateString(
+        styleNode, ErrorContext(key: _styleKey, parentNode: node));
     if (style == null) {
+      // The error has already been reported.
       return;
-    } else if (!validStyles.contains(style)) {
-      // TODO(brianwilkerson) Report the invalid style.
+    }
+    if (!validStyles.contains(style)) {
+      var validStylesList = validStyles.map((style) => "'$style'").join(', ');
+      _reportError(TransformSetErrorCode.invalidParameterStyle, styleNode,
+          [validStylesList]);
       return;
     }
     var isRequired = style.startsWith('required_');
@@ -348,10 +367,10 @@
       // The error has already been reported.
       return null;
     }
-    // TODO(brianwilkerson) In order to support adding multiple type parameters
-    //  we might need to introduce a `TypeParameterModification` change, similar
-    //  to `ParameterModification`. That becomes more likely if we add support
-    //  for removing type parameters.
+    // In order to support adding multiple type parameters we might need to
+    // introduce a `TypeParameterModification` change, similar to
+    // `ParameterModification`. That becomes more likely if we add support for
+    // removing type parameters.
     return AddTypeParameter(
         index: index,
         name: name,
@@ -458,7 +477,8 @@
           template = _translateString(statementsNode,
               ErrorContext(key: _statementsKey, parentNode: node));
         } else {
-          // TODO(brianwilkerson) Report the missing key.
+          _reportError(TransformSetErrorCode.missingOneOfMultipleKeys, node,
+              ["'$_expressionKey' or '$_statementsKey'"]);
           return null;
         }
       }
@@ -505,23 +525,27 @@
   /// error.
   ElementDescriptor _translateElement(YamlNode node, ErrorContext context) {
     if (node is YamlMap) {
-      var uris = _translateList(node.valueAt(_urisKey),
+      var urisNode = node.valueAt(_urisKey);
+      var uris = _translateList(urisNode,
           ErrorContext(key: _urisKey, parentNode: node), _translateUri);
-      var elementKey = _singleKey(node, const [
-        _classKey,
-        _constantKey,
-        _constructorKey,
-        _enumKey,
-        _extensionKey,
-        _fieldKey,
-        _functionKey,
-        _getterKey,
-        _methodKey,
-        _mixinKey,
-        _setterKey,
-        _typedefKey,
-        _variableKey
-      ]);
+      var elementKey = _singleKey(
+          node,
+          const [
+            _classKey,
+            _constantKey,
+            _constructorKey,
+            _enumKey,
+            _extensionKey,
+            _fieldKey,
+            _functionKey,
+            _getterKey,
+            _methodKey,
+            _mixinKey,
+            _setterKey,
+            _typedefKey,
+            _variableKey
+          ],
+          node);
       if (elementKey == null) {
         // The error has already been reported.
         return null;
@@ -534,14 +558,19 @@
       }
       var components = [elementName];
       if (_containerKeyMap.containsKey(elementKey)) {
-        var containerKey = _singleKey(node, _containerKeyMap[elementKey]);
+        var validContainerKeys = _containerKeyMap[elementKey];
+        var containerKey =
+            _singleKey(node, validContainerKeys, node, required: false);
         var containerName = _translateString(node.valueAt(containerKey),
             ErrorContext(key: containerKey, parentNode: node),
             required: false);
         if (containerName == null) {
           if ([_constructorKey, _constantKey, _methodKey, _fieldKey]
               .contains(elementKey)) {
-            // TODO(brianwilkerson) Report that no container was found.
+            var validKeysList =
+                validContainerKeys.map((key) => "'$key'").join(', ');
+            _reportError(TransformSetErrorCode.missingOneOfMultipleKeys, node,
+                [validKeysList]);
             return null;
           }
         } else {
@@ -552,6 +581,12 @@
         // The error has already been reported.
         return null;
       }
+      if (uris.isEmpty) {
+        if ((urisNode as YamlList).isEmpty) {
+          _reportError(TransformSetErrorCode.missingUri, urisNode);
+        }
+        return null;
+      }
       return ElementDescriptor(
           libraryUris: uris,
           kind: ElementKindUtilities.fromName(elementKey),
@@ -568,8 +603,9 @@
   /// extractor.
   ValueGenerator _translateImportValue(YamlMap node) {
     _reportUnsupportedKeys(node, const {_kindKey, _nameKey, _urisKey});
-    var uris = _translateList(node.valueAt(_urisKey),
-        ErrorContext(key: _urisKey, parentNode: node), _translateUri);
+    var urisNode = node.valueAt(_urisKey);
+    var uris = _translateList(
+        urisNode, ErrorContext(key: _urisKey, parentNode: node), _translateUri);
     var name = _translateString(
         node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
     if (uris == null || name == null) {
@@ -577,9 +613,9 @@
       return null;
     }
     if (uris.isEmpty) {
-      // TODO(brianwilkerson) Report an empty list unless it's only empty
-      //  because the elements generated errors. This probably needs to be done
-      //  in [_translateList].
+      if ((urisNode as YamlList).isEmpty) {
+        _reportError(TransformSetErrorCode.missingUri, urisNode);
+      }
       return null;
     }
     return ImportedName(uris, name);
@@ -604,11 +640,20 @@
 
   /// Translate the given [node] as a key.
   String _translateKey(YamlNode node) {
-    if (node is YamlScalar && node.value is String) {
-      return node.value as String;
+    String type;
+    if (node is YamlScalar) {
+      if (node.value is String) {
+        return node.value as String;
+      }
+      type = node.value.runtimeType.toString();
+    } else if (node is YamlList) {
+      type = 'List';
+    } else if (node is YamlMap) {
+      type = 'Map';
+    } else {
+      type = node.runtimeType.toString();
     }
-    // TODO(brianwilkerson) Report the invalidKey.
-    //  "Keys must be of type 'String' but found the type '{0}'."
+    _reportError(TransformSetErrorCode.invalidKey, node, [type]);
     return null;
   }
 
@@ -638,12 +683,12 @@
   /// Translate the [node] into a remove-parameter modification.
   void _translateRemoveParameterChange(YamlMap node) {
     _reportUnsupportedKeys(node, const {_indexKey, _kindKey, _nameKey});
-    ParameterReference reference;
-    var parameterSpecKey = _singleKey(node, const [_nameKey, _indexKey]);
+    var parameterSpecKey = _singleKey(node, const [_nameKey, _indexKey], node);
     if (parameterSpecKey == null) {
       // The error has already been reported.
       return null;
     }
+    ParameterReference reference;
     if (parameterSpecKey == _indexKey) {
       var index = _translateInteger(node.valueAt(_indexKey),
           ErrorContext(key: _indexKey, parentNode: node));
@@ -769,13 +814,14 @@
     assert(node != null);
     if (node is YamlMap) {
       _reportUnsupportedKeys(node, const {_transformsKey, _versionKey});
-      var version = _translateInteger(node.valueAt(_versionKey),
-          ErrorContext(key: _versionKey, parentNode: node));
+      var versionNode = node.valueAt(_versionKey);
+      var version = _translateInteger(
+          versionNode, ErrorContext(key: _versionKey, parentNode: node));
       if (version == null) {
         // The error has already been reported.
         return null;
-      } else if (version > currentVersion) {
-        // TODO(brianwilkerson) Report that the version is unsupported.
+      } else if (version < 1 || version > currentVersion) {
+        _reportError(TransformSetErrorCode.unsupportedVersion, versionNode);
         return null;
       }
       // TODO(brianwilkerson) Version information is currently being ignored,
diff --git a/pkg/analysis_server/test/src/cider/completion_test.dart b/pkg/analysis_server/test/src/cider/completion_test.dart
index 5450ef6..f37076b 100644
--- a/pkg/analysis_server/test/src/cider/completion_test.dart
+++ b/pkg/analysis_server/test/src/cider/completion_test.dart
@@ -330,6 +330,34 @@
     ]);
   }
 
+  Future<void> test_limitedResolution_class_constructor_body() async {
+    _configureToCheckNotResolved(
+      identifiers: {'print'},
+    );
+
+    await _compute(r'''
+class A<T> {
+  int f = 0;
+
+  A(int a) : f = 1 {
+    ^
+  }
+
+  void foo() {
+    print(0);
+  }
+}
+''');
+
+    _assertHasClass(text: 'A');
+    _assertHasClass(text: 'String');
+    _assertHasConstructor(text: 'A');
+    _assertHasFunction(text: 'print');
+    _assertHasMethod(text: 'foo');
+    _assertHasParameter(text: 'a');
+    _assertHasTypeParameter(text: 'T');
+  }
+
   Future<void> test_limitedResolution_class_field_startWithType() async {
     _configureToCheckNotResolved(
       identifiers: {'print'},
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart
new file mode 100644
index 0000000..77d6de7
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConflictingKeyTest);
+  });
+}
+
+@reflectiveTest
+class ConflictingKeyTest extends AbstractTransformSetParserTest {
+  void test_element() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+    method: 'm'
+    class: 'C'
+  changes: []
+''', [
+      error(TransformSetErrorCode.missingOneOfMultipleKeys, 69, 53),
+      error(TransformSetErrorCode.conflictingKey, 109, 5),
+    ]);
+  }
+
+  void test_removeParameterChange() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+    function: 'f'
+  changes:
+    - kind: removeParameter
+      index: 2
+      name: 'p'
+''', [
+      error(TransformSetErrorCode.conflictingKey, 167, 4),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart
new file mode 100644
index 0000000..0a7c158
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidKeyTest);
+  });
+}
+
+@reflectiveTest
+class InvalidKeyTest extends AbstractTransformSetParserTest {
+  void test_integer() {
+    assertErrors('''
+3: 4
+version: 1
+transforms: []
+''', [
+      error(TransformSetErrorCode.invalidKey, 0, 1),
+    ]);
+  }
+
+  void test_list() {
+    assertErrors('''
+[]: 4
+version: 1
+transforms: []
+''', [
+      error(TransformSetErrorCode.invalidKey, 0, 2),
+    ]);
+  }
+
+  void test_map() {
+    assertErrors('''
+{}: 4
+version: 1
+transforms: []
+''', [
+      error(TransformSetErrorCode.invalidKey, 0, 2),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart
new file mode 100644
index 0000000..0fe38db
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidParameterStyleTest);
+  });
+}
+
+@reflectiveTest
+class InvalidParameterStyleTest extends AbstractTransformSetParserTest {
+  void test_invalid() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+    method: 'm'
+    inClass: 'C'
+  changes:
+    - kind: addParameter
+      style: named
+      index: 0
+      name: 'p'
+      argumentValue:
+        expression: ''
+''', [
+      error(TransformSetErrorCode.invalidParameterStyle, 171, 5),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
index 148f8a4..1237ba0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
@@ -128,10 +128,9 @@
     - kind: 'addTypeParameter'
       name: 'a'
       argumentValue:
-        kind: 'argument'
-        index: 0
+        expression: ''
 ''', [
-      error(TransformSetErrorCode.missingKey, 124, 104),
+      error(TransformSetErrorCode.missingKey, 124, 85),
     ]);
   }
 
@@ -148,10 +147,9 @@
     - kind: 'addTypeParameter'
       index: 0
       argumentValue:
-        kind: 'argument'
-        index: 0
+        expression: ''
 ''', [
-      error(TransformSetErrorCode.missingKey, 124, 103),
+      error(TransformSetErrorCode.missingKey, 124, 84),
     ]);
   }
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart
new file mode 100644
index 0000000..255767b
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingOneOfMultipleKeysTest);
+  });
+}
+
+@reflectiveTest
+class MissingOneOfMultipleKeysTest extends AbstractTransformSetParserTest {
+  void test_codeTemplate() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+    function: 'f'
+  changes:
+    - kind: addTypeParameter
+      index: 0
+      name: 'T'
+      argumentValue:
+        variables: []
+''', [
+      error(TransformSetErrorCode.missingOneOfMultipleKeys, 207, 14),
+    ]);
+  }
+
+  void test_element() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+  changes: []
+''', [
+      error(TransformSetErrorCode.missingOneOfMultipleKeys, 69, 22),
+    ]);
+  }
+
+  void test_element_container() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+    method: 'm'
+  changes: []
+''', [
+      error(TransformSetErrorCode.missingOneOfMultipleKeys, 69, 38),
+    ]);
+  }
+
+  void test_removeParameterChange() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['test.dart']
+    function: 'f'
+  changes:
+    - kind: removeParameter
+''', [
+      error(TransformSetErrorCode.missingOneOfMultipleKeys, 124, 22),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart
new file mode 100644
index 0000000..ac21bfc
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingUriTest);
+  });
+}
+
+@reflectiveTest
+class MissingUriTest extends AbstractTransformSetParserTest {
+  void test_element_empty() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: []
+    method: 'm'
+    inClass: 'C'
+  changes: []
+''', [
+      error(TransformSetErrorCode.missingUri, 75, 2),
+    ]);
+  }
+
+  void test_element_nonEmpty() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: [3]
+    method: 'm'
+    inClass: 'C'
+  changes: []
+''', [
+      error(TransformSetErrorCode.invalidValue, 76, 1),
+    ]);
+  }
+
+  void test_import_empty() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['']
+    method: 'm'
+    inClass: 'C'
+  changes:
+    - kind: 'addTypeParameter'
+      index: 0
+      name: 'T'
+      argumentValue:
+        expression: ''
+        variables:
+          t:
+            kind: 'import'
+            uris: []
+            name: 'String'
+''', [
+      error(TransformSetErrorCode.missingUri, 307, 2),
+    ]);
+  }
+
+  void test_import_nonEmpty() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2020-09-14
+  element:
+    uris: ['']
+    method: 'm'
+    inClass: 'C'
+  changes:
+    - kind: 'addTypeParameter'
+      index: 0
+      name: 'T'
+      argumentValue:
+        expression: ''
+        variables:
+          t:
+            kind: 'import'
+            uris: [3]
+            name: 'String'
+''', [
+      error(TransformSetErrorCode.invalidValue, 308, 1),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
index d8b87c6..651508b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
@@ -4,29 +4,41 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'conflicting_key_test.dart' as conflicting_key;
 import 'invalid_character_test.dart' as invalid_character;
+import 'invalid_key_test.dart' as invalid_key;
+import 'invalid_parameter_style_test.dart' as invalid_parameter_style;
 import 'invalid_value_one_of_test.dart' as invalid_value_one_of;
 import 'invalid_value_test.dart' as invalid_value;
 import 'missing_key_test.dart' as missing_key;
+import 'missing_one_of_multiple_keys_test.dart' as missing_one_of_multiple_keys;
 import 'missing_template_end_test.dart' as missing_template_end;
 import 'missing_token_test.dart' as missing_token;
+import 'missing_uri_test.dart' as missing_uri;
 import 'undefined_variable_test.dart' as undefined_variable;
 import 'unknown_accessor_test.dart' as unknown_accessor;
 import 'unsupported_key_test.dart' as unsupported_key;
+import 'unsupported_version_test.dart' as unsupported_version;
 import 'wrong_token_test.dart' as wrong_token;
 import 'yaml_syntax_error_test.dart' as yaml_syntax_error;
 
 void main() {
   defineReflectiveSuite(() {
+    conflicting_key.main();
     invalid_character.main();
+    invalid_key.main();
+    invalid_parameter_style.main();
     invalid_value_one_of.main();
     invalid_value.main();
     missing_key.main();
+    missing_one_of_multiple_keys.main();
     missing_template_end.main();
     missing_token.main();
+    missing_uri.main();
     undefined_variable.main();
     unknown_accessor.main();
     unsupported_key.main();
+    unsupported_version.main();
     wrong_token.main();
     yaml_syntax_error.main();
   });
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart
new file mode 100644
index 0000000..606341f
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnsupportedVersionTest);
+  });
+}
+
+@reflectiveTest
+class UnsupportedVersionTest extends AbstractTransformSetParserTest {
+  void test_tooHigh() {
+    var version = (TransformSetParser.currentVersion + 1).toString();
+    assertErrors('''
+version: $version
+transforms: []
+''', [
+      error(TransformSetErrorCode.unsupportedVersion, 9, version.length),
+    ]);
+  }
+
+  void test_tooLow() {
+    var version = (TransformSetParser.oldestVersion - 1).toString();
+    assertErrors('''
+version: $version
+transforms: []
+''', [
+      error(TransformSetErrorCode.unsupportedVersion, 9, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 0695ce0..00352e2 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -719,7 +719,15 @@
       var enclosingExecutable = node?.thisOrAncestorMatching((e) {
         return e.parent is ClassDeclaration || e.parent is CompilationUnit;
       });
-      enclosingExecutable?.accept(resolverVisitor);
+
+      if (enclosingExecutable != null) {
+        var enclosingClass = enclosingExecutable.parent;
+        if (enclosingClass is ClassDeclaration) {
+          resolverVisitor.enclosingClass = enclosingClass.declaredElement;
+        }
+
+        enclosingExecutable?.accept(resolverVisitor);
+      }
     } else {
       unit.accept(resolverVisitor);
     }
diff --git a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
index af82bcf..fd22ea0 100644
--- a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
+++ b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
@@ -248,6 +248,7 @@
       var pathEntry = _asString(dependency[PATH_FIELD]);
       if (pathEntry != null) {
         YamlNode pathKey() => getKey(dependency, PATH_FIELD);
+        YamlNode pathValue() => getValue(dependency, PATH_FIELD);
         var context = provider.pathContext;
         var normalizedPath = context.joinAll(path.posix.split(pathEntry));
         var packageRoot = context.dirname(source.fullName);
@@ -256,13 +257,13 @@
         dependencyPath = context.normalize(dependencyPath);
         var packageFolder = provider.getFolder(dependencyPath);
         if (!packageFolder.exists) {
-          _reportErrorForNode(reporter, pathKey(),
+          _reportErrorForNode(reporter, pathValue(),
               PubspecWarningCode.PATH_DOES_NOT_EXIST, [pathEntry]);
         } else {
           if (!packageFolder
               .getChild(AnalysisEngine.PUBSPEC_YAML_FILE)
               .exists) {
-            _reportErrorForNode(reporter, pathKey(),
+            _reportErrorForNode(reporter, pathValue(),
                 PubspecWarningCode.PATH_PUBSPEC_DOES_NOT_EXIST, [pathEntry]);
           }
         }
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index e999cd9..9157cbf 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -240,6 +240,7 @@
 
   /// Whether to generate code asserting that non-nullable return values of
   /// `@Native` methods or `JS()` invocations are checked for being non-null.
+  /// Emits checks only in sound null-safety.
   bool nativeNullAssertions = false;
   bool _noNativeNullAssertions = false;
 
@@ -599,7 +600,9 @@
       enableMinification = false;
     }
 
-    if (_noNativeNullAssertions) nativeNullAssertions = false;
+    if (_noNativeNullAssertions || nullSafetyMode != NullSafetyMode.sound) {
+      nativeNullAssertions = false;
+    }
   }
 
   /// Returns `true` if warnings and hints are shown for all packages.
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 464ff44..8c009af 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -1776,14 +1776,23 @@
   js_ast.Fun _emitNativeFunctionBody(Procedure node) {
     var name = _annotationName(node, isJSAnnotation) ?? node.name.text;
     if (node.isGetter) {
-      return js_ast.Fun([], js.block('{ return this.#; }', [name]));
+      var returnValue = js('this.#', [name]);
+      if (_isNullCheckableNative(node)) {
+        // Add a potential null-check on native getter if type is non-nullable.
+        returnValue = runtimeCall('checkNativeNonNull(#)', [returnValue]);
+      }
+      return js_ast.Fun([], js.block('{ return #; }', [returnValue]));
     } else if (node.isSetter) {
       var params = _emitParameters(node.function);
       return js_ast.Fun(
           params, js.block('{ this.# = #; }', [name, params.last]));
     } else {
-      return js.fun(
-          'function (...args) { return this.#.apply(this, args); }', name);
+      var returnValue = js('this.#.apply(this, args)', [name]);
+      if (_isNullCheckableNative(node)) {
+        // Add a potential null-check on return value if type is non-nullable.
+        returnValue = runtimeCall('checkNativeNonNull(#)', [returnValue]);
+      }
+      return js.fun('function (...args) { return #; }', [returnValue]);
     }
   }
 
@@ -2270,6 +2279,10 @@
       // Fields on a native class are implicitly native.
       // Methods/getters/setters are marked external/native.
       if (member is Field || _isExternal(member)) {
+        // If the native member needs to be null-checked and we're running in
+        // sound null-safety, we require symbolizing it in order to access the
+        // null-check at the member definition.
+        if (_isNullCheckableNative(member)) return true;
         var jsName = _annotationName(member, isJSName);
         return jsName != null && jsName != name;
       } else {
@@ -4215,14 +4228,8 @@
 
   @override
   js_ast.Expression visitPropertyGet(PropertyGet node) {
-    var propertyGet =
-        _emitPropertyGet(node.receiver, node.interfaceTarget, node.name.text);
-    if (_isCheckableNative(node.interfaceTarget)) {
-      // If target is a native getter with a non-nullable type, add a null check
-      // for soundness.
-      return runtimeCall('checkNativeNonNull(#)', [propertyGet]);
-    }
-    return propertyGet;
+    return _emitPropertyGet(
+        node.receiver, node.interfaceTarget, node.name.text);
   }
 
   @override
@@ -4276,8 +4283,11 @@
   }
 
   /// Return whether [member] returns a native object whose type needs to be
-  /// checked.
-  bool _isCheckableNative(Member member) =>
+  /// null-checked in sound null-safety.
+  ///
+  /// This is true for non-nullable native return types.
+  bool _isNullCheckableNative(Member member) =>
+      _options.soundNullSafety &&
       member != null &&
       member.isExternal &&
       _extensionTypes.isNativeClass(member.enclosingClass) &&
@@ -4356,14 +4366,8 @@
 
   @override
   js_ast.Expression visitMethodInvocation(MethodInvocation node) {
-    var methodCall = _emitMethodCall(
+    return _emitMethodCall(
         node.receiver, node.interfaceTarget, node.arguments, node);
-    if (_isCheckableNative(node.interfaceTarget)) {
-      // If target is a native method with a non-nullable type, add a null check
-      // for soundness.
-      return runtimeCall('checkNativeNonNull(#)', [methodCall]);
-    }
-    return methodCall;
   }
 
   js_ast.Expression _emitMethodCall(Expression receiver, Member target,
@@ -5092,8 +5096,8 @@
     var result = js.parseForeignJS(source).instantiate(jsArgs);
 
     // Add a check to make sure any JS() values from a native type are typed
-    // properly.
-    if (_isWebLibrary(_currentLibrary.importUri)) {
+    // properly in sound null-safety.
+    if (_isWebLibrary(_currentLibrary.importUri) && _options.soundNullSafety) {
       var type = node.getStaticType(_staticTypeContext);
       if (type.isPotentiallyNonNullable) {
         result = runtimeCall('checkNativeNonNull(#)', [result]);
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index de7521d..4be55af 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -142,6 +142,12 @@
   "collection": {
     ExperimentalFlag.nonNullable,
   },
+  "connectivity": {
+    ExperimentalFlag.nonNullable,
+  },
+  "connectivity_platform_interface": {
+    ExperimentalFlag.nonNullable,
+  },
   "convert": {
     ExperimentalFlag.nonNullable,
   },
@@ -154,6 +160,12 @@
   "dart_internal": {
     ExperimentalFlag.nonNullable,
   },
+  "device_info": {
+    ExperimentalFlag.nonNullable,
+  },
+  "device_info_platform_interface": {
+    ExperimentalFlag.nonNullable,
+  },
   "fake_async": {
     ExperimentalFlag.nonNullable,
   },
@@ -217,6 +229,9 @@
   "platform": {
     ExperimentalFlag.nonNullable,
   },
+  "plugin_platform_interface": {
+    ExperimentalFlag.nonNullable,
+  },
   "pool": {
     ExperimentalFlag.nonNullable,
   },
@@ -262,7 +277,31 @@
   "typed_data": {
     ExperimentalFlag.nonNullable,
   },
+  "url_launcher": {
+    ExperimentalFlag.nonNullable,
+  },
+  "url_launcher_linux": {
+    ExperimentalFlag.nonNullable,
+  },
+  "url_launcher_macos": {
+    ExperimentalFlag.nonNullable,
+  },
+  "url_launcher_platform_interface": {
+    ExperimentalFlag.nonNullable,
+  },
+  "url_launcher_windows": {
+    ExperimentalFlag.nonNullable,
+  },
   "vector_math": {
     ExperimentalFlag.nonNullable,
   },
+  "video_player": {
+    ExperimentalFlag.nonNullable,
+  },
+  "video_player_platform_interface": {
+    ExperimentalFlag.nonNullable,
+  },
+  "video_player_web": {
+    ExperimentalFlag.nonNullable,
+  },
 });
diff --git a/pkg/front_end/lib/src/base/command_line_options.dart b/pkg/front_end/lib/src/base/command_line_options.dart
index 3f5b1ce..a87824f 100644
--- a/pkg/front_end/lib/src/base/command_line_options.dart
+++ b/pkg/front_end/lib/src/base/command_line_options.dart
@@ -20,7 +20,6 @@
 
   static const String linkDependencies = "--link-dependencies";
 
-  static const String bytecode = "--bytecode";
   static const String compileSdk = "--compile-sdk";
   static const String dumpIr = "--dump-ir";
   static const String enableExperiment = "--enable-experiment";
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 2acc197..1b3dce8 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -223,6 +223,7 @@
 config
 configs
 configured
+connectivity
 consideration
 constness
 consult
@@ -304,6 +305,7 @@
 destroy
 deterministic
 dev
+device
 diff
 diffs
 digest
@@ -590,6 +592,7 @@
 lacks
 lang
 largest
+launcher
 lattice
 layer
 layout
@@ -610,6 +613,7 @@
 linearized
 linebreak
 linter
+linux
 lives
 ll
 llub
@@ -632,6 +636,7 @@
 ly
 lz
 m
+macos
 maintaining
 mangled
 manipulation
@@ -806,6 +811,7 @@
 pi
 picking
 pkg
+player
 plugin
 pm
 pn
@@ -1251,6 +1257,7 @@
 verbosity
 versa
 vice
+video
 violated
 visit*
 visitors
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index 470e340..9715fb6 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -481,6 +481,8 @@
     final platformKernel =
         computePlatformBinariesLocation().resolve('vm_platform_strong.dill');
     final ddcPlatformKernel =
+        computePlatformBinariesLocation().resolve('ddc_outline_sound.dill');
+    final ddcPlatformKernelWeak =
         computePlatformBinariesLocation().resolve('ddc_sdk.dill');
     final sdkRoot = computePlatformBinariesLocation();
 
@@ -496,14 +498,32 @@
 
     test('compile expression', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
-      file.writeAsStringSync("main() {}\n");
+      file.writeAsStringSync("main() {\n}\n");
       var dillFile = File('${tempDir.path}/app.dill');
+
+      var package_config =
+          File('${tempDir.path}/.dart_tool/package_config.json')
+            ..createSync(recursive: true)
+            ..writeAsStringSync('''
+  {
+    "configVersion": 2,
+    "packages": [
+      {
+        "name": "hello",
+        "rootUri": "../",
+        "packageUri": "./"
+      }
+    ]
+  }
+  ''');
+
       expect(dillFile.existsSync(), equals(false));
       final List<String> args = <String>[
         '--sdk-root=${sdkRoot.toFilePath()}',
         '--incremental',
         '--platform=${platformKernel.path}',
-        '--output-dill=${dillFile.path}'
+        '--output-dill=${dillFile.path}',
+        '--packages=${package_config.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -1714,10 +1734,22 @@
 
     test('compile to JavaScript', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
-      file.writeAsStringSync("main() {}\n");
-      var packages = File('${tempDir.path}/.packages')
-        ..createSync()
-        ..writeAsStringSync("\n");
+      file.writeAsStringSync("main() {\n}\n");
+      var package_config =
+          File('${tempDir.path}/.dart_tool/package_config.json')
+            ..createSync(recursive: true)
+            ..writeAsStringSync('''
+  {
+    "configVersion": 2,
+    "packages": [
+      {
+        "name": "hello",
+        "rootUri": "../",
+        "packageUri": "./"
+      }
+    ]
+  }
+  ''');
       var dillFile = File('${tempDir.path}/app.dill');
 
       expect(dillFile.existsSync(), false);
@@ -1727,8 +1759,9 @@
         '--incremental',
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
-        '--packages=${packages.path}',
+        '--packages=${package_config.path}',
         '--target=dartdevc',
+        '--enable-experiment=non-nullable',
         file.path,
       ];
 
@@ -1737,8 +1770,8 @@
 
     test('compile to JavaScript with package scheme', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
-      file.writeAsStringSync("main() {}\n");
-      File('${tempDir.path}/.packages')
+      file.writeAsStringSync("main() {\n}\n");
+      var packages = File('${tempDir.path}/.packages')
         ..createSync()
         ..writeAsStringSync("hello:${tempDir.uri}\n");
       var dillFile = File('${tempDir.path}/app.dill');
@@ -1748,22 +1781,118 @@
       final List<String> args = <String>[
         '--sdk-root=${sdkRoot.toFilePath()}',
         '--incremental',
-        '--platform=${ddcPlatformKernel.path}',
+        '--platform=${ddcPlatformKernelWeak.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${tempDir.path}/.packages',
+        '--packages=${packages.path}',
         'package:hello/foo.dart'
       ];
 
       expect(await starter(args), 0);
-    });
+    }, skip: 'https://github.com/dart-lang/sdk/issues/43959');
+
+    test('compile to JavaScript weak null safety', () async {
+      var file = File('${tempDir.path}/foo.dart')..createSync();
+      file.writeAsStringSync("// @dart = 2.9\nmain() {\n}\n");
+      var packages = File('${tempDir.path}/.packages')
+        ..createSync()
+        ..writeAsStringSync("hello:${tempDir.uri}\n");
+      var dillFile = File('${tempDir.path}/app.dill');
+
+      expect(dillFile.existsSync(), false);
+
+      final List<String> args = <String>[
+        '--sdk-root=${sdkRoot.toFilePath()}',
+        '--incremental',
+        '--platform=${ddcPlatformKernelWeak.path}',
+        '--output-dill=${dillFile.path}',
+        '--target=dartdevc',
+        '--packages=${packages.path}',
+        'package:hello/foo.dart'
+      ];
+
+      expect(await starter(args), 0);
+    }, skip: 'https://github.com/dart-lang/sdk/issues/43959');
+
+    test('compile to JavaScript weak null safety then non-existent file',
+        () async {
+      var file = File('${tempDir.path}/foo.dart')..createSync();
+      file.writeAsStringSync("// @dart = 2.9\nmain() {\n}\n");
+      var packages = File('${tempDir.path}/.packages')
+        ..createSync()
+        ..writeAsStringSync("hello:${tempDir.uri}\n");
+      var dillFile = File('${tempDir.path}/app.dill');
+
+      expect(dillFile.existsSync(), false);
+
+      var library = 'package:hello/foo.dart';
+
+      final List<String> args = <String>[
+        '--sdk-root=${sdkRoot.toFilePath()}',
+        '--incremental',
+        '--platform=${ddcPlatformKernelWeak.path}',
+        '--output-dill=${dillFile.path}',
+        '--target=dartdevc',
+        '--packages=${packages.path}',
+      ];
+
+      final StreamController<List<int>> streamController =
+          StreamController<List<int>>();
+      final StreamController<List<int>> stdoutStreamController =
+          StreamController<List<int>>();
+      final IOSink ioSink = IOSink(stdoutStreamController.sink);
+      StreamController<Result> receivedResults = StreamController<Result>();
+      final outputParser = OutputParser(receivedResults);
+      stdoutStreamController.stream
+          .transform(utf8.decoder)
+          .transform(const LineSplitter())
+          .listen(outputParser.listener);
+
+      Future<int> result =
+          starter(args, input: streamController.stream, output: ioSink);
+      streamController.add('compile $library\n'.codeUnits);
+      var count = 0;
+      receivedResults.stream.listen((Result compiledResult) {
+        CompilationResult result =
+            CompilationResult.parse(compiledResult.status);
+        count++;
+        if (count == 1) {
+          // First request is to 'compile', which results in full JavaScript
+          expect(result.errorsCount, equals(0));
+          expect(result.filename, dillFile.path);
+          streamController.add('accept\n'.codeUnits);
+          streamController.add('compile foo.bar\n'.codeUnits);
+        } else {
+          expect(count, 2);
+          // Second request is to 'compile' non-existent file, that should fail.
+          expect(result.errorsCount, greaterThan(0));
+          streamController.add('quit\n'.codeUnits);
+        }
+      });
+
+      expect(await result, 0);
+      expect(count, 2);
+    }, skip: 'https://github.com/dart-lang/sdk/issues/43959');
 
     test('compile to JavaScript with no metadata', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n\n}\n");
-      File('${tempDir.path}/.packages')
-        ..createSync()
-        ..writeAsStringSync("hello:${tempDir.uri}\n");
+
+      var package_config =
+          File('${tempDir.path}/.dart_tool/package_config.json')
+            ..createSync(recursive: true)
+            ..writeAsStringSync('''
+  {
+    "configVersion": 2,
+    "packages": [
+      {
+        "name": "hello",
+        "rootUri": "../",
+        "packageUri": "./"
+      }
+    ]
+  }
+  ''');
 
       var library = 'package:hello/foo.dart';
 
@@ -1785,7 +1914,8 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${tempDir.path}/.packages',
+        '--packages=${package_config.path}',
+        '--enable-experiment=non-nullable',
       ];
 
       final StreamController<List<int>> streamController =
@@ -1827,9 +1957,21 @@
     test('compile to JavaScript with metadata', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n\n}\n");
-      File('${tempDir.path}/.packages')
-        ..createSync()
-        ..writeAsStringSync("hello:${tempDir.uri}\n");
+      var package_config =
+          File('${tempDir.path}/.dart_tool/package_config.json')
+            ..createSync(recursive: true)
+            ..writeAsStringSync('''
+  {
+    "configVersion": 2,
+    "packages": [
+      {
+        "name": "hello",
+        "rootUri": "../",
+        "packageUri": "./"
+      }
+    ]
+  }
+  ''');
 
       var library = 'package:hello/foo.dart';
 
@@ -1851,8 +1993,9 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${tempDir.path}/.packages',
-        '--experimental-emit-debug-metadata'
+        '--packages=${package_config.path}',
+        '--experimental-emit-debug-metadata',
+        '--enable-experiment=non-nullable',
       ];
 
       final StreamController<List<int>> streamController =
@@ -1893,10 +2036,22 @@
 
     test('compile expression to Javascript', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
-      file.writeAsStringSync("main() {\n\n}\n");
-      File('${tempDir.path}/.packages')
-        ..createSync()
-        ..writeAsStringSync("hello:${tempDir.uri}\n");
+      file.writeAsStringSync("main() {\n}\n");
+      var package_config =
+          File('${tempDir.path}/.dart_tool/package_config.json')
+            ..createSync(recursive: true)
+            ..writeAsStringSync('''
+  {
+    "configVersion": 2,
+    "packages": [
+      {
+        "name": "hello",
+        "rootUri": "../",
+        "packageUri": "./"
+      }
+    ]
+  }
+  ''');
 
       var library = 'package:hello/foo.dart';
       var module = 'packages/hello/foo.dart';
@@ -1914,7 +2069,8 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${tempDir.path}/.packages',
+        '--packages=${package_config.path}',
+        '--enable-experiment=non-nullable',
       ];
 
       final StreamController<List<int>> streamController =
@@ -1959,7 +2115,7 @@
           // expression
           outputParser.expectSources = false;
           streamController.add('compile-expression-to-js abc\n'
-                  '$library\n1\n1\nabc\nabc\n$module\n\n'
+                  '$library\n2\n1\nabc\nabc\n$module\n\n'
               .codeUnits);
           count += 1;
         } else if (count == 1) {
@@ -1972,7 +2128,7 @@
 
           outputParser.expectSources = false;
           streamController.add('compile-expression-to-js abc\n'
-                  '$library\n1\n1\nabc\nabc\n$module\n2+2\n'
+                  '$library\n2\n1\nabc\nabc\n$module\n2+2\n'
               .codeUnits);
           count += 1;
         } else if (count == 2) {
@@ -2001,10 +2157,21 @@
     test('mixed compile expression commands with web target', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n\n}\n");
-      File('${tempDir.path}/.packages')
-        ..createSync()
-        ..writeAsStringSync("hello:${tempDir.uri}\n");
-
+      var package_config =
+          File('${tempDir.path}/.dart_tool/package_config.json')
+            ..createSync(recursive: true)
+            ..writeAsStringSync('''
+  {
+    "configVersion": 2,
+    "packages": [
+      {
+        "name": "hello",
+        "rootUri": "../",
+        "packageUri": "./"
+      }
+    ]
+  }
+  ''');
       var library = 'package:hello/foo.dart';
       var module = 'packages/hello/foo.dart';
 
@@ -2021,7 +2188,8 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${tempDir.path}/.packages',
+        '--packages=${package_config.path}',
+        '--enable-experiment=non-nullable'
       ];
 
       final StreamController<List<int>> streamController =
@@ -2066,7 +2234,7 @@
           // expression
           outputParser.expectSources = false;
           streamController.add('compile-expression-to-js abc\n'
-                  '$library\n1\n1\nabc\nabc\n$module\n2+2\n'
+                  '$library\n2\n1\nabc\nabc\n$module\n2+2\n'
               .codeUnits);
           count += 1;
         } else if (count == 1) {
@@ -2103,7 +2271,7 @@
 
           outputParser.expectSources = false;
           streamController.add('compile-expression-to-js abc\n'
-                  '$library\n1\n1\nabc\nabc\n$module\n2+2\n'
+                  '$library\n2\n1\nabc\nabc\n$module\n2+2\n'
               .codeUnits);
           count += 1;
         } else if (count == 3) {
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 7f3aed5..91a6317 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -387,12 +387,31 @@
   };
 
   /// The set of objects which the named configuration should imply.
-  static final _namedConfigurationOptions = {
+  static const _namedConfigurationOptions = {
     'system',
     'arch',
     'mode',
     'compiler',
     'runtime',
+    'timeout',
+    'nnbd',
+    'sanitizer',
+    'enable_asserts',
+    'use_cfe',
+    'analyzer_use_fasta_parser',
+    'use_elf',
+    'use_sdk',
+    'hot_reload',
+    'hot_reload_rollback',
+    'host_checked',
+    'csp',
+    'minified',
+    'vm_options',
+    'dart2js_options',
+    'experiments',
+    'babel',
+    'builder_tag',
+    'use_qemu'
   };
 
   /// Parses a list of strings as test options.
@@ -557,8 +576,8 @@
       for (var optionName in _namedConfigurationOptions) {
         if (options.containsKey(optionName)) {
           var namedConfig = options['named_configuration'];
-          _fail("The named configuration '$namedConfig' implies "
-              "'$optionName'. Try removing '$optionName'.");
+          _fail("Can't pass '--$optionName' since it is determined by the "
+              "named configuration '$namedConfig'.");
         }
       }
     }
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 6b7379a..5364fc2 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -303,7 +303,7 @@
 
 /// Find the most recently-built [binary] in any of the build directories.
 String _findBinary(String name, String windowsExtension) {
-  String binary = Platform.isWindows ? "$name.$windowsExtension" : name;
+  var binary = Platform.isWindows ? "$name.$windowsExtension" : name;
 
   String newestPath;
   DateTime newestTime;
diff --git a/pkg/vm/lib/metadata/procedure_attributes.dart b/pkg/vm/lib/metadata/procedure_attributes.dart
index 99a0023..d6840f2 100644
--- a/pkg/vm/lib/metadata/procedure_attributes.dart
+++ b/pkg/vm/lib/metadata/procedure_attributes.dart
@@ -122,13 +122,4 @@
         methodOrSetterSelectorId: methodOrSetterSelectorId,
         getterSelectorId: getterSelectorId);
   }
-
-  /// Converts [metadata] into a bytecode attribute.
-  Constant getBytecodeAttribute(ProcedureAttributesMetadata metadata) {
-    return ListConstant(const DynamicType(), [
-      IntConstant(_getFlags(metadata)),
-      IntConstant(metadata.methodOrSetterSelectorId),
-      IntConstant(metadata.getterSelectorId),
-    ]);
-  }
 }
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 174a310..97cf03a 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -132,8 +132,6 @@
         // need to index dart:collection, as it is only needed for desugaring of
         // const sets. We can remove it from this list at that time.
         "dart:collection",
-        // The bytecode pipeline uses the index to check if dart:ffi is used.
-        "dart:ffi",
         // TODO(askesc): This is for the VM host endian optimization, which
         // could possibly be done more cleanly after the VM no longer supports
         // doing constant evaluation on its own. See http://dartbug.com/32836
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 9299ed5..bbb753e 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,4 +1,12 @@
 # Changelog
+
+## 5.4.0
+- Update to version `3.41.0` of the spec.
+- Added `PortList` class.
+- Added `getPorts` RPC.
+- Added optional properties `portId`, `allocationLocation`, and `debugName` to
+  `InstanceRef` and `Instance`.
+
 ## 5.3.1
 - Rename `State` class to `_State` to avoid class name conflicts with Flutter.
 
@@ -6,7 +14,6 @@
 - Added support for `dart:io` extensions version 1.5.
 - Added combination getter/setter `socketProfilingEnabled`.
 - Deprecated `startSocketProfiling` and `pauseSocketProfiling`.
-- Added support for `dart:io` extensions version 1.4.
 - Update to version `3.40.0` of the spec.
 - Added `IsolateFlag` class.
 - Added `isolateFlags` property to `Isolate`.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index e2ae6d1..617bd7c 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -192,6 +192,7 @@
   if (obj == "MirrorReference") return obj;
   if (obj == "Null") return obj;
   if (obj == "PlainInstance") return obj;
+  if (obj == "ReceivePort") return obj;
   if (obj == "RegExp") return obj;
   if (obj == "StackTrace") return obj;
   if (obj == "String") return obj;
@@ -912,6 +913,13 @@
   return obj;
 }
 
+vms.PortList assertPortList(vms.PortList obj) {
+  assertNotNull(obj);
+  assertString(obj.type);
+  assertListOfInstanceRef(obj.ports);
+  return obj;
+}
+
 vms.ProfileFunction assertProfileFunction(vms.ProfileFunction obj) {
   assertNotNull(obj);
   assertString(obj.kind);
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index ae6691f..8803d45 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -25,6 +25,7 @@
 src/org/dartlang/vm/service/consumer/InvokeConsumer.java
 src/org/dartlang/vm/service/consumer/KillConsumer.java
 src/org/dartlang/vm/service/consumer/PauseConsumer.java
+src/org/dartlang/vm/service/consumer/PortListConsumer.java
 src/org/dartlang/vm/service/consumer/ProcessMemoryUsageConsumer.java
 src/org/dartlang/vm/service/consumer/ProtocolListConsumer.java
 src/org/dartlang/vm/service/consumer/ReloadSourcesConsumer.java
@@ -95,6 +96,7 @@
 src/org/dartlang/vm/service/element/NullRef.java
 src/org/dartlang/vm/service/element/Obj.java
 src/org/dartlang/vm/service/element/ObjRef.java
+src/org/dartlang/vm/service/element/PortList.java
 src/org/dartlang/vm/service/element/ProcessMemoryItem.java
 src/org/dartlang/vm/service/element/ProcessMemoryUsage.java
 src/org/dartlang/vm/service/element/ProfileFunction.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index d0564a6..ae41aeb 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.40
+version=3.41
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index fd20c5b..4dfc752 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -28,7 +28,7 @@
         HeapSnapshotObjectNoData,
         HeapSnapshotObjectNullData;
 
-const String vmServiceVersion = '3.40.0';
+const String vmServiceVersion = '3.41.0';
 
 /// @optional
 const String optional = 'optional';
@@ -157,6 +157,7 @@
   'Null': NullVal.parse,
   '@Object': ObjRef.parse,
   'Object': Obj.parse,
+  'PortList': PortList.parse,
   'ProfileFunction': ProfileFunction.parse,
   'ProtocolList': ProtocolList.parse,
   'Protocol': Protocol.parse,
@@ -209,6 +210,7 @@
   'getIsolateGroupMemoryUsage': const ['MemoryUsage'],
   'getScripts': const ['ScriptList'],
   'getObject': const ['Obj'],
+  'getPorts': const ['PortList'],
   'getRetainingPath': const ['RetainingPath'],
   'getProcessMemoryUsage': const ['ProcessMemoryUsage'],
   'getStack': const ['Stack'],
@@ -688,6 +690,12 @@
     int count,
   });
 
+  /// The `getPorts` RPC is used to retrieve the list of `ReceivePort` instances
+  /// for a given isolate.
+  ///
+  /// See [PortList].
+  Future<PortList> getPorts(String isolateId);
+
   /// The `getRetainingPath` RPC is used to lookup a path from an object
   /// specified by `targetId` to a GC root (i.e., the object which is preventing
   /// this object from being garbage collected).
@@ -1318,6 +1326,11 @@
             count: params['count'],
           );
           break;
+        case 'getPorts':
+          response = await _serviceImplementation.getPorts(
+            params['isolateId'],
+          );
+          break;
         case 'getRetainingPath':
           response = await _serviceImplementation.getRetainingPath(
             params['isolateId'],
@@ -1771,6 +1784,10 @@
       });
 
   @override
+  Future<PortList> getPorts(String isolateId) =>
+      _call('getPorts', {'isolateId': isolateId});
+
+  @override
   Future<RetainingPath> getRetainingPath(
           String isolateId, String targetId, int limit) =>
       _call('getRetainingPath',
@@ -2432,6 +2449,9 @@
 
   /// An instance of the Dart class BoundedType.
   static const String kBoundedType = 'BoundedType';
+
+  /// An instance of the Dart class ReceivePort.
+  static const String kReceivePort = 'ReceivePort';
 }
 
 /// A `SentinelKind` is used to distinguish different kinds of `Sentinel`
@@ -4239,6 +4259,27 @@
   @optional
   ContextRef closureContext;
 
+  /// The port ID for a ReceivePort.
+  ///
+  /// Provided for instance kinds:
+  ///  - ReceivePort
+  @optional
+  int portId;
+
+  /// The stack trace associated with the allocation of a ReceivePort.
+  ///
+  /// Provided for instance kinds:
+  ///  - ReceivePort
+  @optional
+  InstanceRef allocationLocation;
+
+  /// A name associated with a ReceivePort used for debugging purposes.
+  ///
+  /// Provided for instance kinds:
+  ///  - ReceivePort
+  @optional
+  String debugName;
+
   InstanceRef({
     @required this.kind,
     @required this.classRef,
@@ -4252,6 +4293,9 @@
     this.pattern,
     this.closureFunction,
     this.closureContext,
+    this.portId,
+    this.allocationLocation,
+    this.debugName,
   }) : super(id: id);
 
   InstanceRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
@@ -4269,6 +4313,10 @@
         createServiceObject(json['closureFunction'], const ['FuncRef']);
     closureContext =
         createServiceObject(json['closureContext'], const ['ContextRef']);
+    portId = json['portId'];
+    allocationLocation =
+        createServiceObject(json['allocationLocation'], const ['InstanceRef']);
+    debugName = json['debugName'];
   }
 
   @override
@@ -4288,6 +4336,9 @@
     _setIfNotNull(json, 'pattern', pattern?.toJson());
     _setIfNotNull(json, 'closureFunction', closureFunction?.toJson());
     _setIfNotNull(json, 'closureContext', closureContext?.toJson());
+    _setIfNotNull(json, 'portId', portId);
+    _setIfNotNull(json, 'allocationLocation', allocationLocation?.toJson());
+    _setIfNotNull(json, 'debugName', debugName);
     return json;
   }
 
@@ -4318,6 +4369,7 @@
   ///  - Double (suitable for passing to Double.parse())
   ///  - Int (suitable for passing to int.parse())
   ///  - String (value may be truncated)
+  ///  - StackTrace
   @optional
   String valueAsString;
 
@@ -4554,6 +4606,27 @@
   @optional
   InstanceRef bound;
 
+  /// The port ID for a ReceivePort.
+  ///
+  /// Provided for instance kinds:
+  ///  - ReceivePort
+  @optional
+  int portId;
+
+  /// The stack trace associated with the allocation of a ReceivePort.
+  ///
+  /// Provided for instance kinds:
+  ///  - ReceivePort
+  @optional
+  InstanceRef allocationLocation;
+
+  /// A name associated with a ReceivePort used for debugging purposes.
+  ///
+  /// Provided for instance kinds:
+  ///  - ReceivePort
+  @optional
+  String debugName;
+
   Instance({
     @required this.kind,
     @required this.classRef,
@@ -4582,6 +4655,9 @@
     this.parameterIndex,
     this.targetType,
     this.bound,
+    this.portId,
+    this.allocationLocation,
+    this.debugName,
   }) : super(id: id);
 
   Instance._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
@@ -4627,6 +4703,10 @@
     parameterIndex = json['parameterIndex'];
     targetType = createServiceObject(json['targetType'], const ['InstanceRef']);
     bound = createServiceObject(json['bound'], const ['InstanceRef']);
+    portId = json['portId'];
+    allocationLocation =
+        createServiceObject(json['allocationLocation'], const ['InstanceRef']);
+    debugName = json['debugName'];
   }
 
   @override
@@ -4663,6 +4743,9 @@
     _setIfNotNull(json, 'parameterIndex', parameterIndex);
     _setIfNotNull(json, 'targetType', targetType?.toJson());
     _setIfNotNull(json, 'bound', bound?.toJson());
+    _setIfNotNull(json, 'portId', portId);
+    _setIfNotNull(json, 'allocationLocation', allocationLocation?.toJson());
+    _setIfNotNull(json, 'debugName', debugName);
     return json;
   }
 
@@ -5743,6 +5826,37 @@
   String toString() => '[Obj type: ${type}, id: ${id}]';
 }
 
+/// A `PortList` contains a list of ports associated with some isolate.
+///
+/// See [getPort].
+class PortList extends Response {
+  static PortList parse(Map<String, dynamic> json) =>
+      json == null ? null : PortList._fromJson(json);
+
+  List<InstanceRef> ports;
+
+  PortList({
+    @required this.ports,
+  });
+
+  PortList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
+    ports = List<InstanceRef>.from(
+        createServiceObject(json['ports'], const ['InstanceRef']) ?? []);
+  }
+
+  @override
+  Map<String, dynamic> toJson() {
+    var json = <String, dynamic>{};
+    json['type'] = 'PortList';
+    json.addAll({
+      'ports': ports.map((f) => f.toJson()).toList(),
+    });
+    return json;
+  }
+
+  String toString() => '[PortList type: ${type}, ports: ${ports}]';
+}
+
 /// A `ProfileFunction` contains profiling information about a Dart or native
 /// function.
 ///
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 7d0d07a..0c77a68 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
 description: >-
   A library to communicate with a service implementing the Dart VM
   service protocol.
-version: 5.3.1
+version: 5.4.0
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
 
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index b514b86..918b045 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -35,10 +35,6 @@
 // Some checks are only performed at runtime to allow for generic code, these
 // throw ArgumentExceptions.
 
-static bool IsPointerType(const AbstractType& type) {
-  return IsFfiPointerClassId(type.type_class_id());
-}
-
 static void CheckSized(const AbstractType& type_arg) {
   const classid_t type_cid = type_arg.type_class_id();
   if (IsFfiNativeTypeTypeClassId(type_cid) || IsFfiTypeVoidClassId(type_cid) ||
@@ -54,26 +50,6 @@
   }
 }
 
-// The following functions are runtime checks on arguments.
-
-static const Integer& AsInteger(const Instance& instance) {
-  if (!instance.IsInteger()) {
-    const String& error = String::Handle(String::NewFormatted(
-        "Expected an int but found %s", instance.ToCString()));
-    Exceptions::ThrowArgumentError(error);
-  }
-  return Integer::Cast(instance);
-}
-
-static const Double& AsDouble(const Instance& instance) {
-  if (!instance.IsDouble()) {
-    const String& error = String::Handle(String::NewFormatted(
-        "Expected a double but found %s", instance.ToCString()));
-    Exceptions::ThrowArgumentError(error);
-  }
-  return Double::Cast(instance);
-}
-
 // Calculate the size of a native type.
 //
 // You must check [IsConcreteNativeType] and [CheckSized] first to verify that
@@ -96,75 +72,20 @@
 // The remainder of this file implements the dart:ffi native methods.
 
 DEFINE_NATIVE_ENTRY(Ffi_fromAddress, 1, 1) {
-  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, arg_ptr, arguments->NativeArgAt(0));
-  return Pointer::New(type_arg, arg_ptr.AsInt64Value());
+  UNREACHABLE();
 }
 
 DEFINE_NATIVE_ENTRY(Ffi_address, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  return Integer::New(pointer.NativeAddress());
-}
-
-static ObjectPtr LoadValueNumeric(Zone* zone,
-                                  const Pointer& target,
-                                  classid_t type_cid,
-                                  const Integer& offset) {
-  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
-  const size_t address =
-      target.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
-  switch (type_cid) {
-    case kFfiInt8Cid:
-      return Integer::New(*reinterpret_cast<int8_t*>(address));
-    case kFfiInt16Cid:
-      return Integer::New(*reinterpret_cast<int16_t*>(address));
-    case kFfiInt32Cid:
-      return Integer::New(*reinterpret_cast<int32_t*>(address));
-    case kFfiInt64Cid:
-      return Integer::New(*reinterpret_cast<int64_t*>(address));
-    case kFfiUint8Cid:
-      return Integer::NewFromUint64(*reinterpret_cast<uint8_t*>(address));
-    case kFfiUint16Cid:
-      return Integer::NewFromUint64(*reinterpret_cast<uint16_t*>(address));
-    case kFfiUint32Cid:
-      return Integer::NewFromUint64(*reinterpret_cast<uint32_t*>(address));
-    case kFfiUint64Cid:
-      return Integer::NewFromUint64(*reinterpret_cast<uint64_t*>(address));
-    case kFfiIntPtrCid:
-      return Integer::New(*reinterpret_cast<intptr_t*>(address));
-    case kFfiFloatCid:
-      return Double::New(*reinterpret_cast<float_t*>(address));
-    case kFfiDoubleCid:
-      return Double::New(*reinterpret_cast<double_t*>(address));
-    default:
-      UNREACHABLE();
-  }
+  UNREACHABLE();
 }
 
 #define DEFINE_NATIVE_ENTRY_LOAD(type)                                         \
-  DEFINE_NATIVE_ENTRY(Ffi_load##type, 0, 2) {                                  \
-    GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \
-    GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));  \
-    return LoadValueNumeric(zone, pointer, kFfi##type##Cid, offset);           \
-  }
+  DEFINE_NATIVE_ENTRY(Ffi_load##type, 0, 2) { UNREACHABLE(); }
 CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_LOAD)
 #undef DEFINE_NATIVE_ENTRY_LOAD
 
 DEFINE_NATIVE_ENTRY(Ffi_loadPointer, 1, 2) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));
-
-  const auto& pointer_type_arg =
-      AbstractType::Handle(zone, pointer.type_argument());
-  const AbstractType& type_arg =
-      AbstractType::Handle(TypeArguments::Handle(pointer_type_arg.arguments())
-                               .TypeAt(Pointer::kNativeTypeArgPos));
-
-  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
-  const size_t address =
-      pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
-
-  return Pointer::New(type_arg, *reinterpret_cast<uword*>(address));
+  UNREACHABLE();
 }
 
 static ObjectPtr LoadValueStruct(Zone* zone,
@@ -208,95 +129,13 @@
   return LoadValueStruct(zone, pointer_offset, pointer_type_arg);
 }
 
-static void StoreValueNumeric(Zone* zone,
-                              const Pointer& pointer,
-                              classid_t type_cid,
-                              const Integer& offset,
-                              const Instance& new_value) {
-  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
-  const size_t address =
-      pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
-  switch (type_cid) {
-    case kFfiInt8Cid:
-      *reinterpret_cast<int8_t*>(address) = AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiInt16Cid:
-      *reinterpret_cast<int16_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiInt32Cid:
-      *reinterpret_cast<int32_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiInt64Cid:
-      *reinterpret_cast<int64_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiUint8Cid:
-      *reinterpret_cast<uint8_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiUint16Cid:
-      *reinterpret_cast<uint16_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiUint32Cid:
-      *reinterpret_cast<uint32_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiUint64Cid:
-      *reinterpret_cast<uint64_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiIntPtrCid:
-      *reinterpret_cast<intptr_t*>(address) =
-          AsInteger(new_value).AsInt64Value();
-      break;
-    case kFfiFloatCid:
-      *reinterpret_cast<float*>(address) = AsDouble(new_value).value();
-      break;
-    case kFfiDoubleCid:
-      *reinterpret_cast<double*>(address) = AsDouble(new_value).value();
-      break;
-    default:
-      UNREACHABLE();
-  }
-}
-
 #define DEFINE_NATIVE_ENTRY_STORE(type)                                        \
-  DEFINE_NATIVE_ENTRY(Ffi_store##type, 0, 3) {                                 \
-    GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \
-    GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));  \
-    GET_NON_NULL_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(2));  \
-    StoreValueNumeric(zone, pointer, kFfi##type##Cid, offset, value);          \
-    return Object::null();                                                     \
-  }
+  DEFINE_NATIVE_ENTRY(Ffi_store##type, 0, 3) { UNREACHABLE(); }
 CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_STORE)
 #undef DEFINE_NATIVE_ENTRY_STORE
 
 DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 3) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, new_value, arguments->NativeArgAt(2));
-  AbstractType& pointer_type_arg =
-      AbstractType::Handle(pointer.type_argument());
-
-  auto& new_value_type =
-      AbstractType::Handle(zone, new_value.GetType(Heap::kNew));
-  if (!new_value_type.IsSubtypeOf(pointer_type_arg, Heap::kNew)) {
-    const String& error = String::Handle(String::NewFormatted(
-        "New value (%s) is not a subtype of '%s'.",
-        String::Handle(new_value_type.UserVisibleName()).ToCString(),
-        String::Handle(pointer_type_arg.UserVisibleName()).ToCString()));
-    Exceptions::ThrowArgumentError(error);
-  }
-
-  ASSERT(IsPointerType(pointer_type_arg));
-  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
-  const size_t address =
-      pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value());
-  *reinterpret_cast<uword*>(address) = new_value.NativeAddress();
-  return Object::null();
+  UNREACHABLE();
 }
 
 DEFINE_NATIVE_ENTRY(Ffi_sizeOf, 1, 0) {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 4b381cb..905cb26 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -51,11 +51,12 @@
   return Smi::New(hash);
 }
 
-DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 1) {
+DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 2) {
   ASSERT(
       TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
+  GET_NON_NULL_NATIVE_ARGUMENT(String, debug_name, arguments->NativeArgAt(1));
   Dart_Port port_id = PortMap::CreatePort(isolate->message_handler());
-  return ReceivePort::New(port_id, false /* not control port */);
+  return ReceivePort::New(port_id, debug_name, false /* not control port */);
 }
 
 DEFINE_NATIVE_ENTRY(RawReceivePortImpl_get_id, 0, 1) {
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 625ca6c..cf1e6ff 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -255,7 +255,7 @@
 }
 
 DEFINE_NATIVE_ENTRY(Internal_reachabilityFence, 0, 1) {
-  return Object::null();
+  UNREACHABLE();
 }
 
 DEFINE_NATIVE_ENTRY(Internal_collectAllGarbage, 0, 0) {
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 43383d4..3eabaf4 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -214,4 +214,12 @@
   return stacktrace;
 }
 
+bool HasStack() {
+  Thread* thread = Thread::Current();
+  StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread,
+                            StackFrameIterator::kNoCrossThreadIteration);
+  StackFrame* frame = frames.NextFrame();
+  return frame != nullptr;
+}
+
 }  // namespace dart
diff --git a/runtime/lib/stacktrace.h b/runtime/lib/stacktrace.h
index 9c8abae..a804d62 100644
--- a/runtime/lib/stacktrace.h
+++ b/runtime/lib/stacktrace.h
@@ -21,6 +21,9 @@
 // Creates a StackTrace object to be attached to an exception.
 StackTracePtr GetStackTraceForException();
 
+// Returns false if there is no Dart stack available.
+bool HasStack();
+
 }  // namespace dart
 
 #endif  // RUNTIME_LIB_STACKTRACE_H_
diff --git a/runtime/observatory/lib/src/models/objects/instance.dart b/runtime/observatory/lib/src/models/objects/instance.dart
index ab8d6d6..a0400c5 100644
--- a/runtime/observatory/lib/src/models/objects/instance.dart
+++ b/runtime/observatory/lib/src/models/objects/instance.dart
@@ -120,6 +120,9 @@
 
   /// An instance of the Dart class TypeRef.
   typeRef,
+
+  /// An instance of the Dart class RawReceivePort
+  receivePort,
 }
 
 bool isTypedData(InstanceKind? kind) {
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 4f9ead0..55c9d13 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -2781,6 +2781,8 @@
       return M.InstanceKind.typeParameter;
     case 'TypeRef':
       return M.InstanceKind.typeRef;
+    case 'ReceivePort':
+      return M.InstanceKind.receivePort;
   }
   var message = 'Unrecognized instance kind: $s';
   Logger.root.severe(message);
diff --git a/runtime/observatory/tests/service/get_ports_public_rpc_test.dart b/runtime/observatory/tests/service/get_ports_public_rpc_test.dart
new file mode 100644
index 0000000..cc511f7
--- /dev/null
+++ b/runtime/observatory/tests/service/get_ports_public_rpc_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2020, 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.
+
+import 'dart:isolate' hide Isolate;
+import 'package:observatory/service_io.dart';
+import 'package:test/test.dart';
+
+import 'test_helper.dart';
+
+var port1;
+var port2;
+var port3;
+
+void warmup() {
+  port1 = RawReceivePort(null, 'port1');
+  port2 = RawReceivePort((_) {});
+  port3 = RawReceivePort((_) {}, 'port3');
+  port3.close();
+  RawReceivePort((_) {}, 'port4');
+}
+
+int countNameMatches(ports, name) {
+  var matches = 0;
+  for (var port in ports) {
+    if (port['debugName'] == name) {
+      matches++;
+    }
+  }
+  return matches;
+}
+
+final tests = <IsolateTest>[
+  (Isolate isolate) async {
+    dynamic result = await isolate.invokeRpcNoUpgrade('getPorts', {});
+    expect(result['type'], 'PortList');
+    expect(result['ports'], isList);
+    final ports = result['ports'];
+    // There are at least three ports: the three created in warm up that
+    // weren't closed. Some OSes will have other ports open but we do not try
+    // and test for these.
+    expect(ports.length, greaterThanOrEqualTo(3));
+    expect(countNameMatches(ports, 'port1'), 1);
+    expect(countNameMatches(ports, 'port3'), 0);
+    expect(countNameMatches(ports, 'port4'), 1);
+    expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1));
+  },
+];
+
+main(args) async => runIsolateTests(args, tests, testeeBefore: warmup);
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 8b56393..c8b0244 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -9,12 +9,12 @@
 
 var tests = <VMTest>[
   (VM vm) async {
-    var result = await vm.invokeRpcNoUpgrade('getVersion', {});
-    expect(result['type'], equals('Version'));
-    expect(result['major'], equals(3));
-    expect(result['minor'], equals(40));
-    expect(result['_privateMajor'], equals(0));
-    expect(result['_privateMinor'], equals(0));
+    final result = await vm.invokeRpcNoUpgrade('getVersion', {});
+    expect(result['type'], 'Version');
+    expect(result['major'], 3);
+    expect(result['minor'], 41);
+    expect(result['_privateMajor'], 0);
+    expect(result['_privateMinor'], 0);
   },
 ];
 
diff --git a/runtime/observatory_2/lib/src/models/objects/instance.dart b/runtime/observatory_2/lib/src/models/objects/instance.dart
index 66965e9..e52cdd7 100644
--- a/runtime/observatory_2/lib/src/models/objects/instance.dart
+++ b/runtime/observatory_2/lib/src/models/objects/instance.dart
@@ -120,6 +120,9 @@
 
   /// An instance of the Dart class TypeRef.
   typeRef,
+
+  /// An instance of the Dart class RawReceivePort
+  receivePort,
 }
 
 bool isTypedData(InstanceKind kind) {
diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart
index 1bd33fb..fe4027b 100644
--- a/runtime/observatory_2/lib/src/service/object.dart
+++ b/runtime/observatory_2/lib/src/service/object.dart
@@ -2790,6 +2790,8 @@
       return M.InstanceKind.typeParameter;
     case 'TypeRef':
       return M.InstanceKind.typeRef;
+    case 'ReceivePort':
+      return M.InstanceKind.receivePort;
   }
   var message = 'Unrecognized instance kind: $s';
   Logger.root.severe(message);
diff --git a/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart
new file mode 100644
index 0000000..179823f
--- /dev/null
+++ b/runtime/observatory_2/tests/service_2/get_ports_public_rpc_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2020, 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.
+
+import 'dart:isolate' hide Isolate;
+import 'package:observatory_2/service_io.dart';
+import 'package:test/test.dart';
+
+import 'test_helper.dart';
+
+var port1;
+var port2;
+var port3;
+
+void warmup() {
+  port1 = RawReceivePort(null, 'port1');
+  port2 = RawReceivePort((_) {});
+  port3 = RawReceivePort((_) {}, 'port3');
+  port3.close();
+  RawReceivePort((_) {}, 'port4');
+}
+
+int countNameMatches(ports, name) {
+  var matches = 0;
+  for (var port in ports) {
+    if (port['debugName'] == name) {
+      matches++;
+    }
+  }
+  return matches;
+}
+
+final tests = <IsolateTest>[
+  (Isolate isolate) async {
+    dynamic result = await isolate.invokeRpcNoUpgrade('getPorts', {});
+    expect(result['type'], 'PortList');
+    expect(result['ports'], isList);
+    final ports = result['ports'];
+    // There are at least three ports: the three created in warm up that
+    // weren't closed. Some OSes will have other ports open but we do not try
+    // and test for these.
+    expect(ports.length, greaterThanOrEqualTo(3));
+    expect(countNameMatches(ports, 'port1'), 1);
+    expect(countNameMatches(ports, 'port3'), 0);
+    expect(countNameMatches(ports, 'port4'), 1);
+    expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1));
+  },
+];
+
+main(args) async => runIsolateTests(args, tests, testeeBefore: warmup);
diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
index d5450e5..df37cb9 100644
--- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
     var result = await vm.invokeRpcNoUpgrade('getVersion', {});
     expect(result['type'], equals('Version'));
     expect(result['major'], equals(3));
-    expect(result['minor'], equals(40));
+    expect(result['minor'], equals(41));
     expect(result['_privateMajor'], equals(0));
     expect(result['_privateMinor'], equals(0));
   },
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index b7ef75aa..8b15f7b 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -54,7 +54,7 @@
   V(CapabilityImpl_factory, 1)                                                 \
   V(CapabilityImpl_equals, 2)                                                  \
   V(CapabilityImpl_get_hashcode, 1)                                            \
-  V(RawReceivePortImpl_factory, 1)                                             \
+  V(RawReceivePortImpl_factory, 2)                                             \
   V(RawReceivePortImpl_get_id, 1)                                              \
   V(RawReceivePortImpl_get_sendport, 1)                                        \
   V(RawReceivePortImpl_closeInternal, 1)                                       \
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 6650cd6..52fcd87 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -497,7 +497,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -1017,7 +1017,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -1528,7 +1528,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -2049,7 +2049,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -2559,7 +2559,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -3073,7 +3073,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -3578,7 +3578,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 24;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 8;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 20;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 16;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 56;
@@ -4093,7 +4093,7 @@
 static constexpr dart::compiler::target::word PatchClass_InstanceSize = 48;
 static constexpr dart::compiler::target::word PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word RedirectionData_InstanceSize = 32;
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 96;
@@ -4659,7 +4659,7 @@
 static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 20;
 static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 8;
 static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 20;
 static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
     16;
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60;
@@ -5233,7 +5233,7 @@
 static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
     32;
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
@@ -5811,7 +5811,7 @@
 static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
     32;
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
@@ -6377,7 +6377,7 @@
 static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 20;
 static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 8;
 static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 12;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 12;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 20;
 static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
     16;
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60;
@@ -6944,7 +6944,7 @@
 static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
     32;
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
@@ -7515,7 +7515,7 @@
 static constexpr dart::compiler::target::word AOT_PatchClass_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_PcDescriptors_HeaderSize = 16;
 static constexpr dart::compiler::target::word AOT_Pointer_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ReceivePort_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_RedirectionData_InstanceSize =
     32;
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index a17966f..63db37e 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -725,6 +725,31 @@
   return result.raw();
 }
 
+ObjectPtr DartLibraryCalls::LookupOpenPorts() {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Function& function = Function::Handle(
+      zone, thread->isolate()->object_store()->lookup_open_ports());
+  const int kTypeArgsLen = 0;
+  const int kNumArguments = 0;
+  if (function.IsNull()) {
+    Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
+    ASSERT(!isolate_lib.IsNull());
+    const String& class_name = String::Handle(
+        zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
+    const String& function_name = String::Handle(
+        zone, isolate_lib.PrivateName(Symbols::_lookupOpenPorts()));
+    function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
+                                       kTypeArgsLen, kNumArguments,
+                                       Object::empty_array());
+    ASSERT(!function.IsNull());
+    thread->isolate()->object_store()->set_lookup_open_ports(function);
+  }
+  const Object& result = Object::Handle(
+      zone, DartEntry::InvokeFunction(function, Object::empty_array()));
+  return result.raw();
+}
+
 ObjectPtr DartLibraryCalls::HandleMessage(const Object& handler,
                                           const Instance& message) {
   Thread* thread = Thread::Current();
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 2ebdbe8..c85f683 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -282,6 +282,9 @@
   // Returns the handler if one has been registered for this port id.
   static ObjectPtr LookupHandler(Dart_Port port_id);
 
+  // Returns a list of open ReceivePorts.
+  static ObjectPtr LookupOpenPorts();
+
   // Returns null on success, a RawError on failure.
   static ObjectPtr HandleMessage(const Object& handler,
                                  const Instance& dart_message);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 8b8bbc0..7a1c69e 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2385,8 +2385,9 @@
     args.SetAt(2, Instance::Handle(state->BuildArgs(thread)));
     args.SetAt(3, Instance::Handle(state->BuildMessage(thread)));
     args.SetAt(4, is_spawn_uri ? Bool::True() : Bool::False());
-    args.SetAt(5, ReceivePort::Handle(ReceivePort::New(
-                      isolate->main_port(), true /* control port */)));
+    args.SetAt(5, ReceivePort::Handle(
+                      ReceivePort::New(isolate->main_port(), Symbols::Empty(),
+                                       true /* control port */)));
     args.SetAt(6, capabilities);
 
     const Library& lib = Library::Handle(Library::IsolateLibrary());
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e5af575..bc6666b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "include/dart_api.h"
+#include "lib/stacktrace.h"
 #include "platform/assert.h"
 #include "platform/text_buffer.h"
 #include "platform/unaligned.h"
@@ -23805,6 +23806,7 @@
 }
 
 ReceivePortPtr ReceivePort::New(Dart_Port id,
+                                const String& debug_name,
                                 bool is_control_port,
                                 Heap::Space space) {
   ASSERT(id != ILLEGAL_PORT);
@@ -23812,6 +23814,8 @@
   Zone* zone = thread->zone();
   const SendPort& send_port =
       SendPort::Handle(zone, SendPort::New(id, thread->isolate()->origin_id()));
+  const StackTrace& allocation_location_ =
+      HasStack() ? GetCurrentStackTrace(0) : StackTrace::Handle();
 
   ReceivePort& result = ReceivePort::Handle(zone);
   {
@@ -23820,6 +23824,9 @@
     NoSafepointScope no_safepoint;
     result ^= raw;
     result.StorePointer(&result.raw_ptr()->send_port_, send_port.raw());
+    result.StorePointer(&result.raw_ptr()->debug_name_, debug_name.raw());
+    result.StorePointer(&result.raw_ptr()->allocation_location_,
+                        allocation_location_.raw());
   }
   if (is_control_port) {
     PortMap::SetPortState(id, PortMap::kControlPort);
@@ -23890,6 +23897,39 @@
   return "TransferableTypedData";
 }
 
+bool Closure::CanonicalizeEquals(const Instance& other) const {
+  if (!other.IsClosure()) return false;
+
+  const Closure& other_closure = Closure::Cast(other);
+  return (instantiator_type_arguments() ==
+          other_closure.instantiator_type_arguments()) &&
+         (function_type_arguments() ==
+          other_closure.function_type_arguments()) &&
+         (delayed_type_arguments() == other_closure.delayed_type_arguments()) &&
+         (function() == other_closure.function()) &&
+         (context() == other_closure.context());
+}
+
+void Closure::CanonicalizeFieldsLocked(Thread* thread) const {
+  TypeArguments& type_args = TypeArguments::Handle();
+  type_args = instantiator_type_arguments();
+  if (!type_args.IsNull()) {
+    type_args = type_args.Canonicalize(thread, nullptr);
+    set_instantiator_type_arguments(type_args);
+  }
+  type_args = function_type_arguments();
+  if (!type_args.IsNull()) {
+    type_args = type_args.Canonicalize(thread, nullptr);
+    set_function_type_arguments(type_args);
+  }
+  type_args = delayed_type_arguments();
+  if (!type_args.IsNull()) {
+    type_args = type_args.Canonicalize(thread, nullptr);
+    set_delayed_type_arguments(type_args);
+  }
+  // Ignore function, context, hash.
+}
+
 intptr_t Closure::NumTypeParameters(Thread* thread) const {
   // Only check for empty here, as the null TAV is used to mean that the
   // closed-over delayed type parameters were all of dynamic type.
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 903ad3d..1bd2be8 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -10467,6 +10467,9 @@
   TypeArgumentsPtr instantiator_type_arguments() const {
     return raw_ptr()->instantiator_type_arguments_;
   }
+  void set_instantiator_type_arguments(const TypeArguments& args) const {
+    StorePointer(&raw_ptr()->instantiator_type_arguments_, args.raw());
+  }
   static intptr_t instantiator_type_arguments_offset() {
     return OFFSET_OF(ClosureLayout, instantiator_type_arguments_);
   }
@@ -10474,6 +10477,9 @@
   TypeArgumentsPtr function_type_arguments() const {
     return raw_ptr()->function_type_arguments_;
   }
+  void set_function_type_arguments(const TypeArguments& args) const {
+    StorePointer(&raw_ptr()->function_type_arguments_, args.raw());
+  }
   static intptr_t function_type_arguments_offset() {
     return OFFSET_OF(ClosureLayout, function_type_arguments_);
   }
@@ -10481,6 +10487,9 @@
   TypeArgumentsPtr delayed_type_arguments() const {
     return raw_ptr()->delayed_type_arguments_;
   }
+  void set_delayed_type_arguments(const TypeArguments& args) const {
+    StorePointer(&raw_ptr()->delayed_type_arguments_, args.raw());
+  }
   static intptr_t delayed_type_arguments_offset() {
     return OFFSET_OF(ClosureLayout, delayed_type_arguments_);
   }
@@ -10507,10 +10516,8 @@
     return RoundedAllocationSize(sizeof(ClosureLayout));
   }
 
-  // Returns true if all elements are OK for canonicalization.
-  virtual void CanonicalizeFieldsLocked(Thread* thread) const {
-    // None of the fields of a closure are instances.
-  }
+  virtual void CanonicalizeFieldsLocked(Thread* thread) const;
+  virtual bool CanonicalizeEquals(const Instance& other) const;
   virtual uint32_t CanonicalizeHash() const {
     return Function::Handle(function()).Hash();
   }
@@ -10560,10 +10567,17 @@
   InstancePtr handler() const { return raw_ptr()->handler_; }
   void set_handler(const Instance& value) const;
 
+  StackTracePtr allocation_location() const {
+    return raw_ptr()->allocation_location_;
+  }
+
+  StringPtr debug_name() const { return raw_ptr()->debug_name_; }
+
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(ReceivePortLayout));
   }
   static ReceivePortPtr New(Dart_Port id,
+                            const String& debug_name,
                             bool is_control_port,
                             Heap::Space space = Heap::kNew);
 
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 0d6553e..acdaca6 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1452,7 +1452,15 @@
 }
 
 void ReceivePort::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
+  JSONObject obj(stream);
+  Instance::PrintSharedInstanceJSON(&obj, ref);
+  const StackTrace& allocation_location_ =
+      StackTrace::Handle(allocation_location());
+  const String& debug_name_ = String::Handle(debug_name());
+  obj.AddProperty("kind", "ReceivePort");
+  obj.AddProperty64("portId", Id());
+  obj.AddProperty("debugName", debug_name_.ToCString());
+  obj.AddProperty("allocationLocation", allocation_location_);
 }
 
 void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const {
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index dc51e07..829ae7e 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -160,6 +160,7 @@
   RW(Instance, stack_overflow)                                                 \
   RW(Instance, out_of_memory)                                                  \
   RW(Function, lookup_port_handler)                                            \
+  RW(Function, lookup_open_ports)                                              \
   RW(Function, handle_message_function)                                        \
   RW(Function, growable_list_factory)                                          \
   RW(Function, simple_instance_of_function)                                    \
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 4a713b6..a124ad5 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2726,7 +2726,9 @@
   VISIT_FROM(ObjectPtr, send_port_)
   SendPortPtr send_port_;
   InstancePtr handler_;
-  VISIT_TO(ObjectPtr, handler_)
+  StringPtr debug_name_;
+  StackTracePtr allocation_location_;
+  VISIT_TO(ObjectPtr, allocation_location_)
 };
 
 class TransferableTypedDataLayout : public InstanceLayout {
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index 7276a25..f5089d9 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -171,6 +171,8 @@
   F(ExternalTypedData, length_)                                                \
   F(ReceivePort, send_port_)                                                   \
   F(ReceivePort, handler_)                                                     \
+  F(ReceivePort, debug_name_)                                                  \
+  F(ReceivePort, allocation_location_)                                         \
   F(StackTrace, async_link_)                                                   \
   F(StackTrace, code_array_)                                                   \
   F(StackTrace, pc_offset_array_)                                              \
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 23dfdde..d12772e 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -3142,6 +3142,30 @@
   return true;
 }
 
+static const MethodParameter* get_ports_params[] = {
+    RUNNABLE_ISOLATE_PARAMETER,
+    NULL,
+};
+
+static bool GetPorts(Thread* thread, JSONStream* js) {
+  // Ensure the array and handles created below are promptly destroyed.
+  StackZone zone(thread);
+  HANDLESCOPE(thread);
+  const GrowableObjectArray& ports = GrowableObjectArray::Handle(
+      GrowableObjectArray::RawCast(DartLibraryCalls::LookupOpenPorts()));
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "PortList");
+  {
+    Instance& port = Instance::Handle(zone.GetZone());
+    JSONArray arr(&jsobj, "ports");
+    for (int i = 0; i < ports.Length(); ++i) {
+      port ^= ports.At(i);
+      arr.AddValue(port);
+    }
+  }
+  return true;
+}
+
 #if !defined(DART_PRECOMPILED_RUNTIME)
 static const char* const report_enum_names[] = {
     SourceReport::kCallSitesStr,
@@ -4389,12 +4413,12 @@
   return true;
 }
 
-static const MethodParameter* get_ports_params[] = {
+static const MethodParameter* get_ports_private_params[] = {
     RUNNABLE_ISOLATE_PARAMETER,
     NULL,
 };
 
-static bool GetPorts(Thread* thread, JSONStream* js) {
+static bool GetPortsPrivate(Thread* thread, JSONStream* js) {
   MessageHandler* message_handler = thread->isolate()->message_handler();
   PortMap::PrintPortsForMessageHandler(message_handler, js);
   return true;
@@ -5054,6 +5078,8 @@
     get_inbound_references_params },
   { "getInstances", GetInstances,
     get_instances_params },
+  { "getPorts", GetPorts,
+    get_ports_params },
   { "getIsolate", GetIsolate,
     get_isolate_params },
   { "_getIsolateObjectStore", GetIsolateObjectStore,
@@ -5074,8 +5100,8 @@
     get_object_store_params },
   { "_getPersistentHandles", GetPersistentHandles,
       get_persistent_handles_params, },
-  { "_getPorts", GetPorts,
-    get_ports_params },
+  { "_getPorts", GetPortsPrivate,
+    get_ports_private_params },
   { "getProcessMemoryUsage", GetProcessMemoryUsage,
     get_process_memory_usage_params },
   { "_getReachableSize", GetReachableSize,
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index bf1d99b..9d09af1 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
 namespace dart {
 
 #define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 40
+#define SERVICE_PROTOCOL_MINOR_VERSION 41
 
 class Array;
 class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index b8d0906..6fe2fb8 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.40
+# Dart VM Service Protocol 3.41
 
 > Please post feedback to the [observatory-discuss group][discuss-list]
 
-This document describes of _version 3.40_ of the Dart VM Service Protocol. This
+This document describes of _version 3.41_ of the Dart VM Service Protocol. This
 protocol is used to communicate with a running Dart Virtual Machine.
 
 To use the Service Protocol, start the VM with the *--observe* flag.
@@ -47,6 +47,7 @@
   - [getIsolateGroup](#getisolategroup)
   - [getMemoryUsage](#getmemoryusage)
   - [getObject](#getobject)
+  - [getPorts](#getports)
   - [getProcessMemoryUsage](#getprocessmemoryusage)
   - [getRetainingPath](#getretainingpath)
   - [getScripts](#getscripts)
@@ -113,6 +114,7 @@
   - [NativeFunction](#nativefunction)
   - [Null](#null)
   - [Object](#object)
+  - [PortList](#portlist)
   - [ReloadReport](#reloadreport)
   - [Response](#response)
   - [RetainingObject](#retainingobject)
@@ -936,6 +938,17 @@
 Float32x4List, and Float64x2List.  These parameters are otherwise
 ignored.
 
+### getPorts
+
+```
+PortList getPorts(string isolateId)
+```
+
+The _getPorts_ RPC is used to retrieve the list of `ReceivePort` instances for a
+given isolate.
+
+See [PortList](#portlist).
+
 ### getRetainingPath
 
 ```
@@ -2426,6 +2439,24 @@
   // Provided for instance kinds:
   //   Closure
   @Context closureContext [optional];
+
+  // The port ID for a ReceivePort.
+  //
+  // Provided for instance kinds:
+  //   ReceivePort
+  int portId [optional];
+
+  // The stack trace associated with the allocation of a ReceivePort.
+  //
+  // Provided for instance kinds:
+  //   ReceivePort
+  @Instance allocationLocation [optional];
+
+  // A name associated with a ReceivePort used for debugging purposes.
+  //
+  // Provided for instance kinds:
+  //   ReceivePort
+  string debugName [optional];
 }
 ```
 
@@ -2446,6 +2477,7 @@
   //   Double (suitable for passing to Double.parse())
   //   Int (suitable for passing to int.parse())
   //   String (value may be truncated)
+  //   StackTrace
   string valueAsString [optional];
 
   // The valueAsString for String references may be truncated. If so,
@@ -2658,6 +2690,24 @@
   //   BoundedType
   //   TypeParameter
   @Instance bound [optional];
+
+  // The port ID for a ReceivePort.
+  //
+  // Provided for instance kinds:
+  //   ReceivePort
+  int portId [optional];
+
+  // The stack trace associated with the allocation of a ReceivePort.
+  //
+  // Provided for instance kinds:
+  //   ReceivePort
+  @Instance allocationLocation [optional];
+
+  // A name associated with a ReceivePort used for debugging purposes.
+  //
+  // Provided for instance kinds:
+  //   ReceivePort
+  string debugName [optional];
 }
 ```
 
@@ -2742,6 +2792,9 @@
 
   // An instance of the Dart class BoundedType.
   BoundedType,
+
+  // An instance of the Dart class ReceivePort.
+  ReceivePort,
 }
 ```
 
@@ -3184,6 +3237,18 @@
 
 An _Object_ is a  persistent object that is owned by some isolate.
 
+### PortList
+
+```
+class PortList extends Response {
+  @Instance[] ports;
+}
+```
+
+A _PortList_ contains a list of ports associated with some isolate.
+
+See [getPort](#getPort).
+
 ### ProfileFunction
 
 ```
@@ -3855,5 +3920,6 @@
 3.38 | Added `isSystemIsolate` property to `@Isolate` and `Isolate`, `isSystemIsolateGroup` property to `@IsolateGroup` and `IsolateGroup`, and properties `systemIsolates` and `systemIsolateGroups` to `VM`.
 3.39 | Removed the following deprecated RPCs and objects: `getClientName`, `getWebSocketTarget`, `setClientName`, `requireResumeApproval`, `ClientName`, and `WebSocketTarget`.
 3.40 | Added `IsolateFlag` object and `isolateFlags` property to `Isolate`.
+3.41 | Added `PortList` object, `ReceivePort` `InstanceKind`, and `getPorts` RPC.
 
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 40b953c..d8f11c2 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -447,6 +447,7 @@
   V(_handleMessage, "_handleMessage")                                          \
   V(_instanceOf, "_instanceOf")                                                \
   V(_lookupHandler, "_lookupHandler")                                          \
+  V(_lookupOpenPorts, "_lookupOpenPorts")                                      \
   V(_name, "_name")                                                            \
   V(_onData, "_onData")                                                        \
   V(_rehashObjects, "_rehashObjects")                                          \
diff --git a/sdk/lib/_internal/allowed_experiments.json b/sdk/lib/_internal/allowed_experiments.json
index cda7feb..4644443 100644
--- a/sdk/lib/_internal/allowed_experiments.json
+++ b/sdk/lib/_internal/allowed_experiments.json
@@ -34,6 +34,12 @@
     "collection": {
       "experimentSet": "nullSafety"
     },
+    "connectivity": {
+      "experimentSet": "nullSafety"
+    },
+    "connectivity_platform_interface": {
+      "experimentSet": "nullSafety"
+    },
     "convert": {
       "experimentSet": "nullSafety"
     },
@@ -46,6 +52,12 @@
     "dart_internal": {
       "experimentSet": "nullSafety"
     },
+    "device_info": {
+      "experimentSet": "nullSafety"
+    },
+    "device_info_platform_interface": {
+      "experimentSet": "nullSafety"
+    },
     "fake_async": {
       "experimentSet": "nullSafety"
     },
@@ -109,6 +121,9 @@
     "platform": {
       "experimentSet": "nullSafety"
     },
+    "plugin_platform_interface": {
+      "experimentSet": "nullSafety"
+    },
     "pool": {
       "experimentSet": "nullSafety"
     },
@@ -154,8 +169,32 @@
     "typed_data": {
       "experimentSet": "nullSafety"
     },
+    "url_launcher": {
+      "experimentSet": "nullSafety"
+    },
+    "url_launcher_linux": {
+      "experimentSet": "nullSafety"
+    },
+    "url_launcher_macos": {
+      "experimentSet": "nullSafety"
+    },
+    "url_launcher_platform_interface": {
+      "experimentSet": "nullSafety"
+    },
+    "url_launcher_windows": {
+      "experimentSet": "nullSafety"
+    },
     "vector_math": {
       "experimentSet": "nullSafety"
+    },
+    "video_player": {
+      "experimentSet": "nullSafety"
+    },
+    "video_player_platform_interface": {
+      "experimentSet": "nullSafety"
+    },
+    "video_player_web": {
+      "experimentSet": "nullSafety"
     }
   }
 }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 52c3266..4a224cd 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -872,8 +872,15 @@
 })()''');
 
 checkNativeNonNull(dynamic variable) {
-  if (_nativeNonNullAsserts) {
-    return nullCheck(variable);
+  if (_nativeNonNullAsserts && variable == null) {
+    // TODO(srujzs): Add link/patch for instructions to disable in internal
+    // build systems.
+    throw TypeErrorImpl('''
+      Unexpected null value encountered in Dart web platform libraries.
+      This may be a bug in the Dart SDK APIs. If you would like to report a bug
+      or disable this error, you can use the following instructions:
+      https://github.com/dart-lang/sdk/tree/master/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
+    ''');
   }
   return variable;
 }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index 99ca1e2..b6a0325 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -48,7 +48,10 @@
 bool _nativeNonNullAsserts = false;
 
 /// Enables null assertions on native APIs to make sure value returned from the
-/// browser is sound. These apply to dart:html and similar web libraries.
+/// browser is sound.
+///
+/// These apply to dart:html and similar web libraries. Note that these only are
+/// added in sound null-safety only.
 void nativeNonNullAsserts(bool enable) {
   _nativeNonNullAsserts = enable;
 }
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index a04c737..02bc8c7 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -39,7 +39,7 @@
 
 int _sizeOf<T extends NativeType>() native "Ffi_sizeOf";
 
-// Implemented in the method recognizer, bytecode interpreter uses runtime.
+// Implemented in the method recognizer.
 Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
 
 // The real implementation of this function (for interface calls) lives in
@@ -92,7 +92,7 @@
         "Pointer.fromFunction cannot be called dynamically.");
   }
 
-  // Implemented in the method recognizer, bytecode interpreter uses runtime.
+  // Implemented in the method recognizer.
   @patch
   int get address native "Ffi_address";
 
@@ -114,10 +114,9 @@
 /// calculations. See pkg/vm/lib/transformations/ffi.dart.
 @pragma('vm:prefer-inline')
 int _abi()
-    native "Recognized method: method is directly interpreted by the bytecode interpreter or IR graph is built in the flow graph builder.";
+    native "Recognized method: IR graph is built in the flow graph builder.";
 
-// The following functions are implemented in the method recognizer, but the
-// bytecode interpreter uses native entries.
+// The following functions are implemented in the method recognizer.
 //
 // TODO(38172): Since these are not inlined (force optimize), they force
 // allocating a Pointer with in elementAt/offsetBy. Allocating these pointers
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index 812f18f..ad5f5b7 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -163,7 +163,7 @@
 
 // This function can be used to keep an object alive til that point.
 //
-// This is implemented by a recognized method, but in bytecode through a native.
+// This is implemented by a recognized method.
 @pragma('vm:prefer-inline')
 void reachabilityFence(Object object) native "Internal_reachabilityFence";
 
diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart
index 91a567d..97e90ce 100644
--- a/sdk/lib/_internal/vm/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/vm/lib/isolate_patch.dart
@@ -22,7 +22,8 @@
 @patch
 class ReceivePort {
   @patch
-  factory ReceivePort() => new _ReceivePortImpl();
+  factory ReceivePort([String debugName = '']) =>
+      new _ReceivePortImpl(debugName);
 
   @patch
   factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) {
@@ -62,15 +63,16 @@
    * event is received.
    */
   @patch
-  factory RawReceivePort([Function? handler]) {
-    _RawReceivePortImpl result = new _RawReceivePortImpl();
+  factory RawReceivePort([Function? handler, String debugName = '']) {
+    _RawReceivePortImpl result = new _RawReceivePortImpl(debugName);
     result.handler = handler;
     return result;
   }
 }
 
 class _ReceivePortImpl extends Stream implements ReceivePort {
-  _ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePort());
+  _ReceivePortImpl([String debugName = ''])
+      : this.fromRawReceivePort(new RawReceivePort(null, debugName));
 
   _ReceivePortImpl.fromRawReceivePort(this._rawPort)
       : _controller = new StreamController(sync: true) {
@@ -128,11 +130,20 @@
 
 @pragma("vm:entry-point")
 class _RawReceivePortImpl implements RawReceivePort {
-  factory _RawReceivePortImpl() native "RawReceivePortImpl_factory";
+  factory _RawReceivePortImpl(String debugName) {
+    final port = _RawReceivePortImpl._(debugName);
+    _portMap[port._get_id()] = <String, dynamic>{
+      'port': port,
+    };
+    return port;
+  }
+
+  factory _RawReceivePortImpl._(String debugName)
+      native "RawReceivePortImpl_factory";
 
   close() {
     // Close the port and remove it from the handler map.
-    _handlerMap.remove(this._closeInternal());
+    _portMap.remove(this._closeInternal());
   }
 
   SendPort get sendPort {
@@ -155,10 +166,15 @@
   // Called from the VM to retrieve the handler for a message.
   @pragma("vm:entry-point", "call")
   static _lookupHandler(int id) {
-    var result = _handlerMap[id];
+    var result = _portMap[id]?['handler'];
     return result;
   }
 
+  @pragma("vm:entry-point", "call")
+  static _lookupOpenPorts() {
+    return _portMap.values.map((e) => e['port']).toList();
+  }
+
   // Called from the VM to dispatch to the handler.
   @pragma("vm:entry-point", "call")
   static void _handleMessage(Function handler, var message) {
@@ -173,22 +189,16 @@
   _closeInternal() native "RawReceivePortImpl_closeInternal";
 
   void set handler(Function? value) {
-    _handlerMap[this._get_id()] = value;
+    final id = this._get_id();
+    if (!_portMap.containsKey(id)) {
+      _portMap[id] = <String, dynamic>{
+        'port': this,
+      };
+    }
+    _portMap[id]!['handler'] = value;
   }
 
-  // TODO(iposva): Ideally keep this map in the VM.
-  // id to handler mapping.
-  static _initHandlerMap() {
-    // TODO(18511): Workaround bad CheckSmi hoisting.
-    var tempMap = new HashMap();
-    // Collect feedback that not all keys are Smis.
-    tempMap["."] = 1;
-    tempMap["."] = 2;
-
-    return new HashMap();
-  }
-
-  static final Map _handlerMap = _initHandlerMap();
+  static final _portMap = <dynamic, Map<String, dynamic>>{};
 }
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md b/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
new file mode 100644
index 0000000..eb9e79d
--- /dev/null
+++ b/sdk/lib/html/doc/NATIVE_NULL_ASSERTIONS.md
@@ -0,0 +1,42 @@
+# Native Null Assertions in Dart Dev Compiler and Dart2JS
+
+## Overview
+
+In the Dart web platform libraries, e.g. `dart:html`, there are APIs that depend
+on JS interoperability. With null-safety, the types returned from these interop
+procedures are not null-checked by default. In both DDC and dart2js, there
+exists a flag to turn on checks, or native null assertions, for these instances.
+In DDC, it's called `nativeNonNullAsserts` and in dart2js, it's called
+`--native-null-assertions`.
+
+Specifically, the flag focused on two cases. The first case is checks around
+types returned from APIs that are declared `native`. If the return type here is
+non-nullable, enabling native null assertions will throw an error if a `null`
+value is returned. For example,
+
+`int get foo native;`
+
+will throw an error if `.foo` returns a `null` value. This may happen due to a
+number of reasons, one of which could be browser incompatibility.
+
+The second case is on `JS()` invocations. `JS()` is an internal-only function
+that allows you to inline JavaScript. If the static type of the `JS()`
+invocation is non-nullable, but a `null` value is returned, there will be an
+error thrown if native null assertions are enabled.
+
+The goals with these native null assertions are to ensure the Dart web platform
+libraries are typed correctly and to help achieve sound null-safety.
+
+If you come across an error related to this flag, this may or may not be a bug
+in the Dart web platform libraries. If so, please file a bug at:
+https://github.com/dart-lang/sdk/issues/labels/web-libraries
+
+## Disabling native null assertions
+
+Native null assertions will be turned on by default across different build
+systems. If it is enabled, here's how you can disable it in the following build
+systems:
+
+### build_web_compilers
+
+https://github.com/dart-lang/build/tree/master/docs/native_null_assertions.md
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 98d2dcf..e5a757f 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -785,7 +785,7 @@
     _close();
   }
 
-  void _closeHandler() {
+  void _closeHandler() async {
     if (_status == connectedStatus) {
       if (_closedRead) return;
       _socketClosedRead = true;
@@ -796,7 +796,7 @@
           _close();
         }
       } else {
-        _scheduleFilter();
+        await _scheduleFilter();
       }
     } else if (_status == handshakeStatus) {
       _socketClosedRead = true;
@@ -805,26 +805,23 @@
             new HandshakeException('Connection terminated during handshake'),
             null);
       } else {
-        _secureHandshake();
+        await _secureHandshake();
       }
     }
   }
 
-  void _secureHandshake() {
+  Future<void> _secureHandshake() async {
     try {
-      _secureFilter!.handshake().then((needRetryHandshake) {
-        if (needRetryHandshake) {
-          // Some certificates have been evaluated, need to rety handshake.
-          _secureHandshake();
-        } else {
-          _filterStatus.writeEmpty = false;
-          _readSocket();
-          _writeSocket();
-          _scheduleFilter();
-        }
-      }).catchError((e, stackTrace) {
-        _reportError(e, stackTrace);
-      });
+      bool needRetryHandshake = await _secureFilter!.handshake();
+      if (needRetryHandshake) {
+        // Some certificates have been evaluated, need to retry handshake.
+        await _secureHandshake();
+      } else {
+        _filterStatus.writeEmpty = false;
+        _readSocket();
+        _writeSocket();
+        await _scheduleFilter();
+      }
     } catch (e, stackTrace) {
       _reportError(e, stackTrace);
     }
@@ -885,67 +882,71 @@
     }
   }
 
-  void _scheduleFilter() {
+  Future<void> _scheduleFilter() async {
     _filterPending = true;
-    _tryFilter();
+    return _tryFilter();
   }
 
-  void _tryFilter() {
+  Future<void> _tryFilter() async {
     if (_status == closedStatus) {
       return;
     }
-    if (_filterPending && !_filterActive) {
-      _filterActive = true;
-      _filterPending = false;
-      _pushAllFilterStages().then((status) {
-        _filterStatus = status;
-        _filterActive = false;
-        if (_status == closedStatus) {
-          _secureFilter!.destroy();
-          _secureFilter = null;
-          return;
-        }
-        _socket.readEventsEnabled = true;
-        if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
-          // Checks for and handles all cases of partially closed sockets.
-          shutdown(SocketDirection.send);
-          if (_status == closedStatus) {
-            return;
-          }
-        }
-        if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
-          if (_status == handshakeStatus) {
-            _secureFilter!.handshake();
-            if (_status == handshakeStatus) {
-              throw new HandshakeException(
-                  'Connection terminated during handshake');
-            }
-          }
-          _closeHandler();
-        }
+    if (!_filterPending || _filterActive) {
+      return;
+    }
+    _filterActive = true;
+    _filterPending = false;
+
+    try {
+      _filterStatus = await _pushAllFilterStages();
+      _filterActive = false;
+      if (_status == closedStatus) {
+        _secureFilter!.destroy();
+        _secureFilter = null;
+        return;
+      }
+      _socket.readEventsEnabled = true;
+      if (_filterStatus.writeEmpty && _closedWrite && !_socketClosedWrite) {
+        // Checks for and handles all cases of partially closed sockets.
+        shutdown(SocketDirection.send);
         if (_status == closedStatus) {
           return;
         }
-        if (_filterStatus.progress) {
-          _filterPending = true;
-          if (_filterStatus.writeEncryptedNoLongerEmpty) {
-            _writeSocket();
-          }
-          if (_filterStatus.writePlaintextNoLongerFull) {
-            _sendWriteEvent();
-          }
-          if (_filterStatus.readEncryptedNoLongerFull) {
-            _readSocket();
-          }
-          if (_filterStatus.readPlaintextNoLongerEmpty) {
-            _scheduleReadEvent();
-          }
+      }
+      if (_filterStatus.readEmpty && _socketClosedRead && !_closedRead) {
+        if (_status == handshakeStatus) {
+          _secureFilter!.handshake();
           if (_status == handshakeStatus) {
-            _secureHandshake();
+            throw new HandshakeException(
+                'Connection terminated during handshake');
           }
         }
-        _tryFilter();
-      }).catchError(_reportError);
+        _closeHandler();
+      }
+      if (_status == closedStatus) {
+        return;
+      }
+      if (_filterStatus.progress) {
+        _filterPending = true;
+        if (_filterStatus.writeEncryptedNoLongerEmpty) {
+          _writeSocket();
+        }
+        if (_filterStatus.writePlaintextNoLongerFull) {
+          _sendWriteEvent();
+        }
+        if (_filterStatus.readEncryptedNoLongerFull) {
+          _readSocket();
+        }
+        if (_filterStatus.readPlaintextNoLongerEmpty) {
+          _scheduleReadEvent();
+        }
+        if (_status == handshakeStatus) {
+          await _secureHandshake();
+        }
+      }
+      return _tryFilter();
+    } catch (e, st) {
+      _reportError(e, st);
     }
   }
 
@@ -1024,7 +1025,7 @@
     }
   }
 
-  Future<_FilterStatus> _pushAllFilterStages() {
+  Future<_FilterStatus> _pushAllFilterStages() async {
     bool wasInHandshake = _status != connectedStatus;
     List args = new List<dynamic>.filled(2 + bufferCount * 2, null);
     args[0] = _secureFilter!._pointer();
@@ -1035,75 +1036,74 @@
       args[2 * i + 3] = bufs[i].end;
     }
 
-    return _IOService._dispatch(_IOService.sslProcessFilter, args)
-        .then((response) {
-      if (response.length == 2) {
-        if (wasInHandshake) {
-          // If we're in handshake, throw a handshake error.
-          _reportError(
-              new HandshakeException('${response[1]} error ${response[0]}'),
-              null);
-        } else {
-          // If we're connected, throw a TLS error.
-          _reportError(
-              new TlsException('${response[1]} error ${response[0]}'), null);
-        }
+    var response =
+        await _IOService._dispatch(_IOService.sslProcessFilter, args);
+    if (response.length == 2) {
+      if (wasInHandshake) {
+        // If we're in handshake, throw a handshake error.
+        _reportError(
+            new HandshakeException('${response[1]} error ${response[0]}'),
+            null);
+      } else {
+        // If we're connected, throw a TLS error.
+        _reportError(
+            new TlsException('${response[1]} error ${response[0]}'), null);
       }
-      int start(int index) => response[2 * index];
-      int end(int index) => response[2 * index + 1];
+    }
+    int start(int index) => response[2 * index];
+    int end(int index) => response[2 * index + 1];
 
-      _FilterStatus status = new _FilterStatus();
-      // Compute writeEmpty as "write plaintext buffer and write encrypted
-      // buffer were empty when we started and are empty now".
-      status.writeEmpty = bufs[writePlaintextId].isEmpty &&
-          start(writeEncryptedId) == end(writeEncryptedId);
-      // If we were in handshake when this started, _writeEmpty may be false
-      // because the handshake wrote data after we checked.
-      if (wasInHandshake) status.writeEmpty = false;
+    _FilterStatus status = new _FilterStatus();
+    // Compute writeEmpty as "write plaintext buffer and write encrypted
+    // buffer were empty when we started and are empty now".
+    status.writeEmpty = bufs[writePlaintextId].isEmpty &&
+        start(writeEncryptedId) == end(writeEncryptedId);
+    // If we were in handshake when this started, _writeEmpty may be false
+    // because the handshake wrote data after we checked.
+    if (wasInHandshake) status.writeEmpty = false;
 
-      // Compute readEmpty as "both read buffers were empty when we started
-      // and are empty now".
-      status.readEmpty = bufs[readEncryptedId].isEmpty &&
-          start(readPlaintextId) == end(readPlaintextId);
+    // Compute readEmpty as "both read buffers were empty when we started
+    // and are empty now".
+    status.readEmpty = bufs[readEncryptedId].isEmpty &&
+        start(readPlaintextId) == end(readPlaintextId);
 
-      _ExternalBuffer buffer = bufs[writePlaintextId];
-      int new_start = start(writePlaintextId);
-      if (new_start != buffer.start) {
-        status.progress = true;
-        if (buffer.free == 0) {
-          status.writePlaintextNoLongerFull = true;
-        }
-        buffer.start = new_start;
+    _ExternalBuffer buffer = bufs[writePlaintextId];
+    int new_start = start(writePlaintextId);
+    if (new_start != buffer.start) {
+      status.progress = true;
+      if (buffer.free == 0) {
+        status.writePlaintextNoLongerFull = true;
       }
-      buffer = bufs[readEncryptedId];
-      new_start = start(readEncryptedId);
-      if (new_start != buffer.start) {
-        status.progress = true;
-        if (buffer.free == 0) {
-          status.readEncryptedNoLongerFull = true;
-        }
-        buffer.start = new_start;
+      buffer.start = new_start;
+    }
+    buffer = bufs[readEncryptedId];
+    new_start = start(readEncryptedId);
+    if (new_start != buffer.start) {
+      status.progress = true;
+      if (buffer.free == 0) {
+        status.readEncryptedNoLongerFull = true;
       }
-      buffer = bufs[writeEncryptedId];
-      int new_end = end(writeEncryptedId);
-      if (new_end != buffer.end) {
-        status.progress = true;
-        if (buffer.length == 0) {
-          status.writeEncryptedNoLongerEmpty = true;
-        }
-        buffer.end = new_end;
+      buffer.start = new_start;
+    }
+    buffer = bufs[writeEncryptedId];
+    int new_end = end(writeEncryptedId);
+    if (new_end != buffer.end) {
+      status.progress = true;
+      if (buffer.length == 0) {
+        status.writeEncryptedNoLongerEmpty = true;
       }
-      buffer = bufs[readPlaintextId];
-      new_end = end(readPlaintextId);
-      if (new_end != buffer.end) {
-        status.progress = true;
-        if (buffer.length == 0) {
-          status.readPlaintextNoLongerEmpty = true;
-        }
-        buffer.end = new_end;
+      buffer.end = new_end;
+    }
+    buffer = bufs[readPlaintextId];
+    new_end = end(readPlaintextId);
+    if (new_end != buffer.end) {
+      status.progress = true;
+      if (buffer.length == 0) {
+        status.readPlaintextNoLongerEmpty = true;
       }
-      return status;
-    });
+      buffer.end = new_end;
+    }
+    return status;
   }
 }
 
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 0c5747e..b7650dd 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -671,9 +671,12 @@
    * receive messages. See [Stream.asBroadcastStream] for transforming the port
    * to a broadcast stream.
    *
+   * The optional `debugName` parameter can be set to associate a name with
+   * this port that can be displayed in tooling.
+   *
    * A receive port is closed by canceling its subscription.
    */
-  external factory ReceivePort();
+  external factory ReceivePort([String debugName = '']);
 
   /**
    * Creates a [ReceivePort] from a [RawReceivePort].
@@ -718,8 +721,12 @@
    * A [RawReceivePort] is low level and does not work with [Zone]s. It
    * can not be paused. The data-handler must be set before the first
    * event is received.
+   *
+   * The optional `debugName` parameter can be set to associate a name with
+   * this port that can be displayed in tooling.
+   *
    */
-  external factory RawReceivePort([Function? handler]);
+  external factory RawReceivePort([Function? handler, String debugName = '']);
 
   /**
    * Sets the handler that is invoked for every incoming message.
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
index 7ed8c58..660a546 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
@@ -2,6 +2,7 @@
 // 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.
 
+// Requirements=nnbd-strong
 // dart2jsOptions=--no-native-null-assertions
 
 import 'non_web_library_interfaces.dart';
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
index ee0d648..8b7ee4c 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
@@ -2,6 +2,7 @@
 // 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.
 
+// Requirements=nnbd-strong
 // dart2jsOptions=--no-native-null-assertions
 
 import 'null_assertions_test_lib.dart';
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
index 61c018b..e923657 100644
--- a/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
@@ -2,6 +2,7 @@
 // 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.
 
+// Requirements=nnbd-strong
 // dart2jsOptions=--native-null-assertions
 
 import 'non_web_library_interfaces.dart';
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
index 71baddf..2c41d2a 100644
--- a/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
@@ -2,6 +2,7 @@
 // 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.
 
+// Requirements=nnbd-strong
 // dart2jsOptions=--native-null-assertions
 
 import 'null_assertions_test_lib.dart';
diff --git a/tests/ffi/dylib_isolates_test.dart b/tests/ffi/dylib_isolates_test.dart
index 5eb73ef..f790e12 100644
--- a/tests/ffi/dylib_isolates_test.dart
+++ b/tests/ffi/dylib_isolates_test.dart
@@ -7,6 +7,7 @@
 // SharedObjects=ffi_test_functions
 
 import 'dart:ffi';
+import 'dart:io';
 import 'dart:isolate';
 
 import "package:expect/expect.dart";
@@ -29,7 +30,9 @@
   final receivePort = ReceivePort();
   Isolate.spawn(secondIsolateMain, receivePort.sendPort);
   await receivePort.first;
-  Expect.equals(42, getGlobalVar());
+  if (!Platform.isIOS /* Static linking causes different behavior. */) {
+    Expect.equals(42, getGlobalVar());
+  }
 }
 
 void secondIsolateMain(SendPort sendPort) {
diff --git a/tests/ffi/prepare_flutter_bundle.dart b/tests/ffi/prepare_flutter_bundle.dart
deleted file mode 100644
index 83a4a42..0000000
--- a/tests/ffi/prepare_flutter_bundle.dart
+++ /dev/null
@@ -1,204 +0,0 @@
-// 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.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:path/path.dart' as path;
-import 'package:args/args.dart';
-
-main(List<String> args) async {
-  if (args.length != 1) {
-    print('Usage ${Platform.executable} ${Platform.script} <output-dir>');
-    exit(1);
-  }
-
-  final sdkRoot =
-      path.canonicalize(path.join(Platform.script.path, '../../..'));
-  final flutterTestsDir = args.single;
-
-  print('Using SDK root: $sdkRoot');
-  final testFiles = <String>[];
-  final failedOrTimedOut = <String>[];
-  final filteredTests = <String>[];
-  await for (final testFile in listTestFiles(sdkRoot, filteredTests)) {
-    final duration = await run(sdkRoot, testFile);
-    if (duration != null && duration.inSeconds < 5) {
-      testFiles.add(testFile);
-    } else {
-      failedOrTimedOut.add(testFile);
-    }
-  }
-  testFiles.sort();
-  failedOrTimedOut.sort();
-  filteredTests.sort();
-
-  dumpTestList(testFiles, 'The following tests will be included:');
-  dumpTestList(failedOrTimedOut,
-      'The following tests will be excluded due to timeout or test failure:');
-  dumpTestList(
-      filteredTests,
-      'The following tests were filtered due to using '
-      'dart_api.h/async/DynamicLibrary.{process,executable}/...');
-
-  final allFiles = <String>{};
-  allFiles.add(path.join(sdkRoot, 'pkg/expect/lib/expect.dart'));
-  for (final testFile in testFiles) {
-    allFiles.add(testFile);
-    await addImportedFilesTo(allFiles, testFile);
-  }
-
-  await generateCleanDir(flutterTestsDir);
-
-  final dartTestsDir = path.join(flutterTestsDir, 'lib/src/generated');
-  await generateDartTests(dartTestsDir, allFiles, testFiles);
-
-  final ccDir = path.join(flutterTestsDir, 'ios/Classes');
-  await generateCLibs(sdkRoot, ccDir, allFiles, testFiles);
-
-  print('');
-  print('Please copy generated files into FFI flutter test application');
-  print('  * $dartTestsDir');
-  print('  * $ccDir');
-}
-
-void dumpTestList(List<String> testFiles, String message) {
-  if (testFiles.isEmpty) return;
-
-  print(message);
-  for (final testFile in testFiles) {
-    print('  ${path.basename(testFile)}');
-  }
-}
-
-final importRegExp = RegExp(r'''^import.*['"](.+)['"].*;''');
-
-Future addImportedFilesTo(Set<String> allFiles, String testFile) async {
-  final content = await File(testFile).readAsString();
-  for (final line in content.split('\n')) {
-    final match = importRegExp.matchAsPrefix(line);
-    if (match != null) {
-      final filename = match.group(1);
-      if (!filename.contains('dart:') &&
-          !filename.contains('package:expect') &&
-          !filename.contains('package:ffi')) {
-        final importedFile = Uri.file(testFile).resolve(filename).toFilePath();
-        if (allFiles.add(importedFile)) {
-          addImportedFilesTo(allFiles, importedFile);
-        }
-      }
-    }
-  }
-}
-
-Future generateCLibs(String sdkRoot, String destDir, Set<String> allFiles,
-    List<String> testFiles) async {
-  final dir = await generateCleanDir(destDir);
-
-  String destinationFile;
-
-  final lib1 =
-      path.join(sdkRoot, 'runtime/bin/ffi_test/ffi_test_dynamic_library.cc');
-  destinationFile =
-      path.join(dir.path, path.basename(lib1)).replaceAll('.cc', '.cpp');
-  File(destinationFile).writeAsStringSync(File(lib1).readAsStringSync());
-
-  final lib2 = path.join(sdkRoot, 'runtime/bin/ffi_test/ffi_test_functions.cc');
-  destinationFile =
-      path.join(dir.path, path.basename(lib2)).replaceAll('.cc', '.cpp');
-  File(destinationFile).writeAsStringSync(File(lib2).readAsStringSync());
-}
-
-String cleanDart(String content) {
-  return content.replaceAll('package:expect/expect.dart', 'expect.dart');
-}
-
-Future generateDartTests(
-    String destDir, Set<String> allFiles, List<String> testFiles) async {
-  final dir = await generateCleanDir(destDir);
-
-  final sink = File(path.join(dir.path, 'all.dart')).openWrite();
-  sink.writeln('import "dart:async";');
-  sink.writeln('');
-  for (int i = 0; i < testFiles.length; ++i) {
-    sink.writeln('import "${path.basename(testFiles[i])}" as main$i;');
-  }
-  sink.writeln('');
-  sink.writeln('Future invoke(dynamic fun) async {');
-  sink.writeln('  if (fun is void Function() || fun is Future Function()) {');
-  sink.writeln('    return await fun();');
-  sink.writeln('  } else {');
-  sink.writeln('    return await fun(<String>[]);');
-  sink.writeln('  }');
-  sink.writeln('}');
-  sink.writeln('');
-  sink.writeln('dynamic main() async {');
-  for (int i = 0; i < testFiles.length; ++i) {
-    sink.writeln('  await invoke(main$i.main);');
-  }
-  sink.writeln('}');
-  await sink.close();
-
-  for (final file in allFiles) {
-    File(path.join(dir.path, path.basename(file)))
-        .writeAsStringSync(cleanDart(File(file).readAsStringSync()));
-  }
-
-  File(path.join(dir.path, 'dylib_utils.dart')).writeAsStringSync('''
-import 'dart:ffi' as ffi;
-import 'dart:io' show Platform;
-
-ffi.DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
-  return Platform.isAndroid
-      ? ffi.DynamicLibrary.open('libffi_tests.so')
-      : ffi.DynamicLibrary.process();
-}
-''');
-}
-
-Stream<String> listTestFiles(
-    String sdkRoot, List<String> filteredTests) async* {
-  await for (final file in Directory(path.join(sdkRoot, 'tests/ffi')).list()) {
-    if (file is File && file.path.endsWith('_test.dart')) {
-      // These tests are VM specific and cannot necessarily be run on Flutter.
-      if (path.basename(file.path).startsWith('vmspecific_')) {
-        filteredTests.add(file.path);
-        continue;
-      }
-      // These tests use special features which are hard to test on Flutter.
-      final contents = file.readAsStringSync();
-      if (contents.contains(RegExp('//# .* compile-time error')) ||
-          contents.contains('DynamicLibrary.process') ||
-          contents.contains('DynamicLibrary.executable')) {
-        filteredTests.add(file.path);
-        continue;
-      }
-      yield file.path;
-    }
-  }
-}
-
-Future<Duration> run(String sdkRoot, String testFile) async {
-  final env = Map<String, String>.from(Platform.environment);
-  env['LD_LIBRARY_PATH'] = path.join(sdkRoot, 'out/ReleaseX64');
-  final sw = Stopwatch()..start();
-  final Process process = await Process.start(
-      Platform.executable, <String>[testFile],
-      environment: env);
-  final timer = Timer(const Duration(seconds: 3), () => process.kill());
-  process.stdout.listen((_) {});
-  process.stderr.listen((_) {});
-  if (await process.exitCode != 0) return null;
-  timer.cancel();
-  return sw.elapsed;
-}
-
-Future<Directory> generateCleanDir(String dirname) async {
-  final directory = Directory(dirname);
-  if (await directory.exists()) {
-    await directory.delete(recursive: true);
-  }
-  await directory.create(recursive: true);
-  return directory;
-}
diff --git a/tests/ffi/regress_37254_test.dart b/tests/ffi/regress_37254_test.dart
index b4fce7c..ce696af 100644
--- a/tests/ffi/regress_37254_test.dart
+++ b/tests/ffi/regress_37254_test.dart
@@ -238,7 +238,6 @@
 }
 
 void main() {
-  // Trigger both the runtime entry and the IL in bytecode.
   for (int i = 0; i < 100; i++) {
     store1();
     store2();
diff --git a/tests/ffi/regress_43016_test.dart b/tests/ffi/regress_43016_test.dart
index 8468fcd..f1489e0 100644
--- a/tests/ffi/regress_43016_test.dart
+++ b/tests/ffi/regress_43016_test.dart
@@ -27,7 +27,6 @@
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
 void main() {
-  // Trigger both the runtime entry and the IL in bytecode.
   for (int i = 0; i < 10000; i++) {
     pass_struct(nullptr);
   }
diff --git a/tests/ffi_2/dylib_isolates_test.dart b/tests/ffi_2/dylib_isolates_test.dart
index 5eb73ef..f790e12 100644
--- a/tests/ffi_2/dylib_isolates_test.dart
+++ b/tests/ffi_2/dylib_isolates_test.dart
@@ -7,6 +7,7 @@
 // SharedObjects=ffi_test_functions
 
 import 'dart:ffi';
+import 'dart:io';
 import 'dart:isolate';
 
 import "package:expect/expect.dart";
@@ -29,7 +30,9 @@
   final receivePort = ReceivePort();
   Isolate.spawn(secondIsolateMain, receivePort.sendPort);
   await receivePort.first;
-  Expect.equals(42, getGlobalVar());
+  if (!Platform.isIOS /* Static linking causes different behavior. */) {
+    Expect.equals(42, getGlobalVar());
+  }
 }
 
 void secondIsolateMain(SendPort sendPort) {
diff --git a/tests/ffi_2/prepare_flutter_bundle.dart b/tests/ffi_2/prepare_flutter_bundle.dart
index 83a4a42..8ff9447 100644
--- a/tests/ffi_2/prepare_flutter_bundle.dart
+++ b/tests/ffi_2/prepare_flutter_bundle.dart
@@ -6,7 +6,9 @@
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
-import 'package:args/args.dart';
+
+// TODO(dacoharkes): Migrate script to be nullsafe and generate nullsafe
+// Flutter app.
 
 main(List<String> args) async {
   if (args.length != 1) {
@@ -51,16 +53,34 @@
 
   await generateCleanDir(flutterTestsDir);
 
-  final dartTestsDir = path.join(flutterTestsDir, 'lib/src/generated');
+  final dartTestsDirRelative = 'example/lib';
+  final dartTestsDir = path.join(flutterTestsDir, dartTestsDirRelative);
   await generateDartTests(dartTestsDir, allFiles, testFiles);
 
-  final ccDir = path.join(flutterTestsDir, 'ios/Classes');
+  final ccDirRelative = 'ios/Classes';
+  final ccDir = path.join(flutterTestsDir, ccDirRelative);
   await generateCLibs(sdkRoot, ccDir, allFiles, testFiles);
 
-  print('');
-  print('Please copy generated files into FFI flutter test application');
-  print('  * $dartTestsDir');
-  print('  * $ccDir');
+  print('''
+
+Files generated in:
+  * $dartTestsDir
+  * $ccDir
+
+Generate flutter test application with:
+  flutter create --platforms=android,ios --template=plugin <ffi_test_app_name>
+
+Please copy generated files into FFI flutter test application:
+  cd <ffi_test_app_dir> && cp -r $flutterTestsDir ./
+
+After copying modify the test application:
+  * Modify example/pubspec.yaml to depend on package:ffi.
+  * Modify example/lib/main.dart to invoke all.dart while rendering.
+  * Open example/ios/Runner.xcworkspace in Xcode.
+    * Add the cpp files to Pods/Development Pods/<deep nesting>/ios/Classes
+      to ensure they are statically linked to the app.
+''');
+  // TODO(dacoharkes): Automate these steps. How to automate the XCode step?
 }
 
 void dumpTestList(List<String> testFiles, String message) {
@@ -108,6 +128,12 @@
   destinationFile =
       path.join(dir.path, path.basename(lib2)).replaceAll('.cc', '.cpp');
   File(destinationFile).writeAsStringSync(File(lib2).readAsStringSync());
+
+  final lib3 = path.join(
+      sdkRoot, 'runtime/bin/ffi_test/ffi_test_functions_generated.cc');
+  destinationFile =
+      path.join(dir.path, path.basename(lib3)).replaceAll('.cc', '.cpp');
+  File(destinationFile).writeAsStringSync(File(lib3).readAsStringSync());
 }
 
 String cleanDart(String content) {
@@ -159,7 +185,8 @@
 
 Stream<String> listTestFiles(
     String sdkRoot, List<String> filteredTests) async* {
-  await for (final file in Directory(path.join(sdkRoot, 'tests/ffi')).list()) {
+  await for (final file
+      in Directory(path.join(sdkRoot, 'tests/ffi_2')).list()) {
     if (file is File && file.path.endsWith('_test.dart')) {
       // These tests are VM specific and cannot necessarily be run on Flutter.
       if (path.basename(file.path).startsWith('vmspecific_')) {
diff --git a/tests/ffi_2/regress_37254_test.dart b/tests/ffi_2/regress_37254_test.dart
index dcd42b9..6ba796f 100644
--- a/tests/ffi_2/regress_37254_test.dart
+++ b/tests/ffi_2/regress_37254_test.dart
@@ -238,7 +238,6 @@
 }
 
 void main() {
-  // Trigger both the runtime entry and the IL in bytecode.
   for (int i = 0; i < 100; i++) {
     store1();
     store2();
diff --git a/tests/ffi_2/regress_43016_test.dart b/tests/ffi_2/regress_43016_test.dart
index 1d06b87..b0ebc0c 100644
--- a/tests/ffi_2/regress_43016_test.dart
+++ b/tests/ffi_2/regress_43016_test.dart
@@ -27,7 +27,6 @@
 final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
 void main() {
-  // Trigger both the runtime entry and the IL in bytecode.
   for (int i = 0; i < 10000; i++) {
     pass_struct(nullptr);
   }
diff --git a/tools/VERSION b/tools/VERSION
index 6a2eb32..ce12cbe 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 273
+PRERELEASE 274
 PRERELEASE_PATCH 0
\ No newline at end of file