Version 2.15.0-268.8.beta

* Cherry-pick 243fb5c383416fb82b6852a83ad3c4449683858a to beta
* Cherry-pick 1ca06b953112612cd6250d2b11bb776688ec8e1a to beta
* Cherry-pick b8e419d16b10be073f080192a55aaf598321ca10 to beta
* Cherry-pick dc7e082336fc7a9c639c1d62edf4cc0ebb57ea51 to beta
* Cherry-pick 6225f46b760a5c1eebff9c4dce621e93192a886c to beta
* Cherry-pick b97737c3b53a6c043a6a1b97e61b8670ded75629 to beta
* Cherry-pick 109c317ac12a43d8a25b14bca9805276bf8c84ee to beta
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03de374..c611f3b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -429,9 +429,12 @@
 
 #### `dart:js_util`
 
-- The `js_util` methods `getProperty`, `setProperty`, `callMethod`,
-  `callConstructor`, and `newObject` now support a generic type argument
-  to specify the return type.
+- The `js_util` methods `setProperty`, `callMethod`, and `callConstructor` have
+  been optimized to remove checks on arguments when the checks can be elided.
+  Also, those methods, along with `getProperty` and `newObject`, now support a
+  generic type argument to specify a return type. These two changes make simple
+  `js_util` usage, like reading and writing primitive properties or calling
+  methods with simple arguments, have zero overhead.
 
 #### `dart:web_sql`
 
@@ -592,6 +595,14 @@
   `dart pub get/upgrade/downgrade/add/remove` that will result in the `example/`
   folder dependencies to be updated after operating in the current directory.
 
+### Other libraries
+
+#### `package:js`
+
+- Extensions on JS interop or native `dart:html` classes can now declare
+  members as `external`. These members are equivalent to regular extension
+  members that use `js_util` to expose the underlying JavaScript.
+
 ## 2.14.4 - 2021-10-14
 
 This is a patch release that fixes:
diff --git a/DEPS b/DEPS
index 18e0f7a..cb395cc 100644
--- a/DEPS
+++ b/DEPS
@@ -107,7 +107,7 @@
   "dart_style_rev": "08b0294d0a500d5c02168ef57dcb8868d0c3cb48",
 
   "dartdoc_rev" : "520e64977de7a87b2fd5be56e5c2e1a58d55bdad",
-  "devtools_rev" : "8881a7caa9067471008a8e00750b161f53cdb843",
+  "devtools_rev" : "3a2f570813200e6dee141f3e7a9edcae5f31c2e8",
   "jsshell_tag": "version:88.0",
   "ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
   "fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
@@ -139,7 +139,7 @@
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "process_rev": "56ece43b53b64c63ae51ec184b76bd5360c28d0b",
   "protobuf_rev": "c1eb6cb51af39ccbaa1a8e19349546586a5c8e31",
-  "pub_rev": "0035a40f25d027130c0314571da53ffafc6d973b",
+  "pub_rev": "96404e0749864c9fbf8b12e1d424e8078809e00a",
   "pub_semver_rev": "a43ad72fb6b7869607581b5fedcb186d1e74276a",
   "root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
   "rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244",
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index dc0030a..ac9fbb1 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -632,39 +632,31 @@
 
   @override
   DartObjectImpl? visitConstructorReference(ConstructorReference node) {
-    var constructorTearoffResult = DartObjectImpl(
+    var constructorFunctionType = node.typeOrThrow as FunctionType;
+    var classType = constructorFunctionType.returnType as InterfaceType;
+    var typeArguments = classType.typeArguments;
+    // The result is already instantiated during resolution;
+    // [_dartObjectComputer.typeInstantiate] is unnecessary.
+    var typeElement =
+        node.constructorName.type2.name.staticElement as TypeDefiningElement;
+
+    TypeAliasElement? viaTypeAlias;
+    if (typeElement is TypeAliasElementImpl) {
+      if (constructorFunctionType.typeFormals.isNotEmpty &&
+          !typeElement.isProperRename()) {
+        // The type alias is not a proper rename of the aliased class, so
+        // the constructor tear-off is distinct from the associated
+        // constructor function of the aliased class.
+        viaTypeAlias = typeElement;
+      }
+    }
+
+    return DartObjectImpl(
       typeSystem,
       node.typeOrThrow,
-      FunctionState(node.constructorName.staticElement),
+      FunctionState(node.constructorName.staticElement,
+          typeArguments: typeArguments, viaTypeAlias: viaTypeAlias),
     );
-    var typeArgumentList = node.constructorName.type2.typeArguments;
-    if (typeArgumentList == null) {
-      return constructorTearoffResult;
-    } else {
-      var typeArguments = <DartType>[];
-      for (var typeArgument in typeArgumentList.arguments) {
-        var object = typeArgument.accept(this);
-        if (object == null) {
-          return null;
-        }
-        var typeArgumentType = object.toTypeValue();
-        if (typeArgumentType == null) {
-          return null;
-        }
-        // TODO(srawlins): Test type alias types (`typedef i = int`) used as
-        // type arguments. Possibly change implementation based on
-        // canonicalization rules.
-        typeArguments.add(typeArgumentType);
-      }
-      // The result is already instantiated during resolution;
-      // [_dartObjectComputer.typeInstantiate] is unnecessary.
-      return DartObjectImpl(
-        typeSystem,
-        node.typeOrThrow,
-        FunctionState(node.constructorName.staticElement,
-            typeArguments: typeArguments),
-      );
-    }
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index 227abea..094b8b6 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -920,11 +920,14 @@
     List<DartType> typeArguments,
   ) {
     var functionState = _state as FunctionState;
-    var element = functionState._element;
     return DartObjectImpl(
       typeSystem,
       type,
-      FunctionState(element, typeArguments: typeArguments),
+      FunctionState(
+        functionState._element,
+        typeArguments: typeArguments,
+        viaTypeAlias: functionState._viaTypeAlias,
+      ),
     );
   }
 
@@ -1245,10 +1248,22 @@
 
   final List<DartType>? _typeArguments;
 
+  /// The type alias which was referenced when tearing off a constructor,
+  /// if this function is a constructor tear-off, referenced via a type alias,
+  /// and the type alias is not a proper rename for the class, and the
+  /// constructor tear-off is generic, so the tear-off cannot be considered
+  /// equivalent to tearing off the associated constructor function of the
+  /// aliased class.
+  ///
+  /// Otherwise null.
+  final TypeDefiningElement? _viaTypeAlias;
+
   /// Initialize a newly created state to represent the function with the given
   /// [element].
-  FunctionState(this._element, {List<DartType>? typeArguments})
-      : _typeArguments = typeArguments;
+  FunctionState(this._element,
+      {List<DartType>? typeArguments, TypeDefiningElement? viaTypeAlias})
+      : _typeArguments = typeArguments,
+        _viaTypeAlias = viaTypeAlias;
 
   @override
   int get hashCode => _element == null ? 0 : _element.hashCode;
@@ -1272,6 +1287,9 @@
     if (typeArguments.length != otherTypeArguments.length) {
       return false;
     }
+    if (_viaTypeAlias != object._viaTypeAlias) {
+      return false;
+    }
     for (var i = 0; i < typeArguments.length; i++) {
       if (typeArguments[i] != otherTypeArguments[i]) {
         return false;
@@ -1309,6 +1327,9 @@
       if (element?.declaration != otherElement?.declaration) {
         return BoolState.FALSE_STATE;
       }
+      if (_viaTypeAlias != rightOperand._viaTypeAlias) {
+        return BoolState.FALSE_STATE;
+      }
       var typeArguments = _typeArguments;
       var otherTypeArguments = rightOperand._typeArguments;
       if (typeArguments == null || otherTypeArguments == null) {
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 549136f..d5bc77f 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -5582,6 +5582,37 @@
     }
   }
 
+  /// Returns whether this alias is a "proper rename" of [aliasedClass], as
+  /// defined in the constructor-tearoffs specification.
+  bool isProperRename() {
+    var aliasedType_ = aliasedType;
+    if (aliasedType_ is! InterfaceType) {
+      return false;
+    }
+    var aliasedClass = aliasedType_.element;
+    var typeArguments = aliasedType_.typeArguments;
+    var typeParameterCount = typeParameters.length;
+    if (typeParameterCount != aliasedClass.typeParameters.length) {
+      return false;
+    }
+    if (typeParameterCount != typeArguments.length) {
+      return false;
+    }
+    for (var i = 0; i < typeParameterCount; i++) {
+      var bound = typeParameters[i].bound ?? library.typeProvider.dynamicType;
+      var aliasedBound = aliasedClass.typeParameters[i].bound ??
+          library.typeProvider.dynamicType;
+      if (!library.typeSystem.isSubtypeOf(bound, aliasedBound) ||
+          !library.typeSystem.isSubtypeOf(aliasedBound, bound)) {
+        return false;
+      }
+      if (typeParameters[i] != typeArguments[i].element) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   void setLinkedData(Reference reference, ElementLinkedData linkedData) {
     this.reference = reference;
     reference.element = this;
diff --git a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
index ceecf70..4ef8323 100644
--- a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
@@ -123,6 +123,7 @@
         constructorName.staticElement = constructorElement.declaration;
         constructorName.name?.staticElement = constructorElement.declaration;
         node.staticType = inferred;
+        // The NamedType child of `constructorName` doesn't have a static type.
         constructorName.type2.type = null;
       }
     } else {
@@ -132,6 +133,7 @@
       } else {
         node.staticType = constructorElement.type;
       }
+      // The NamedType child of `constructorName` doesn't have a static type.
       constructorName.type2.type = null;
     }
   }
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index f544ef9..26f0785 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -28,6 +28,126 @@
 @reflectiveTest
 class ConstantVisitorTest extends ConstantVisitorTestSupport
     with ConstantVisitorTestCases {
+  test_identical_constructorReference_aliasIsNotGeneric() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC = C<int>;
+const a = identical(MyC.new, C<int>.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsNotProperRename_differentBound() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T extends num> = C<T>;
+const a = identical(MyC.new, C.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(false),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsNotProperRename_differentCount() async {
+    await resolveTestCode('''
+class C<T, U> {}
+typedef MyC<T> = C<T, int>;
+const a = identical(MyC.new, C.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(false),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsNotProperRename_differentOrder() async {
+    await resolveTestCode('''
+class C<T, U> {}
+typedef MyC<T, U> = C<U, T>;
+const a = identical(MyC.new, C.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(false),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsNotProperRename_instantiated() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T extends num> = C<T>;
+const a = identical(MyC<int>.new, C<int>.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsNotProperRename_mixedInstantiations() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T extends num> = C<T>;
+const a = identical(MyC<int>.new, (MyC.new)<int>);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(false),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsProperRename_instantiated() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T> = C<T>;
+const a = identical(MyC<int>.new, MyC<int>.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsProperRename_mixedInstantiations() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T> = C<T>;
+const a = identical(MyC<int>.new, (MyC.new)<int>);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsProperRename_mutualSubtypes() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T extends Object?> = C<T>;
+const a = identical(MyC<int>.new, MyC<int>.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
+  test_identical_constructorReference_aliasIsProperRename_uninstantiated() async {
+    await resolveTestCode('''
+class C<T> {}
+typedef MyC<T> = C<T>;
+const a = identical(MyC.new, MyC.new);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
   test_identical_constructorReference_explicitTypeArgs_differentClasses() async {
     await resolveTestCode('''
 class C<T> {}
@@ -76,6 +196,19 @@
     );
   }
 
+  test_identical_constructorReference_inferredTypeArgs_sameElement() async {
+    await resolveTestCode('''
+class C<T> {}
+const C<int> Function() c1 = C.new;
+const c2 = C<int>.new;
+const a = identical(c1, c2);
+''');
+    expect(
+      _evaluateConstant('a'),
+      _boolValue(true),
+    );
+  }
+
   test_identical_constructorReference_notInstantiated_differentClasses() async {
     await resolveTestCode('''
 class C<T> {}
diff --git a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
index 48f946f..0b2478b 100644
--- a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
@@ -85,6 +85,26 @@
     );
   }
 
+  test_alias_generic_uninstantiated_const() async {
+    await assertNoErrorsInCode('''
+class A<T, U> {
+  const A.foo();
+}
+typedef TA<T, U> = A<U, T>;
+
+const a = TA.foo;
+''');
+
+    var classElement = findElement.class_('A');
+    assertConstructorReference(
+      findNode.constructorReference('TA.foo;'),
+      classElement.getNamedConstructor('foo'),
+      classElement,
+      'A<U, T> Function<T, U>()',
+      expectedTypeNameElement: findElement.typeAlias('TA'),
+    );
+  }
+
   test_alias_generic_unnamed() async {
     await assertNoErrorsInCode('''
 class A<T> {
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index bed3b36..6a27317 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -150,13 +150,12 @@
     }
   }
 
-  void assertConstructorElement(
-      ConstructorElement? expected, ConstructorElement? actual) {
-    if (expected is ConstructorMember && actual is ConstructorMember) {
-      expect(expected.declaration, same(actual.declaration));
+  void assertConstructorElement(ConstructorElement? actual, Object? expected) {
+    if (actual is ConstructorMember && expected is ConstructorMember) {
+      expect(actual.declaration, same(expected.declaration));
       // TODO(brianwilkerson) Compare the type arguments of the two members.
     } else {
-      expect(expected, same(actual));
+      assertElement(actual, expected);
     }
   }
 
@@ -168,12 +167,11 @@
     PrefixElement? expectedPrefix,
     Element? expectedTypeNameElement,
   }) {
-    var actualConstructorElement = getNodeElement(node) as ConstructorElement?;
     var actualConstructorName = node.constructorName.name;
     if (actualConstructorName != null) {
       assertConstructorElement(
         actualConstructorName.staticElement as ConstructorElement?,
-        actualConstructorElement,
+        expectedConstructorElement,
       );
     }
 
@@ -182,8 +180,13 @@
 
     var namedType = node.constructorName.type2;
     expectedTypeNameElement ??= expectedClassElement;
-    assertNamedType(namedType, expectedTypeNameElement, null,
-        expectedPrefix: expectedPrefix);
+    assertNamedType(
+      namedType, expectedTypeNameElement,
+      // The [NamedType] child node of the [ConstructorName] should not have a
+      // static type.
+      null,
+      expectedPrefix: expectedPrefix,
+    );
   }
 
   void assertConstructors(ClassElement class_, List<String> expected) {
diff --git a/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart b/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
index 6cc3be4..169a1b9 100644
--- a/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
+++ b/runtime/tests/vm/dart/isolates/fast_object_copy_test.dart
@@ -233,6 +233,7 @@
     await testMapRehash();
     await testMapRehash2();
     await testMapRehash3();
+    await testMapRehash4();
 
     await testSetRehash();
     await testSetRehash2();
@@ -532,6 +533,27 @@
     Expect.equals(before + 1, after);
   }
 
+  Future testMapRehash4() async {
+    // This is a regression test for http://dartbug.com/47598
+    print('testMapRehash4');
+
+    // This map doesn't need rehashing
+    final graph = {'a': 1, 'b': 2, 'c': 3}..remove('b');
+    final graphCopy = (await sendReceive(graph) as Map);
+    Expect.equals(2, graphCopy.length);
+    Expect.equals(1, graphCopy['a']);
+    Expect.equals(3, graphCopy['c']);
+
+    // This map will need re-hashing due to usage of a key that has a
+    // user-defined get:hashCode.
+    final graph2 = {'a': 1, 'b': 2, const HashIncrementer(): 3}..remove('b');
+    final graph2Copy = (await sendReceive(graph2) as Map);
+    Expect.equals(2, graph2Copy.length);
+    Expect.equals(1, graph2Copy['a']);
+    --HashIncrementer.counter;
+    Expect.equals(3, graph2Copy[const HashIncrementer()]);
+  }
+
   Future testSetRehash() async {
     print('testSetRehash');
     final obj = Object();
diff --git a/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart b/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
index 79de0c5..1a1512d 100644
--- a/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
+++ b/runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
@@ -235,6 +235,7 @@
     await testMapRehash();
     await testMapRehash2();
     await testMapRehash3();
+    await testMapRehash4();
 
     await testSetRehash();
     await testSetRehash2();
@@ -534,6 +535,27 @@
     Expect.equals(before + 1, after);
   }
 
+  Future testMapRehash4() async {
+    // This is a regression test for http://dartbug.com/47598
+    print('testMapRehash4');
+
+    // This map doesn't need rehashing
+    final graph = {'a': 1, 'b': 2, 'c': 3}..remove('b');
+    final graphCopy = (await sendReceive(graph) as Map);
+    Expect.equals(2, graphCopy.length);
+    Expect.equals(1, graphCopy['a']);
+    Expect.equals(3, graphCopy['c']);
+
+    // This map will need re-hashing due to usage of a key that has a
+    // user-defined get:hashCode.
+    final graph2 = {'a': 1, 'b': 2, const HashIncrementer(): 3}..remove('b');
+    final graph2Copy = (await sendReceive(graph2) as Map);
+    Expect.equals(2, graph2Copy.length);
+    Expect.equals(1, graph2Copy['a']);
+    --HashIncrementer.counter;
+    Expect.equals(3, graph2Copy[const HashIncrementer()]);
+  }
+
   Future testSetRehash() async {
     print('testSetRehash');
     final obj = Object();
diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc
index bb715ff..d348aec 100644
--- a/runtime/vm/object_graph_copy.cc
+++ b/runtime/vm/object_graph_copy.cc
@@ -1148,8 +1148,9 @@
       auto key_value_pairs = untagged_data->data();
       for (intptr_t i = 0; i < length; i += one_for_set_two_for_map) {
         ObjectPtr key = key_value_pairs[i].Decompress(Base::heap_base_);
+        const bool is_deleted_entry = key == data;
         if (key->IsHeapObject()) {
-          if (MightNeedReHashing(key)) {
+          if (!is_deleted_entry && MightNeedReHashing(key)) {
             needs_rehashing = true;
             break;
           }
@@ -1171,6 +1172,7 @@
     if (needs_rehashing) {
       to_untagged->hash_mask_ = Smi::New(0);
       to_untagged->index_ = TypedData::RawCast(Object::null());
+      to_untagged->deleted_keys_ = Smi::New(0);
       Base::EnqueueObjectToRehash(to);
     }
 
@@ -1185,15 +1187,15 @@
       Base::StoreCompressedPointersNoBarrier(
           from, to, OFFSET_OF(UntaggedLinkedHashBase, hash_mask_),
           OFFSET_OF(UntaggedLinkedHashBase, hash_mask_));
+      Base::StoreCompressedPointersNoBarrier(
+          from, to, OFFSET_OF(UntaggedLinkedHashMap, deleted_keys_),
+          OFFSET_OF(UntaggedLinkedHashMap, deleted_keys_));
     }
     Base::ForwardCompressedPointer(from, to,
                                    OFFSET_OF(UntaggedLinkedHashBase, data_));
     Base::StoreCompressedPointersNoBarrier(
         from, to, OFFSET_OF(UntaggedLinkedHashBase, used_data_),
         OFFSET_OF(UntaggedLinkedHashBase, used_data_));
-    Base::StoreCompressedPointersNoBarrier(
-        from, to, OFFSET_OF(UntaggedLinkedHashMap, deleted_keys_),
-        OFFSET_OF(UntaggedLinkedHashMap, deleted_keys_));
   }
 
   void CopyLinkedHashMap(typename Types::LinkedHashMap from,
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index 14fbf46..f9b905b 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -372,6 +372,7 @@
     _hashMask = _HashBase._indexSizeToHashMask(_index.length);
     final int tmpUsed = _usedData;
     _usedData = 0;
+    _deletedKeys = 0;
     for (int i = 0; i < tmpUsed; i += 2) {
       final key = _data[i];
       if (!_HashBase._isDeleted(_data, key)) {
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index d439fd4..438e967 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -563,9 +563,9 @@
   /// This operation is potentially dangerous and should be used judiciously.
   /// The isolate stops operating *immediately*. It throws if the optional
   /// [message] does not adhere to the limitations on what can be sent from one
-  /// isolate to another. It also throws if a [finalMessagePort] is associated
-  /// with an isolate spawned outside of current isolate group, spawned via
-  /// [spawnUri].
+  /// isolate to another (see [SendPort.send] for more details). It also throws
+  /// if a [finalMessagePort] is associated with an isolate spawned outside of
+  /// current isolate group, spawned via [spawnUri].
   ///
   /// If successful, a call to this method does not return. Pending `finally`
   /// blocks are not executed, control flow will not go back to the event loop,
@@ -575,9 +575,9 @@
   /// code will run in the isolate.)
   ///
   /// If [finalMessagePort] is provided, and the [message] can be sent through
-  /// it, then the message is sent through that port as the final operation of
-  /// the current isolate. The isolate terminates immediately after
-  /// that [SendPort.send] call returns.
+  /// it (see [SendPort.send] for more details), then the message is sent
+  /// through that port as the final operation of the current isolate. The
+  /// isolate terminates immediately after that [SendPort.send] call returns.
   ///
   /// If the port is a native port -- one provided by [ReceivePort.sendPort] or
   /// [RawReceivePort.sendPort] -- the system may be able to send this final
@@ -599,9 +599,10 @@
 /// when sent.
 abstract class SendPort implements Capability {
   /// Sends an asynchronous [message] through this send port, to its
-  /// corresponding `ReceivePort`.
+  /// corresponding [ReceivePort].
   ///
-  /// The content of [message] can be:
+  /// The transitive object graph of [message] can contain the following
+  /// objects:
   ///   - [Null]
   ///   - [bool]
   ///   - [int]
@@ -612,14 +613,34 @@
   ///   - [SendPort]
   ///   - [Capability]
   ///
-  /// In the special circumstances when two isolates share the same code and are
-  /// running in the same process (e.g. isolates created via [Isolate.spawn]),
-  /// it is also possible to send object instances (which would be copied in the
-  /// process).
+  /// If the sender and receiver isolate share the same code (e.g. isolates
+  /// created via [Isolate.spawn]), the transitive object graph of [message] can
+  /// contain any object, with the following exceptions:
   ///
-  /// The send happens immediately and doesn't block.  The corresponding receive
+  ///   - Objects with native resources (subclasses of e.g.
+  ///     `NativeFieldWrapperClass1`). A [Socket] object for example referrs
+  ///     internally to objects that have native resources attached and can
+  ///     therefore not be sent.
+  ///   - [ReceivePort]
+  ///   - [DynamicLibrary]
+  ///   - [Pointer]
+  ///   - [UserTag]
+  ///   - `MirrorReference`
+  ///
+  /// Apart from those exceptions any object can be sent. Objects that are
+  /// identified as immutable (e.g. strings) will be shared whereas all other
+  /// objects will be copied.
+  ///
+  /// The send happens immediately and may have a linear time cost to copy the
+  /// transtive object graph. The send itself doesn't block (i.e. doesn't wait
+  /// until the receiver has received the message). The corresponding receive
   /// port can receive the message as soon as its isolate's event loop is ready
   /// to deliver it, independently of what the sending isolate is doing.
+  ///
+  /// Note: Due to an implementation choice the Dart VM made for how closures
+  /// represent captured state, closures can currently capture more state than
+  /// they need, which can cause the transitive closure to be larger than
+  /// needed. Open bug to address this: http://dartbug.com/36983
   void send(Object? message);
 
   /// Tests whether [other] is a [SendPort] pointing to the same
diff --git a/tools/VERSION b/tools/VERSION
index d18afdd..53fe3f8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 15
 PATCH 0
 PRERELEASE 268
-PRERELEASE_PATCH 1
\ No newline at end of file
+PRERELEASE_PATCH 8
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 2facefd5..a960fa8 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -312,9 +312,11 @@
       "xcodebuild/DebugX64/",
       "xcodebuild/DebugX64C/",
       "xcodebuild/DebugXARM64/",
+      "xcodebuild/DebugARM64/",
       "xcodebuild/ProductX64/",
       "xcodebuild/ProductX64C/",
       "xcodebuild/ProductXARM64/",
+      "xcodebuild/ProductARM64/",
       "xcodebuild/ReleaseIA32/",
       "xcodebuild/ReleaseSIMARM/",
       "xcodebuild/ReleaseSIMARM64/",
@@ -322,6 +324,7 @@
       "xcodebuild/ReleaseX64/",
       "xcodebuild/ReleaseX64C/",
       "xcodebuild/ReleaseXARM64/",
+      "xcodebuild/ReleaseARM64/",
       "pkg/",
       "samples/",
       "samples_2/",