Version 2.14.0-305.0.dev

Merge commit 'd5a97be46681feb703031587bfc35945d9d36744' into 'dev'
diff --git a/pkg/front_end/testcases/general/async_nested.dart.weak.transformed.expect b/pkg/front_end/testcases/general/async_nested.dart.weak.transformed.expect
index 45a2ff8..758329d 100644
--- a/pkg/front_end/testcases/general/async_nested.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/async_nested.dart.weak.transformed.expect
@@ -36,9 +36,9 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
-  dynamic :async_temporary_2;
+  self::Node* :async_temporary_0;
+  self::Node* :async_temporary_1;
+  self::Node* :async_temporary_2;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L1:
diff --git a/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect b/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect
index cb5a62a..c35babf 100644
--- a/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/await_complex.dart.weak.transformed.expect
@@ -65,12 +65,12 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
-  dynamic :async_temporary_2;
-  dynamic :async_temporary_3;
-  dynamic :async_temporary_4;
-  dynamic :async_temporary_5;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::int* :async_temporary_3;
+  core::int* :async_temporary_4;
+  core::int* :async_temporary_5;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L1:
@@ -121,11 +121,11 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
-  dynamic :async_temporary_2;
-  dynamic :async_temporary_3;
-  dynamic :async_temporary_4;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::int* :async_temporary_3;
+  core::int* :async_temporary_4;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L2:
@@ -172,11 +172,11 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
-  dynamic :async_temporary_2;
-  dynamic :async_temporary_3;
-  dynamic :async_temporary_4;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::int* :async_temporary_3;
+  core::int* :async_temporary_4;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L3:
@@ -225,10 +225,10 @@
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
-  dynamic :async_temporary_2;
-  dynamic :async_temporary_3;
-  dynamic :async_temporary_4;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::List<core::int*>* :async_temporary_3;
+  core::int* :async_temporary_4;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L4:
@@ -288,13 +288,13 @@
         core::bool* a = false;
         core::bool* b = true;
         :async_temporary_0 = (a || b) =={core::Object::==}{(core::Object) → core::bool} true;
-        if(:async_temporary_0)
+        if(_in::unsafeCast<core::bool*>(:async_temporary_0))
           ;
         else {
           [yield] let dynamic #t22 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
           :async_temporary_0 = :result as{TypeError,ForDynamic} core::bool* =={core::Object::==}{(core::Object) → core::bool} true;
         }
-        core::bool* c = :async_temporary_0;
+        core::bool* c = _in::unsafeCast<core::bool*>(:async_temporary_0);
         self::expect(true, c);
         if(a || b) {
           :async_temporary_1 = a;
@@ -426,8 +426,8 @@
   dynamic :saved_try_context_var3;
   dynamic :exception0;
   dynamic :stack_trace0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
+  core::List<dynamic>* :async_temporary_0;
+  core::List<dynamic>* :async_temporary_1;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L7:
diff --git a/pkg/front_end/testcases/general/bug33206.dart.weak.transformed.expect b/pkg/front_end/testcases/general/bug33206.dart.weak.transformed.expect
index 7178e45..85541c5 100644
--- a/pkg/front_end/testcases/general/bug33206.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/bug33206.dart.weak.transformed.expect
@@ -105,7 +105,7 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
+  self::Y* :async_temporary_0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L3:
diff --git a/pkg/front_end/testcases/general/issue40662.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue40662.dart.weak.transformed.expect
index b5dfa01..79b6c00 100644
--- a/pkg/front_end/testcases/general/issue40662.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/issue40662.dart.weak.transformed.expect
@@ -17,10 +17,10 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
   core::List<core::int*>* :async_temporary_2;
-  dynamic :async_temporary_3;
+  core::int* :async_temporary_3;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L1:
@@ -35,7 +35,7 @@
         else {
           :async_temporary_2 = null;
         }
-        :return_value = self::bar(_in::unsafeCast<core::int*>(:async_temporary_3), :async_temporary_2);
+        :return_value = self::bar(_in::unsafeCast<core::int*>(:async_temporary_3), _in::unsafeCast<core::List<core::int*>*>(:async_temporary_2));
         break #L1;
       }
       asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
@@ -88,4 +88,4 @@
 Extra constant evaluation status:
 Evaluated: InstanceInvocation @ org-dartlang-testcase:///issue40662.dart:8:10 -> IntConstant(-1)
 Evaluated: InstanceInvocation @ org-dartlang-testcase:///issue40662.dart:9:10 -> IntConstant(-1)
-Extra constant evaluation: evaluated: 93, effectively constant: 2
+Extra constant evaluation: evaluated: 94, effectively constant: 2
diff --git a/pkg/front_end/testcases/general/regression_flutter51828.dart.weak.transformed.expect b/pkg/front_end/testcases/general/regression_flutter51828.dart.weak.transformed.expect
index 23aa402..3d879b8 100644
--- a/pkg/front_end/testcases/general/regression_flutter51828.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/regression_flutter51828.dart.weak.transformed.expect
@@ -91,7 +91,7 @@
   core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
+  self::B* :async_temporary_0;
   dynamic :async_temporary_1;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_then_conditional.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional.dart.weak.transformed.expect
index 6efd0ab..2c0fd45 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional.dart.weak.transformed.expect
@@ -56,7 +56,7 @@
             [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
             :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_2.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_2.dart.weak.transformed.expect
index 29a38cc..ada0903 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_2.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_2.dart.weak.transformed.expect
@@ -56,7 +56,7 @@
             [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
             :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_3.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_3.dart.weak.transformed.expect
index 9ac9e7e..057adde 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_3.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_3.dart.weak.transformed.expect
@@ -56,7 +56,7 @@
             [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
             :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_4.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_4.dart.weak.transformed.expect
index 768aaeb..fd4b819 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_4.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_4.dart.weak.transformed.expect
@@ -56,7 +56,7 @@
             [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
             :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_5.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_5.dart.weak.transformed.expect
index 6fc6957..6e05707 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_5.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_5.dart.weak.transformed.expect
@@ -56,7 +56,7 @@
             [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
             :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_6.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_6.dart.weak.transformed.expect
index 4bf5a96..1968cbf 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_6.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_6.dart.weak.transformed.expect
@@ -56,7 +56,7 @@
             [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
             :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/front_end/testcases/inference/future_then_ifNull.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/future_then_ifNull.dart.weak.transformed.expect
index d6e68fc..077bfa1 100644
--- a/pkg/front_end/testcases/inference/future_then_ifNull.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_ifNull.dart.weak.transformed.expect
@@ -57,7 +57,7 @@
           else {
             :async_temporary_0 = #t1;
           }
-          :return_value = :async_temporary_0;
+          :return_value = _in::unsafeCast<core::int*>(:async_temporary_0);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index b18d98f..43fca30 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -115,21 +115,40 @@
     return result;
   }
 
+  // Wraps VariableGet in an unsafeCast if `type` isn't dynamic.
+  Expression unsafeCastVariableGet(
+      VariableDeclaration variable, DartType type) {
+    if (type != const DynamicType()) {
+      return StaticInvocation(
+          continuationRewriter.helper.unsafeCast,
+          Arguments(<Expression>[VariableGet(variable)],
+              types: <DartType>[type]));
+    }
+    return VariableGet(variable);
+  }
+
   // Name an expression by emitting an assignment to a temporary variable.
   Expression name(Expression expr) {
-    // Allocate as dynamic as temps might be reused with different types.
-    VariableDeclaration temp =
-        allocateTemporary(nameIndex, const DynamicType());
-    statements.add(ExpressionStatement(VariableSet(temp, expr)));
-    // Type annotate the get via an unsafe cast since all temps are allocated
-    // as dynamic.
     DartType type = expr.getStaticType(_staticTypeContext);
-    return StaticInvocation(continuationRewriter.helper.unsafeCast,
-        Arguments(<Expression>[VariableGet(temp)], types: <DartType>[type]));
+    VariableDeclaration temp = allocateTemporary(nameIndex, type);
+    statements.add(ExpressionStatement(VariableSet(temp, expr)));
+    // Wrap in unsafeCast to make sure we pass type information even if we later
+    // have to re-type the temporary variable to dynamic.
+    return unsafeCastVariableGet(temp, type);
   }
 
   VariableDeclaration allocateTemporary(int index,
       [DartType type = const DynamicType()]) {
+    if (variables.length > index) {
+      // Re-type temporary to dynamic if we detect reuse with different type.
+      // Note: We should make sure all uses use `unsafeCast(...)` to pass their
+      // type information on, as that is lost otherwise.
+      if (variables[index].type != const DynamicType() &&
+          variables[index].type != type) {
+        variables[index].type = const DynamicType();
+      }
+      return variables[index];
+    }
     for (var i = variables.length; i <= index; i++) {
       variables.add(VariableDeclaration(":async_temporary_${i}", type: type));
     }
@@ -384,10 +403,9 @@
     // so any statements it emits occur after in the accumulated list (that is,
     // so they occur before in the corresponding block).
     var rightBody = blockOf(rightStatements);
-    var result = allocateTemporary(
-        nameIndex,
-        _staticTypeContext.typeEnvironment.coreTypes
-            .boolRawType(_staticTypeContext.nonNullable));
+    final type = _staticTypeContext.typeEnvironment.coreTypes
+        .boolRawType(_staticTypeContext.nonNullable);
+    final result = allocateTemporary(nameIndex, type);
     final objectEquals = continuationRewriter.helper.coreTypes.objectEquals;
     rightBody.addStatement(new ExpressionStatement(new VariableSet(
         result,
@@ -402,7 +420,8 @@
       then = new EmptyStatement();
       otherwise = rightBody;
     }
-    statements.add(new IfStatement(new VariableGet(result), then, otherwise));
+    statements.add(
+        new IfStatement(unsafeCastVariableGet(result, type), then, otherwise));
 
     final test = new EqualsCall(expr.left, new BoolLiteral(true),
         interfaceTarget: objectEquals,
@@ -414,7 +433,7 @@
 
     ++nameIndex;
     seenAwait = seenAwait || rightAwait;
-    return new VariableGet(result);
+    return unsafeCastVariableGet(result, type);
   }
 
   TreeNode visitConditionalExpression(ConditionalExpression expr) {
@@ -455,15 +474,15 @@
       });
     }
 
-    // If then or otherwise has emitted statements we will produce a temporary t
-    // and emit:
+    // If `then` or `otherwise` has emitted statements we will produce a
+    // temporary t and emit:
     //
     // if ([condition]) {
     //   t = [left];
     // } else {
     //   t = [right];
     // }
-    var result = allocateTemporary(nameIndex, expr.staticType);
+    final result = allocateTemporary(nameIndex, expr.staticType);
     var thenBody = blockOf(thenStatements);
     var otherwiseBody = blockOf(otherwiseStatements);
     thenBody.addStatement(
@@ -478,7 +497,7 @@
 
     ++nameIndex;
     seenAwait = seenAwait || thenAwait || otherwiseAwait;
-    return new VariableGet(result);
+    return unsafeCastVariableGet(result, expr.staticType);
   }
 
   // Others.
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/async_await.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/async_await.dart.expect
index d1f3c4e..6e5364a 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/async_await.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/async_await.dart.expect
@@ -2,7 +2,6 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
-import "dart:_internal" as _in;
 
 class A extends core::Object {
   synthetic constructor •() → self::A*
@@ -86,7 +85,7 @@
       {
         :async_temporary_0 = [@vm.inferred-type.metadata=#lib::A] self::foo();
         [yield] let dynamic #t1 = asy::_awaitHelper([@vm.inferred-type.metadata=dart.async::_Future<dynamic>] self::baz(), :async_op_then, :async_op_error, :async_op) in null;
-        [yield] let dynamic #t2 = asy::_awaitHelper([@vm.direct-call.metadata=#lib::A.bar??] [@vm.inferred-type.metadata=dart.async::_Future<dynamic> (receiver not int)] _in::unsafeCast<dynamic>(:async_temporary_0){dynamic}.bar(:result), :async_op_then, :async_op_error, :async_op) in null;
+        [yield] let dynamic #t2 = asy::_awaitHelper([@vm.direct-call.metadata=#lib::A.bar??] [@vm.inferred-type.metadata=dart.async::_Future<dynamic> (receiver not int)] :async_temporary_0{dynamic}.bar(:result), :async_op_then, :async_op_error, :async_op) in null;
         :result;
       }
       asy::_completeOnAsyncReturn(:async_future, :return_value, :is_sync);
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index d296cc7cb..c0ad639 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -239,33 +239,35 @@
 #if defined(DEBUG)
   // Basic checking.
   cls = object_store->object_class();
-  ASSERT(Instance::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Instance::InstanceSize(), cls.host_instance_size());
   cls = object_store->integer_implementation_class();
-  ASSERT(Integer::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Integer::InstanceSize(), cls.host_instance_size());
   cls = object_store->smi_class();
-  ASSERT(Smi::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Smi::InstanceSize(), cls.host_instance_size());
   cls = object_store->mint_class();
-  ASSERT(Mint::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Mint::InstanceSize(), cls.host_instance_size());
   cls = object_store->one_byte_string_class();
-  ASSERT(OneByteString::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(OneByteString::InstanceSize(), cls.host_instance_size());
   cls = object_store->two_byte_string_class();
-  ASSERT(TwoByteString::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(TwoByteString::InstanceSize(), cls.host_instance_size());
   cls = object_store->external_one_byte_string_class();
-  ASSERT(ExternalOneByteString::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(ExternalOneByteString::InstanceSize(), cls.host_instance_size());
   cls = object_store->external_two_byte_string_class();
-  ASSERT(ExternalTwoByteString::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(ExternalTwoByteString::InstanceSize(), cls.host_instance_size());
   cls = object_store->double_class();
-  ASSERT(Double::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Double::InstanceSize(), cls.host_instance_size());
   cls = object_store->bool_class();
-  ASSERT(Bool::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Bool::InstanceSize(), cls.host_instance_size());
   cls = object_store->array_class();
-  ASSERT(Array::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(Array::InstanceSize(), cls.host_instance_size());
   cls = object_store->immutable_array_class();
-  ASSERT(ImmutableArray::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(ImmutableArray::InstanceSize(), cls.host_instance_size());
   cls = object_store->weak_property_class();
-  ASSERT(WeakProperty::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(WeakProperty::InstanceSize(), cls.host_instance_size());
   cls = object_store->linked_hash_map_class();
-  ASSERT(LinkedHashMap::InstanceSize() == cls.host_instance_size());
+  ASSERT_EQUAL(LinkedHashMap::InstanceSize(), cls.host_instance_size());
+  cls = object_store->linked_hash_set_class();
+  ASSERT_EQUAL(LinkedHashMap::InstanceSize(), cls.host_instance_size());
 #endif  // defined(DEBUG)
 
   // Remember the currently pending classes.
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 2fbc03f..5a41a68 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -17,7 +17,7 @@
 // Size of the class-id part of the object header. See UntaggedObject.
 typedef uint16_t ClassIdTagType;
 
-#define CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                           \
+#define CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(V)                   \
   V(Class)                                                                     \
   V(PatchClass)                                                                \
   V(Function)                                                                  \
@@ -88,11 +88,16 @@
   V(RegExp)                                                                    \
   V(WeakProperty)                                                              \
   V(MirrorReference)                                                           \
-  V(LinkedHashMap)                                                             \
   V(FutureOr)                                                                  \
   V(UserTag)                                                                   \
   V(TransferableTypedData)
 
+// TODO(http://dartbug.com/45908): Add ImmutableLinkedHashMap.
+#define CLASS_LIST_MAPS(V) V(LinkedHashMap)
+
+// TODO(http://dartbug.com/45908): Add ImmutableLinkedHashSet.
+#define CLASS_LIST_SETS(V) V(LinkedHashSet)
+
 #define CLASS_LIST_ARRAYS(V)                                                   \
   V(Array)                                                                     \
   V(ImmutableArray)
@@ -163,12 +168,16 @@
   V(Float64x2)
 
 #define CLASS_LIST_FOR_HANDLES(V)                                              \
-  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                                 \
+  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(V)                         \
+  V(LinkedHashMap)                                                             \
+  V(LinkedHashSet)                                                             \
   V(Array)                                                                     \
   V(String)
 
 #define CLASS_LIST_NO_OBJECT(V)                                                \
-  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                                 \
+  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(V)                         \
+  CLASS_LIST_MAPS(V)                                                           \
+  CLASS_LIST_SETS(V)                                                           \
   CLASS_LIST_ARRAYS(V)                                                         \
   CLASS_LIST_STRINGS(V)
 
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 55d5b84..d47ec82 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -6473,7 +6473,11 @@
     case kWeakPropertyCid:
       return new (Z) WeakPropertySerializationCluster();
     case kLinkedHashMapCid:
-      return new (Z) LinkedHashMapSerializationCluster();
+      // We do not have mutable hash maps in snapshots.
+      UNREACHABLE();
+    case kLinkedHashSetCid:
+      // We do not have mutable hash sets in snapshots.
+      UNREACHABLE();
     case kArrayCid:
       return new (Z) ArraySerializationCluster(is_canonical, kArrayCid);
     case kImmutableArrayCid:
@@ -7380,7 +7384,11 @@
       ASSERT(!is_canonical);
       return new (Z) WeakPropertyDeserializationCluster();
     case kLinkedHashMapCid:
-      return new (Z) LinkedHashMapDeserializationCluster(is_canonical);
+      // We do not have mutable hash maps in snapshots.
+      UNREACHABLE();
+    case kLinkedHashSetCid:
+      // We do not have mutable hash sets in snapshots.
+      UNREACHABLE();
     case kArrayCid:
       return new (Z) ArrayDeserializationCluster(is_canonical, kArrayCid);
     case kImmutableArrayCid:
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 9dab2b8..d80cb7453 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -440,7 +440,7 @@
 
   V8SnapshotProfileWriter* profile_writer() const { return profile_writer_; }
 
-  // If the given [obj] was not included into the snaposhot and have not
+  // If the given [obj] was not included into the snapshot and have not
   // yet gotten an artificial node created for it create an artificial node
   // in the profile representing this object.
   // Returns true if [obj] has an artificial profile node associated with it.
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index c289e46..f711e69 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -410,6 +410,8 @@
       return TypedDataBase::InstanceSize();
     case kLinkedHashMapCid:
       return LinkedHashMap::InstanceSize();
+    case kLinkedHashSetCid:
+      return LinkedHashSet::InstanceSize();
     case kUnhandledExceptionCid:
       return UnhandledException::InstanceSize();
     case kWeakPropertyCid:
@@ -960,243 +962,19 @@
   return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
 }
 
-word Pointer::NextFieldOffset() {
-  return TranslateOffsetInWords(dart::Pointer::NextFieldOffset());
-}
-
-word WeakSerializationReference::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ObjectPool::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Class::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Function::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ICData::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word MegamorphicCache::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word SingleTargetCache::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Array::NextFieldOffset() {
-  return -kWordSize;
-}
-
 intptr_t Array::index_at_offset(intptr_t offset_in_bytes) {
   return dart::Array::index_at_offset(
       TranslateOffsetInWordsToHost(offset_in_bytes));
 }
 
-word GrowableObjectArray::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypedDataBase::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypedData::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ExternalTypedData::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypedDataView::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word LinkedHashMap::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word AbstractType::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Type::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word FunctionType::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypeRef::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Double::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Mint::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word String::NextFieldOffset() {
-  return -kWordSize;
-}
-
 word String::InstanceSize(word payload_size) {
   return RoundedAllocationSize(String::InstanceSize() + payload_size);
 }
 
-word OneByteString::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TwoByteString::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ExternalOneByteString::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ExternalTwoByteString::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Int32x4::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Float32x4::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Float64x2::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word DynamicLibrary::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word PatchClass::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word FfiTrampolineData::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Script::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Library::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Namespace::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word KernelProgramInfo::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word PcDescriptors::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word CodeSourceMap::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word CompressedStackMaps::NextFieldOffset() {
-  return -kWordSize;
-}
-
 word LocalVarDescriptors::InstanceSize() {
   return 0;
 }
 
-word LocalVarDescriptors::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ExceptionHandlers::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ContextScope::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Sentinel::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word UnlinkedCall::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ApiError::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word LanguageError::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word UnhandledException::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word UnwindError::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Bool::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypeParameter::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word LibraryPrefix::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Capability::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ReceivePort::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word SendPort::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TransferableTypedData::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word StackTrace::NextFieldOffset() {
-  return -kWordSize;
-}
-
 word Integer::NextFieldOffset() {
   return TranslateOffsetInWords(dart::Integer::NextFieldOffset());
 }
@@ -1205,94 +983,10 @@
   return 0;
 }
 
-word Smi::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word WeakProperty::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word MirrorReference::NextFieldOffset() {
-  return -kWordSize;
-}
-
 word Number::NextFieldOffset() {
   return TranslateOffsetInWords(dart::Number::NextFieldOffset());
 }
 
-word MonomorphicSmiableCall::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word InstructionsSection::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word InstructionsTable::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Instructions::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Code::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word SubtypeTestCache::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word LoadingUnit::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Context::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Closure::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ClosureData::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word RegExp::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word UserTag::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word FutureOr::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word Field::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypeParameters::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word TypeArguments::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word FreeListElement::FakeInstance::NextFieldOffset() {
-  return -kWordSize;
-}
-
-word ForwardingCorpse::FakeInstance::NextFieldOffset() {
-  return -kWordSize;
-}
-
 }  // namespace target
 }  // namespace compiler
 }  // namespace dart
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index fb22d3b..96342d7 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -419,6 +419,9 @@
 
 bool WillAllocateNewOrRememberedArray(intptr_t length);
 
+#define FINAL_CLASS()                                                          \
+  static word NextFieldOffset() { return -kWordSize; }
+
 //
 // Target specific offsets and constants.
 //
@@ -461,7 +464,7 @@
   static word element_offset(intptr_t index);
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Class : public AllStatic {
@@ -480,7 +483,7 @@
 
   static word InstanceSize();
 
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
   // Return class id of the given class on the target.
   static classid_t GetId(const dart::Class& handle);
@@ -526,7 +529,7 @@
   static word signature_offset();
   static word usage_counter_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class CallSiteData : public AllStatic {
@@ -550,7 +553,7 @@
   static word NumArgsTestedShift();
   static word NumArgsTestedMask();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class MegamorphicCache : public AllStatic {
@@ -559,7 +562,7 @@
   static word mask_offset();
   static word buckets_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class SingleTargetCache : public AllStatic {
@@ -569,7 +572,7 @@
   static word entry_point_offset();
   static word target_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Array : public AllStatic {
@@ -583,7 +586,7 @@
   static intptr_t index_at_offset(intptr_t offset_in_bytes);
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
   static const word kMaxElements;
   static const word kMaxNewSpaceElements;
@@ -595,7 +598,7 @@
   static word type_arguments_offset();
   static word length_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class PointerBase : public AllStatic {
@@ -607,7 +610,7 @@
  public:
   static word length_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TypedData : public AllStatic {
@@ -616,14 +619,14 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(word lengthInBytes);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ExternalTypedData : public AllStatic {
  public:
   static word data_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TypedDataView : public AllStatic {
@@ -631,7 +634,7 @@
   static word offset_in_bytes_offset();
   static word data_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class LinkedHashBase : public AllStatic {
@@ -647,14 +650,19 @@
 
 class LinkedHashMap : public LinkedHashBase {
  public:
-  static word NextFieldOffset();
+  FINAL_CLASS();
+};
+
+class LinkedHashSet : public LinkedHashBase {
+ public:
+  FINAL_CLASS();
 };
 
 class FutureOr : public AllStatic {
  public:
   static word type_arguments_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ArgumentsDescriptor : public AllStatic {
@@ -678,14 +686,14 @@
  public:
   static word type_arguments_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class AbstractType : public AllStatic {
  public:
   static word type_test_stub_entry_point_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Type : public AllStatic {
@@ -696,7 +704,7 @@
   static word type_class_id_offset();
   static word nullability_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class FunctionType : public AllStatic {
@@ -710,14 +718,14 @@
   static word type_parameters_offset();
   static word nullability_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TypeRef : public AllStatic {
  public:
   static word type_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Nullability : public AllStatic {
@@ -731,14 +739,14 @@
  public:
   static word value_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Mint : public AllStatic {
  public:
   static word value_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class String : public AllStatic {
@@ -748,8 +756,8 @@
   static word hash_offset();
   static word length_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
   static word InstanceSize(word payload_size);
+  FINAL_CLASS();
 };
 
 class OneByteString : public AllStatic {
@@ -757,7 +765,7 @@
   static word data_offset();
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
  private:
   static word element_offset(intptr_t index);
@@ -768,7 +776,7 @@
   static word data_offset();
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
  private:
   static word element_offset(intptr_t index);
@@ -778,77 +786,77 @@
  public:
   static word external_data_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ExternalTwoByteString : public AllStatic {
  public:
   static word external_data_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Int32x4 : public AllStatic {
  public:
   static word value_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Float32x4 : public AllStatic {
  public:
   static word value_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Float64x2 : public AllStatic {
  public:
   static word value_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class DynamicLibrary : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class PatchClass : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class FfiTrampolineData : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Script : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Library : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Namespace : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class KernelProgramInfo : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class PcDescriptors : public AllStatic {
@@ -856,7 +864,7 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(word payload_size);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class CodeSourceMap : public AllStatic {
@@ -864,7 +872,7 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(word payload_size);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class CompressedStackMaps : public AllStatic {
@@ -872,13 +880,13 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(word payload_size);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class LocalVarDescriptors : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ExceptionHandlers : public AllStatic {
@@ -886,7 +894,7 @@
   static word element_offset(intptr_t index);
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ContextScope : public AllStatic {
@@ -894,31 +902,31 @@
   static word element_offset(intptr_t index);
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Sentinel : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class UnlinkedCall : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ApiError : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class LanguageError : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class UnhandledException : public AllStatic {
@@ -926,19 +934,19 @@
   static word exception_offset();
   static word stacktrace_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class UnwindError : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Bool : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TypeParameter : public AllStatic {
@@ -946,7 +954,7 @@
   static word bound_offset();
   static word flags_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
   static word parameterized_class_id_offset();
   static word index_offset();
   static word nullability_offset();
@@ -955,37 +963,37 @@
 class LibraryPrefix : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Capability : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ReceivePort : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class SendPort : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TransferableTypedData : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class StackTrace : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Integer : public AllStatic {
@@ -997,7 +1005,7 @@
 class Smi : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class WeakProperty : public AllStatic {
@@ -1005,13 +1013,13 @@
   static word key_offset();
   static word value_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class MirrorReference : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Number : public AllStatic {
@@ -1036,7 +1044,7 @@
   static word entrypoint_offset();
   static word target_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Thread : public AllStatic {
@@ -1222,7 +1230,7 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(word payload_size);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class InstructionsTable : public AllStatic {
@@ -1230,7 +1238,7 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(intptr_t length);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
  private:
   static word element_offset(intptr_t index);
@@ -1248,7 +1256,7 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(word payload_size);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Code : public AllStatic {
@@ -1264,7 +1272,7 @@
   static word HeaderSize();
   static word InstanceSize();
   static word InstanceSize(intptr_t length);
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
  private:
   static word element_offset(intptr_t index);
@@ -1273,7 +1281,7 @@
 class WeakSerializationReference : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class SubtypeTestCache : public AllStatic {
@@ -1290,13 +1298,13 @@
   static const word kInstanceDelayedFunctionTypeArguments;
   static const word kTestResult;
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class LoadingUnit : public AllStatic {
  public:
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Context : public AllStatic {
@@ -1307,7 +1315,7 @@
   static word variable_offset(intptr_t index);
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Closure : public AllStatic {
@@ -1320,14 +1328,14 @@
   static word instantiator_type_arguments_offset();
   static word hash_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class ClosureData : public AllStatic {
  public:
   static word default_type_arguments_kind_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class OldPage : public AllStatic {
@@ -1363,14 +1371,14 @@
  public:
   static word function_offset(classid_t cid, bool sticky);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class UserTag : public AllStatic {
  public:
   static word tag_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class Symbols : public AllStatic {
@@ -1391,7 +1399,7 @@
   static word initializer_function_offset();
   static word host_offset_or_field_id_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TypeParameters : public AllStatic {
@@ -1401,7 +1409,7 @@
   static word bounds_offset();
   static word defaults_offset();
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 };
 
 class TypeArguments : public AllStatic {
@@ -1413,7 +1421,7 @@
   static word types_offset();
   static word InstanceSize(intptr_t length);
   static word InstanceSize();
-  static word NextFieldOffset();
+  FINAL_CLASS();
 
   static const word kMaxElements;
 };
@@ -1423,7 +1431,7 @@
   class FakeInstance : public AllStatic {
    public:
     static word InstanceSize();
-    static word NextFieldOffset();
+    FINAL_CLASS();
   };
 };
 
@@ -1432,7 +1440,7 @@
   class FakeInstance : public AllStatic {
    public:
     static word InstanceSize();
-    static word NextFieldOffset();
+    FINAL_CLASS();
   };
 };
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 06dcf56..e3e73a8 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -606,7 +606,23 @@
     clazz fake_handle;                                                         \
     builtin_vtables_[k##clazz##Cid] = fake_handle.vtable();                    \
   }
-  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(INIT_VTABLE)
+  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(INIT_VTABLE)
+#undef INIT_VTABLE
+
+#define INIT_VTABLE(clazz)                                                     \
+  {                                                                            \
+    LinkedHashMap fake_handle;                                                 \
+    builtin_vtables_[k##clazz##Cid] = fake_handle.vtable();                    \
+  }
+  CLASS_LIST_MAPS(INIT_VTABLE)
+#undef INIT_VTABLE
+
+#define INIT_VTABLE(clazz)                                                     \
+  {                                                                            \
+    LinkedHashSet fake_handle;                                                 \
+    builtin_vtables_[k##clazz##Cid] = fake_handle.vtable();                    \
+  }
+  CLASS_LIST_SETS(INIT_VTABLE)
 #undef INIT_VTABLE
 
 #define INIT_VTABLE(clazz)                                                     \
@@ -1948,6 +1964,15 @@
     RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib);
     pending_classes.Add(cls);
 
+    cls = Class::New<LinkedHashSet, RTN::LinkedHashSet>(isolate_group);
+    object_store->set_linked_hash_set_class(cls);
+    cls.set_type_arguments_field_offset(
+        LinkedHashSet::type_arguments_offset(),
+        RTN::LinkedHashSet::type_arguments_offset());
+    cls.set_num_type_arguments_unsafe(1);
+    RegisterPrivateClass(cls, Symbols::_LinkedHashSet(), lib);
+    pending_classes.Add(cls);
+
     // Pre-register the async library so we can place the vm class
     // FutureOr there rather than the core library.
     lib = Library::LookupLibrary(thread, Symbols::DartAsync());
@@ -2414,6 +2439,9 @@
     cls = Class::New<LinkedHashMap, RTN::LinkedHashMap>(isolate_group);
     object_store->set_linked_hash_map_class(cls);
 
+    cls = Class::New<LinkedHashSet, RTN::LinkedHashSet>(isolate_group);
+    object_store->set_linked_hash_set_class(cls);
+
     cls = Class::New<Float32x4, RTN::Float32x4>(isolate_group);
     object_store->set_float32x4_class(cls);
 
@@ -24417,6 +24445,54 @@
   return zone->PrintToString("_LinkedHashMap len:%" Pd, Length());
 }
 
+LinkedHashSetPtr LinkedHashSet::New(const Array& data,
+                                    const TypedData& index,
+                                    intptr_t hash_mask,
+                                    intptr_t used_data,
+                                    intptr_t deleted_keys,
+                                    Heap::Space space) {
+  ASSERT(IsolateGroup::Current()->object_store()->linked_hash_map_class() !=
+         Class::null());
+  LinkedHashSet& result =
+      LinkedHashSet::Handle(LinkedHashSet::NewUninitialized(space));
+  result.SetData(data);
+  result.SetIndex(index);
+  result.SetHashMask(hash_mask);
+  result.SetUsedData(used_data);
+  result.SetDeletedKeys(deleted_keys);
+  return result.ptr();
+}
+
+LinkedHashSetPtr LinkedHashSet::NewDefault(Heap::Space space) {
+  const Array& data = Array::Handle(Array::New(kInitialIndexSize, space));
+  const TypedData& index = TypedData::Handle(
+      TypedData::New(kTypedDataUint32ArrayCid, kInitialIndexSize, space));
+  // On 32-bit, the top bits are wasted to avoid Mint allocation.
+  static const intptr_t kAvailableBits = (kSmiBits >= 32) ? 32 : kSmiBits;
+  static const intptr_t kInitialHashMask =
+      (1 << (kAvailableBits - kInitialIndexBits)) - 1;
+  return LinkedHashSet::New(data, index, kInitialHashMask, 0, 0, space);
+}
+
+LinkedHashSetPtr LinkedHashSet::NewUninitialized(Heap::Space space) {
+  ASSERT(IsolateGroup::Current()->object_store()->linked_hash_map_class() !=
+         Class::null());
+  LinkedHashSet& result = LinkedHashSet::Handle();
+  {
+    ObjectPtr raw =
+        Object::Allocate(kLinkedHashSetCid, LinkedHashSet::InstanceSize(),
+                         space, LinkedHashSet::ContainsCompressedPointers());
+    NoSafepointScope no_safepoint;
+    result ^= raw;
+  }
+  return result.ptr();
+}
+
+const char* LinkedHashSet::ToCString() const {
+  Zone* zone = Thread::Current()->zone();
+  return zone->PrintToString("LinkedHashSet len:%" Pd, Length());
+}
+
 const char* FutureOr::ToCString() const {
   // FutureOr is an abstract class.
   UNREACHABLE();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7cc8063..cd72a01 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -10874,8 +10874,6 @@
     return OFFSET_OF(UntaggedPointer, type_arguments_);
   }
 
-  static intptr_t NextFieldOffset() { return sizeof(UntaggedPointer); }
-
   static const intptr_t kNativeTypeArgPos = 0;
 
   // Fetches the NativeType type argument.
@@ -10885,7 +10883,7 @@
   }
 
  private:
-  HEAP_OBJECT_IMPLEMENTATION(Pointer, Instance);
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(Pointer, Instance);
 
   friend class Class;
 };
@@ -11072,6 +11070,113 @@
   friend class LinkedHashMapDeserializationCluster;
 };
 
+class LinkedHashSet : public LinkedHashBase {
+ public:
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(UntaggedLinkedHashSet));
+  }
+
+  // Allocates a set with some default capacity, just like "new Set()".
+  static LinkedHashSetPtr NewDefault(Heap::Space space = Heap::kNew);
+  static LinkedHashSetPtr New(const Array& data,
+                              const TypedData& index,
+                              intptr_t hash_mask,
+                              intptr_t used_data,
+                              intptr_t deleted_keys,
+                              Heap::Space space = Heap::kNew);
+
+  virtual TypeArgumentsPtr GetTypeArguments() const {
+    return untag()->type_arguments();
+  }
+  virtual void SetTypeArguments(const TypeArguments& value) const {
+    ASSERT(value.IsNull() ||
+           ((value.Length() >= 1) &&
+            value.IsInstantiated() /*&& value.IsCanonical()*/));
+    // TODO(asiva): Values read from a message snapshot are not properly marked
+    // as canonical. See for example tests/isolate/message3_test.dart.
+    untag()->set_type_arguments(value.ptr());
+  }
+
+  TypedDataPtr index() const { return untag()->index(); }
+  void SetIndex(const TypedData& value) const {
+    ASSERT(!value.IsNull());
+    untag()->set_index(value.ptr());
+  }
+
+  ArrayPtr data() const { return untag()->data(); }
+  void SetData(const Array& value) const { untag()->set_data(value.ptr()); }
+
+  SmiPtr hash_mask() const { return untag()->hash_mask(); }
+  void SetHashMask(intptr_t value) const {
+    untag()->set_hash_mask(Smi::New(value));
+  }
+
+  SmiPtr used_data() const { return untag()->used_data(); }
+  void SetUsedData(intptr_t value) const {
+    untag()->set_used_data(Smi::New(value));
+  }
+
+  SmiPtr deleted_keys() const { return untag()->deleted_keys(); }
+  void SetDeletedKeys(intptr_t value) const {
+    untag()->set_deleted_keys(Smi::New(value));
+  }
+
+  intptr_t Length() const {
+    // The map may be uninitialized.
+    if (untag()->used_data() == Object::null()) return 0;
+    if (untag()->deleted_keys() == Object::null()) return 0;
+
+    intptr_t used = Smi::Value(untag()->used_data());
+    intptr_t deleted = Smi::Value(untag()->deleted_keys());
+    return used - deleted;
+  }
+
+  // This iterator differs somewhat from its Dart counterpart (_CompactIterator
+  // in runtime/lib/compact_hash.dart):
+  //  - There are no checks for concurrent modifications.
+  //  - Accessing a key or value before the first call to MoveNext and after
+  //    MoveNext returns false will result in crashes.
+  class Iterator : ValueObject {
+   public:
+    explicit Iterator(const LinkedHashSet& set)
+        : data_(Array::Handle(set.data())),
+          scratch_(Object::Handle()),
+          offset_(-1),
+          length_(Smi::Value(set.used_data())) {}
+
+    bool MoveNext() {
+      while (true) {
+        offset_++;
+        if (offset_ >= length_) {
+          return false;
+        }
+        scratch_ = data_.At(offset_);
+        if (scratch_.ptr() != data_.ptr()) {
+          // Slot is not deleted (self-reference indicates deletion).
+          return true;
+        }
+      }
+    }
+
+    ObjectPtr CurrentKey() const { return data_.At(offset_); }
+
+   private:
+    const Array& data_;
+    Object& scratch_;
+    intptr_t offset_;
+    const intptr_t length_;
+  };
+
+ private:
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(LinkedHashSet, LinkedHashBase);
+
+  // Allocate a set, but leave all fields set to null.
+  // Used during deserialization (since set might contain itself as key/value).
+  static LinkedHashSetPtr NewUninitialized(Heap::Space space = Heap::kNew);
+
+  friend class Class;
+};
+
 class Closure : public Instance {
  public:
 #if defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 1bd42fa..d924ea2 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -944,6 +944,10 @@
       writer_->WriteUnsigned(kLengthData);
       writer_->WriteUnsigned(
           Smi::Value(static_cast<LinkedHashMapPtr>(obj)->untag()->used_data()));
+    } else if (cid == kLinkedHashSetCid) {
+      writer_->WriteUnsigned(kLengthData);
+      writer_->WriteUnsigned(
+          Smi::Value(static_cast<LinkedHashSetPtr>(obj)->untag()->used_data()));
     } else if (cid == kObjectPoolCid) {
       writer_->WriteUnsigned(kLengthData);
       writer_->WriteUnsigned(static_cast<ObjectPoolPtr>(obj)->untag()->length_);
@@ -1308,6 +1312,7 @@
     case kInstructionsSectionCid:
     case kInstructionsTableCid:
     case kLinkedHashMapCid:
+    case kLinkedHashSetCid:
     case kMintCid:
     case kNeverCid:
     case kSentinelCid:
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 2fa6cda..95358c6 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -1390,6 +1390,41 @@
   }
 }
 
+void LinkedHashSet::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "PlainInstance");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  intptr_t limit = offset + count;
+  ASSERT(limit <= Length());
+  {
+    JSONArray jsarr(&jsobj, "elements");
+    Object& object = Object::Handle();
+    LinkedHashSet::Iterator iterator(*this);
+    int i = 0;
+    while (iterator.MoveNext() && i < limit) {
+      if (i >= offset) {
+        object = iterator.CurrentKey();
+        jsarr.AddValue(object);
+      }
+      i++;
+    }
+  }
+}
+
 void Float32x4::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
   PrintSharedInstanceJSON(&jsobj, ref);
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 7e5c738..2553f7c 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4965,6 +4965,41 @@
   EXPECT(!iterator.MoveNext());
 }
 
+TEST_CASE(LinkedHashSet_iteration) {
+  const char* kScript =
+      "makeSet() {\n"
+      "  var set = {'x', 'y', 'z', 'w'};\n"
+      "  set.remove('y');\n"
+      "  set.remove('w');\n"
+      "  return set;\n"
+      "}";
+  Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(h_lib);
+  Dart_Handle h_result = Dart_Invoke(h_lib, NewString("makeSet"), 0, NULL);
+  EXPECT_VALID(h_result);
+
+  TransitionNativeToVM transition(thread);
+  Instance& dart_set = Instance::Handle();
+  dart_set ^= Api::UnwrapHandle(h_result);
+  ASSERT(dart_set.IsLinkedHashSet());
+  const LinkedHashSet& cc_set = LinkedHashSet::Cast(dart_set);
+
+  EXPECT_EQ(2, cc_set.Length());
+
+  LinkedHashSet::Iterator iterator(cc_set);
+  Object& object = Object::Handle();
+
+  EXPECT(iterator.MoveNext());
+  object = iterator.CurrentKey();
+  EXPECT_STREQ("x", object.ToCString());
+
+  EXPECT(iterator.MoveNext());
+  object = iterator.CurrentKey();
+  EXPECT_STREQ("z", object.ToCString());
+
+  EXPECT(!iterator.MoveNext());
+}
+
 static void CheckConcatAll(const String* data[], intptr_t n) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index d7a1beb..b79c6b9 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -562,6 +562,7 @@
 COMPRESSED_VISITOR(ExternalTwoByteString)
 COMPRESSED_VISITOR(GrowableObjectArray)
 COMPRESSED_VISITOR(LinkedHashMap)
+COMPRESSED_VISITOR(LinkedHashSet)
 COMPRESSED_VISITOR(ExternalTypedData)
 TYPED_DATA_VIEW_VISITOR(TypedDataView)
 COMPRESSED_VISITOR(ReceivePort)
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 4d0bfbb..f16ef82 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -3006,6 +3006,12 @@
   friend class SnapshotReader;
 };
 
+class UntaggedLinkedHashSet : public UntaggedLinkedHashBase {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(LinkedHashSet);
+
+  friend class SnapshotReader;
+};
+
 class UntaggedFloat32x4 : public UntaggedInstance {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Float32x4);
   VISIT_NOTHING();
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 7e6df08..82f51c6 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1157,38 +1157,8 @@
   map = LinkedHashMap::NewUninitialized();
   reader->AddBackRef(object_id, &map, kIsDeserialized);
 
-  // Read the type arguments.
-  *reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
-  map.SetTypeArguments(*reader->TypeArgumentsHandle());
+  reader->MapReadFrom(object_id, map, tags);
 
-  // Read the number of key/value pairs.
-  intptr_t len = reader->ReadSmiValue();
-  intptr_t used_data = (len << 1);
-  map.SetUsedData(used_data);
-
-  // Allocate the data array.
-  intptr_t data_size =
-      Utils::Maximum(Utils::RoundUpToPowerOfTwo(used_data),
-                     static_cast<uintptr_t>(LinkedHashMap::kInitialIndexSize));
-  Array& data = Array::ZoneHandle(reader->zone(), Array::New(data_size));
-  map.SetData(data);
-  map.SetDeletedKeys(0);
-
-  // The index and hashMask is regenerated by the maps themselves on demand.
-  // Thus, the index will probably be allocated in new space (unless it's huge).
-  // TODO(koda): Eagerly rehash here when no keys have user-defined '==', and
-  // in particular, if/when (const) maps are needed in the VM isolate snapshot.
-  ASSERT(reader->isolate_group() != Dart::vm_isolate_group());
-  map.SetHashMask(0);  // Prefer sentinel 0 over null for better type feedback.
-
-  reader->EnqueueRehashingOfMap(map);
-
-  // Read the keys and values.
-  bool read_as_reference = UntaggedObject::IsCanonical(tags) ? false : true;
-  for (intptr_t i = 0; i < used_data; i++) {
-    *reader->PassiveObjectHandle() = reader->ReadObjectImpl(read_as_reference);
-    data.SetAt(i, *reader->PassiveObjectHandle());
-  }
   return map.ptr();
 }
 
@@ -1197,44 +1167,39 @@
                                     Snapshot::Kind kind,
                                     bool as_reference) {
   ASSERT(writer != NULL);
+  ASSERT(!this->IsCanonical());
+  writer->MapWriteTo(object_id, kLinkedHashMapCid, writer->GetObjectTags(this),
+                     type_arguments(), used_data(), deleted_keys(), data(),
+                     as_reference);
+}
 
-  // Write out the serialization header value for this object.
-  writer->WriteInlinedObjectHeader(object_id);
+LinkedHashSetPtr LinkedHashSet::ReadFrom(SnapshotReader* reader,
+                                         intptr_t object_id,
+                                         intptr_t tags,
+                                         Snapshot::Kind kind,
+                                         bool as_reference) {
+  ASSERT(reader != NULL);
 
-  // Write out the class and tags information.
-  writer->WriteIndexedObject(kLinkedHashMapCid);
-  writer->WriteTags(writer->GetObjectTags(this));
+  LinkedHashSet& set =
+      LinkedHashSet::ZoneHandle(reader->zone(), LinkedHashSet::null());
+  // Since the set might contain itself as a key or value, allocate first.
+  set = LinkedHashSet::NewUninitialized();
+  reader->AddBackRef(object_id, &set, kIsDeserialized);
 
-  // Write out the type arguments.
-  writer->WriteObjectImpl(type_arguments(), kAsInlinedObject);
+  reader->SetReadFrom(object_id, set, tags);
 
-  const intptr_t num_used_data = Smi::Value(used_data());
-  ASSERT((num_used_data & 1) == 0);  // Keys + values, so must be even.
-  const intptr_t num_deleted_keys = Smi::Value(deleted_keys());
+  return set.ptr();
+}
 
-  // Write out the number of (not deleted) key/value pairs that will follow.
-  writer->Write<ObjectPtr>(Smi::New((num_used_data >> 1) - num_deleted_keys));
-
-  // Write out the keys and values.
-  const bool write_as_reference = this->IsCanonical() ? false : true;
-  ArrayPtr data_array = data();
-  ASSERT(num_used_data <= Smi::Value(data_array->untag()->length()));
-#if defined(DEBUG)
-  intptr_t deleted_keys_found = 0;
-#endif  // DEBUG
-  for (intptr_t i = 0; i < num_used_data; i += 2) {
-    ObjectPtr key = data_array->untag()->element(i);
-    if (key == data_array) {
-#if defined(DEBUG)
-      ++deleted_keys_found;
-#endif  // DEBUG
-      continue;
-    }
-    ObjectPtr value = data_array->untag()->element(i + 1);
-    writer->WriteObjectImpl(key, write_as_reference);
-    writer->WriteObjectImpl(value, write_as_reference);
-  }
-  DEBUG_ASSERT(deleted_keys_found == num_deleted_keys);
+void UntaggedLinkedHashSet::WriteTo(SnapshotWriter* writer,
+                                    intptr_t object_id,
+                                    Snapshot::Kind kind,
+                                    bool as_reference) {
+  ASSERT(writer != NULL);
+  ASSERT(!this->IsCanonical());
+  writer->SetWriteTo(object_id, kLinkedHashSetCid, writer->GetObjectTags(this),
+                     type_arguments(), used_data(), deleted_keys(), data(),
+                     as_reference);
 }
 
 Float32x4Ptr Float32x4::ReadFrom(SnapshotReader* reader,
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 238bc27..2decacb 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -5211,7 +5211,12 @@
   }
   {
     JSONArray internals(&map, "Map");
-    DEFINE_ADD_VALUE_F_CID(LinkedHashMap)
+    CLASS_LIST_MAPS(DEFINE_ADD_VALUE_F_CID)
+  }
+
+  {
+    JSONArray internals(&map, "Set");
+    CLASS_LIST_SETS(DEFINE_ADD_VALUE_F_CID)
   }
 #define DEFINE_ADD_MAP_KEY(clazz)                                              \
   {                                                                            \
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index f849156..affccc9 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -42,6 +42,7 @@
   return (class_id == kObjectCid ||
           (class_id >= kInstanceCid && class_id <= kUserTagCid) ||
           class_id == kArrayCid || class_id == kImmutableArrayCid ||
+          class_id == kLinkedHashMapCid || class_id == kLinkedHashSetCid ||
           IsStringClassId(class_id) || IsTypedDataClassId(class_id) ||
           IsExternalTypedDataClassId(class_id) ||
           IsTypedDataViewClassId(class_id) || class_id == kNullCid ||
@@ -333,7 +334,8 @@
       result = obj.ptr();
     }
     RunDelayedTypePostprocessing();
-    const Object& ok = Object::Handle(zone_, RunDelayedRehashingOfMaps());
+    const Object& ok =
+        Object::Handle(zone_, RunDelayedRehashingOfMapsAndSets());
     objects_to_rehash_ = GrowableObjectArray::null();
     if (!ok.IsNull()) {
       return ok.ptr();
@@ -367,13 +369,14 @@
 }
 
 void SnapshotReader::EnqueueRehashingOfMap(const LinkedHashMap& map) {
+  ASSERT(!map.IsCanonical());
   if (objects_to_rehash_.IsNull()) {
     objects_to_rehash_ = GrowableObjectArray::New();
   }
   objects_to_rehash_.Add(map);
 }
 
-ObjectPtr SnapshotReader::RunDelayedRehashingOfMaps() {
+ObjectPtr SnapshotReader::RunDelayedRehashingOfMapsAndSets() {
   if (!objects_to_rehash_.IsNull()) {
     return DartLibraryCalls::RehashObjects(thread(), objects_to_rehash_);
   }
@@ -577,7 +580,7 @@
 #undef SNAPSHOT_READ
 #define SNAPSHOT_READ(clazz) case kFfi##clazz##Cid:
 
-    CLASS_LIST_FFI(SNAPSHOT_READ) { UNREACHABLE(); }
+      CLASS_LIST_FFI(SNAPSHOT_READ) { UNREACHABLE(); }
 #undef SNAPSHOT_READ
     default:
       UNREACHABLE();
@@ -586,7 +589,8 @@
   return pobj_.ptr();
 }
 
-void SnapshotReader::EnqueueRehashingOfSet(const Object& set) {
+void SnapshotReader::EnqueueRehashingOfSet(const LinkedHashSet& set) {
+  ASSERT(!set.IsCanonical());
   if (objects_to_rehash_.IsNull()) {
     objects_to_rehash_ = GrowableObjectArray::New();
   }
@@ -623,9 +627,6 @@
     ASSERT(!cls_.IsNull());
     instance_size = cls_.host_instance_size();
   }
-  if (cls_.id() == set_class_.id()) {
-    EnqueueRehashingOfSet(*result);
-  }
   if (!as_reference) {
     // Read all the individual fields for inlined objects.
     intptr_t next_field_offset = cls_.host_next_field_offset();
@@ -890,6 +891,84 @@
   }
 }
 
+void SnapshotReader::MapReadFrom(intptr_t object_id,
+                                 const LinkedHashMap& map,
+                                 intptr_t tags) {
+  // Read the type arguments.
+  *TypeArgumentsHandle() ^= ReadObjectImpl(kAsInlinedObject);
+  map.SetTypeArguments(*TypeArgumentsHandle());
+
+  // Read the number of key/value pairs.
+  intptr_t len = ReadSmiValue();
+  intptr_t used_data = (len << 1);
+  map.SetUsedData(used_data);
+
+  // Allocate the data array.
+  intptr_t data_size =
+      Utils::Maximum(Utils::RoundUpToPowerOfTwo(used_data),
+                     static_cast<uintptr_t>(LinkedHashMap::kInitialIndexSize));
+  Array& data = Array::ZoneHandle(zone(), Array::New(data_size));
+  map.SetData(data);
+  map.SetDeletedKeys(0);
+
+  // The index and hashMask is regenerated by the maps themselves on demand.
+  // Thus, the index will probably be allocated in new space (unless it's huge).
+  // TODO(koda): Eagerly rehash here when no keys have user-defined '==', and
+  // in particular, if/when (const) maps are needed in the VM isolate snapshot.
+  ASSERT(isolate_group() != Dart::vm_isolate_group());
+  map.SetHashMask(0);  // Prefer sentinel 0 over null for better type feedback.
+
+  // Read the keys and values.
+  bool read_as_reference = UntaggedObject::IsCanonical(tags) ? false : true;
+  for (intptr_t i = 0; i < used_data; i++) {
+    *PassiveObjectHandle() = ReadObjectImpl(read_as_reference);
+    data.SetAt(i, *PassiveObjectHandle());
+  }
+
+  // TODO(http://dartbug.com/45908): Treat immutable, canonical maps.
+  ASSERT(!UntaggedObject::IsCanonical(tags));
+  // Can have user-defined hashCode for keys, compute in Dart.
+  EnqueueRehashingOfMap(map);
+}
+
+void SnapshotReader::SetReadFrom(intptr_t object_id,
+                                 const LinkedHashSet& set,
+                                 intptr_t tags) {
+  // Read the type arguments.
+  *TypeArgumentsHandle() ^= ReadObjectImpl(kAsInlinedObject);
+  set.SetTypeArguments(*TypeArgumentsHandle());
+
+  intptr_t used_data = ReadSmiValue();
+  set.SetUsedData(used_data);
+
+  // Allocate the data array.
+  intptr_t data_size =
+      Utils::Maximum(Utils::RoundUpToPowerOfTwo(used_data),
+                     static_cast<uintptr_t>(LinkedHashSet::kInitialIndexSize));
+  Array& data = Array::ZoneHandle(zone(), Array::New(data_size));
+  set.SetData(data);
+  set.SetDeletedKeys(0);
+
+  // The index and hashMask is regenerated by the sets themselves on demand.
+  // Thus, the index will probably be allocated in new space (unless it's huge).
+  // TODO(koda): Eagerly rehash here when no keys have user-defined '==', and
+  // in particular, if/when (const) sets are needed in the VM isolate snapshot.
+  ASSERT(isolate_group() != Dart::vm_isolate_group());
+  set.SetHashMask(0);  // Prefer sentinel 0 over null for better type feedback.
+
+  // Read the keys and values.
+  bool read_as_reference = UntaggedObject::IsCanonical(tags) ? false : true;
+  for (intptr_t i = 0; i < used_data; i++) {
+    *PassiveObjectHandle() = ReadObjectImpl(read_as_reference);
+    data.SetAt(i, *PassiveObjectHandle());
+  }
+
+  // TODO(http://dartbug.com/45908): Treat immutable, canonical sets.
+  ASSERT(!UntaggedObject::IsCanonical(tags));
+  // Can have user-defined hashCode for keys, compute in Dart.
+  EnqueueRehashingOfSet(set);
+}
+
 MessageSnapshotReader::MessageSnapshotReader(Message* message, Thread* thread)
     : SnapshotReader(message->snapshot(),
                      message->snapshot_length(),
@@ -1402,6 +1481,99 @@
   }
 }
 
+void SnapshotWriter::MapWriteTo(intptr_t object_id,
+                                intptr_t class_id,
+                                intptr_t tags,
+                                TypeArgumentsPtr type_arguments,
+                                SmiPtr used_data_smi,
+                                SmiPtr deleted_keys_smi,
+                                ArrayPtr data,
+                                bool as_reference) {
+  // Write out the serialization header value for this object.
+  WriteInlinedObjectHeader(object_id);
+
+  // Write out the class and tags information.
+  WriteIndexedObject(class_id);
+  WriteTags(tags);
+
+  // Write out the type arguments.
+  WriteObjectImpl(type_arguments, kAsInlinedObject);
+
+  const intptr_t num_used_data = Smi::Value(used_data_smi);
+  ASSERT((num_used_data & 1) == 0);  // Keys + values, so must be even.
+  const intptr_t num_deleted_keys = Smi::Value(deleted_keys_smi);
+
+  // Write out the number of (not deleted) key/value pairs that will follow.
+  Write<ObjectPtr>(Smi::New((num_used_data >> 1) - num_deleted_keys));
+
+  // Write out the keys and values.
+  const bool write_as_reference =
+      UntaggedObject::IsCanonical(tags) ? false : true;
+  ASSERT(num_used_data <= Smi::Value(data->untag()->length()));
+#if defined(DEBUG)
+  intptr_t deleted_keys_found = 0;
+#endif  // DEBUG
+  for (intptr_t i = 0; i < num_used_data; i += 2) {
+    ObjectPtr key = data->untag()->element(i);
+    if (key == data) {
+#if defined(DEBUG)
+      ++deleted_keys_found;
+#endif  // DEBUG
+      continue;
+    }
+    ObjectPtr value = data->untag()->element(i + 1);
+    WriteObjectImpl(key, write_as_reference);
+    WriteObjectImpl(value, write_as_reference);
+  }
+  DEBUG_ASSERT(deleted_keys_found == num_deleted_keys);
+}
+
+void SnapshotWriter::SetWriteTo(intptr_t object_id,
+                                intptr_t class_id,
+                                intptr_t tags,
+                                TypeArgumentsPtr type_arguments,
+                                SmiPtr used_data_smi,
+                                SmiPtr deleted_keys_smi,
+                                ArrayPtr data,
+                                bool as_reference) {
+  // Write out the serialization header value for this object.
+  WriteInlinedObjectHeader(object_id);
+
+  // Write out the class and tags information.
+  WriteIndexedObject(class_id);
+  WriteTags(tags);
+
+  // Write out the type arguments.
+  WriteObjectImpl(type_arguments, kAsInlinedObject);
+
+  const intptr_t num_used_data = Smi::Value(used_data_smi);
+  const intptr_t num_deleted_keys = Smi::Value(deleted_keys_smi);
+
+  // Write out the number of (not deleted) key/value pairs that will follow.
+  Write<ObjectPtr>(Smi::New(num_used_data - num_deleted_keys));
+
+  // Write out the keys and values.
+  const bool write_as_reference =
+      UntaggedObject::IsCanonical(tags) ? false : true;
+  ASSERT(num_used_data <= Smi::Value(data->untag()->length()));
+#if defined(DEBUG)
+  intptr_t deleted_keys_found = 0;
+#endif  // DEBUG
+  for (intptr_t i = 0; i < num_used_data; i++) {
+    ObjectPtr key = data->untag()->element(i);
+    if (key == data) {
+#if defined(DEBUG)
+      ++deleted_keys_found;
+#endif  // DEBUG
+      continue;
+    }
+    ObjectPtr value = data->untag()->element(i + 1);
+    WriteObjectImpl(key, write_as_reference);
+    WriteObjectImpl(value, write_as_reference);
+  }
+  DEBUG_ASSERT(deleted_keys_found == num_deleted_keys);
+}
+
 FunctionPtr SnapshotWriter::IsSerializableClosure(ClosurePtr closure) {
   // Extract the function object to check if this closure
   // can be sent in an isolate message.
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 60da2b3..8123e46 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -321,8 +321,8 @@
   void RunDelayedTypePostprocessing();
 
   void EnqueueRehashingOfMap(const LinkedHashMap& map);
-  void EnqueueRehashingOfSet(const Object& set);
-  ObjectPtr RunDelayedRehashingOfMaps();
+  void EnqueueRehashingOfSet(const LinkedHashSet& set);
+  ObjectPtr RunDelayedRehashingOfMapsAndSets();
 
   ClassPtr ReadClassId(intptr_t object_id);
   ObjectPtr ReadStaticImplicitClosure(intptr_t object_id, intptr_t cls_header);
@@ -349,6 +349,14 @@
                      intptr_t len,
                      intptr_t tags);
 
+  void MapReadFrom(intptr_t object_id,
+                   const LinkedHashMap& result,
+                   intptr_t tags);
+
+  void SetReadFrom(intptr_t object_id,
+                   const LinkedHashSet& result,
+                   intptr_t tags);
+
   intptr_t NextAvailableObjectId() const;
 
   void SetReadException(const char* msg);
@@ -357,32 +365,32 @@
 
   bool is_vm_isolate() const;
 
-  Snapshot::Kind kind_;            // Indicates type of the snapshot.
-  Thread* thread_;                 // Current thread.
-  Zone* zone_;                     // Zone for allocations while reading.
-  Heap* heap_;                     // Heap of the current isolate.
-  PageSpace* old_space_;           // Old space of the current isolate.
-  Class& cls_;                     // Temporary Class handle.
-  Code& code_;                     // Temporary Code handle.
-  Instance& instance_;             // Temporary Instance handle
-  Instructions& instructions_;     // Temporary Instructions handle
-  Object& obj_;                    // Temporary Object handle.
-  PassiveObject& pobj_;            // Temporary PassiveObject handle.
-  Array& array_;                   // Temporary Array handle.
-  Field& field_;                   // Temporary Field handle.
-  String& str_;                    // Temporary String handle.
-  Library& library_;               // Temporary library handle.
-  AbstractType& type_;             // Temporary type handle.
-  TypeArguments& type_arguments_;  // Temporary type argument handle.
-  GrowableObjectArray& tokens_;    // Temporary tokens handle.
-  ExternalTypedData& data_;        // Temporary stream data handle.
+  Snapshot::Kind kind_;             // Indicates type of the snapshot.
+  Thread* thread_;                  // Current thread.
+  Zone* zone_;                      // Zone for allocations while reading.
+  Heap* heap_;                      // Heap of the current isolate.
+  PageSpace* old_space_;            // Old space of the current isolate.
+  Class& cls_;                      // Temporary Class handle.
+  Code& code_;                      // Temporary Code handle.
+  Instance& instance_;              // Temporary Instance handle
+  Instructions& instructions_;      // Temporary Instructions handle
+  Object& obj_;                     // Temporary Object handle.
+  PassiveObject& pobj_;             // Temporary PassiveObject handle.
+  Array& array_;                    // Temporary Array handle.
+  Field& field_;                    // Temporary Field handle.
+  String& str_;                     // Temporary String handle.
+  Library& library_;                // Temporary library handle.
+  AbstractType& type_;              // Temporary type handle.
+  TypeArguments& type_arguments_;   // Temporary type argument handle.
+  GrowableObjectArray& tokens_;     // Temporary tokens handle.
+  ExternalTypedData& data_;         // Temporary stream data handle.
   TypedDataBase& typed_data_base_;  // Temporary typed data base handle.
-  TypedData& typed_data_;          // Temporary typed data handle.
+  TypedData& typed_data_;           // Temporary typed data handle.
   TypedDataView& typed_data_view_;  // Temporary typed data view handle.
-  Function& function_;             // Temporary function handle.
-  Smi& smi_;                       // Temporary Smi handle.
-  UnhandledException& error_;      // Error handle.
-  const Class& set_class_;         // The LinkedHashSet class.
+  Function& function_;              // Temporary function handle.
+  Smi& smi_;                        // Temporary Smi handle.
+  UnhandledException& error_;       // Error handle.
+  const Class& set_class_;          // The LinkedHashSet class.
   intptr_t max_vm_isolate_object_id_;
   ZoneGrowableArray<BackRefNode>* backward_references_;
   GrowableObjectArray& types_to_postprocess_;
@@ -406,6 +414,7 @@
   friend class Library;
   friend class LibraryPrefix;
   friend class LinkedHashMap;
+  friend class LinkedHashSet;
   friend class MirrorReference;
   friend class Namespace;
   friend class PatchClass;
@@ -649,6 +658,22 @@
                     TypeArgumentsPtr type_arguments,
                     CompressedObjectPtr data[],
                     bool as_reference);
+  void MapWriteTo(intptr_t object_id,
+                  intptr_t class_id,
+                  intptr_t tags,
+                  TypeArgumentsPtr type_arguments,
+                  SmiPtr used_data_smi,
+                  SmiPtr deleted_keys_smi,
+                  ArrayPtr data,
+                  bool as_reference);
+  void SetWriteTo(intptr_t object_id,
+                  intptr_t class_id,
+                  intptr_t tags,
+                  TypeArgumentsPtr type_arguments,
+                  SmiPtr used_data_smi,
+                  SmiPtr deleted_keys_smi,
+                  ArrayPtr data,
+                  bool as_reference);
   ClassPtr GetFunctionOwner(FunctionPtr func);
   void CheckForNativeFields(ClassPtr cls);
   void SetWriteException(Exceptions::ExceptionType type, const char* msg);
@@ -686,6 +711,7 @@
   friend class UntaggedInstructions;
   friend class UntaggedLibrary;
   friend class UntaggedLinkedHashMap;
+  friend class UntaggedLinkedHashSet;
   friend class UntaggedLocalVarDescriptors;
   friend class UntaggedMirrorReference;
   friend class UntaggedObjectPool;
diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h
index 4f3b1f6..ffd7d32 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -396,6 +396,7 @@
 DEFINE_TAGGED_POINTER(GrowableObjectArray, Instance)
 DEFINE_TAGGED_POINTER(LinkedHashBase, Instance)
 DEFINE_TAGGED_POINTER(LinkedHashMap, LinkedHashBase)
+DEFINE_TAGGED_POINTER(LinkedHashSet, LinkedHashBase)
 DEFINE_TAGGED_POINTER(Float32x4, Instance)
 DEFINE_TAGGED_POINTER(Int32x4, Instance)
 DEFINE_TAGGED_POINTER(Float64x2, Instance)
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index 492e9bd..dc552c7 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -490,18 +490,14 @@
   E get current => _current as E;
 }
 
-// Set implementation, analogous to _CompactLinkedHashMap.
-@pragma('vm:entry-point')
-class _CompactLinkedHashSet<E> extends _HashFieldBase
-    with _HashBase, _OperatorEqualsAndHashCode, SetMixin<E>
-    implements LinkedHashSet<E> {
-  _CompactLinkedHashSet() : super(_HashBase._INITIAL_INDEX_SIZE >> 1) {
-    assert(_HashBase._UNUSED_PAIR == 0);
-  }
+abstract class _LinkedHashSetMixin<E> implements _HashBase {
+  int _hashCode(e);
+  bool _equals(e1, e2);
+  int get _checkSum;
+  bool _isModifiedSince(List oldData, int oldCheckSum);
 
-  static Set<R> _newEmpty<R>() => new _CompactLinkedHashSet<R>();
-
-  Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newEmpty);
+  bool get isEmpty => length == 0;
+  bool get isNotEmpty => !isEmpty;
   int get length => _usedData - _deletedKeys;
 
   E get first {
@@ -650,19 +646,51 @@
   Iterator<E> get iterator =>
       new _CompactIterator<E>(this, _data, _usedData, -1, 1);
 
-  // Returns a set of the same type, although this
-  // is not required by the spec. (For instance, always using an identity set
-  // would be technically correct, albeit surprising.)
-  Set<E> toSet() => new _CompactLinkedHashSet<E>()..addAll(this);
-
   // This method is called by [_rehashObjects] (see above).
   void _regenerateIndex() {
+    _index = _data.length == 0 ? _initialIndex : new Uint32List(_data.length);
+    assert(_hashMask == 0);
+    _hashMask = _HashBase._indexSizeToHashMask(_index.length);
     _rehash();
   }
 }
 
-class _CompactLinkedIdentityHashSet<E> extends _CompactLinkedHashSet<E>
-    with _IdenticalAndIdentityHashCode {
+// Set implementation, analogous to _CompactLinkedHashMap.
+@pragma('vm:entry-point')
+class _CompactLinkedHashSet<E> extends _HashVMBase
+    with
+        SetMixin<E>,
+        _LinkedHashSetMixin<E>,
+        _HashBase,
+        _OperatorEqualsAndHashCode
+    implements LinkedHashSet<E> {
+  _CompactLinkedHashSet() {
+    _index = _initialIndex;
+    _hashMask = 0;
+    _data = _initialData;
+    _usedData = 0;
+    _deletedKeys = 0;
+  }
+
+  Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newEmpty);
+
+  static Set<R> _newEmpty<R>() => new _CompactLinkedHashSet<R>();
+
+  // Returns a set of the same type, although this
+  // is not required by the spec. (For instance, always using an identity set
+  // would be technically correct, albeit surprising.)
+  Set<E> toSet() => new _CompactLinkedHashSet<E>()..addAll(this);
+}
+
+class _CompactLinkedIdentityHashSet<E> extends _HashFieldBase
+    with
+        SetMixin<E>,
+        _LinkedHashSetMixin<E>,
+        _HashBase,
+        _IdenticalAndIdentityHashCode
+    implements LinkedHashSet<E> {
+  _CompactLinkedIdentityHashSet() : super(_HashBase._INITIAL_INDEX_SIZE);
+
   Set<E> toSet() => new _CompactLinkedIdentityHashSet<E>()..addAll(this);
 
   static Set<R> _newEmpty<R>() => new _CompactLinkedIdentityHashSet<R>();
@@ -670,7 +698,9 @@
   Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newEmpty);
 }
 
-class _CompactLinkedCustomHashSet<E> extends _CompactLinkedHashSet<E> {
+class _CompactLinkedCustomHashSet<E> extends _HashFieldBase
+    with SetMixin<E>, _LinkedHashSetMixin<E>, _HashBase
+    implements LinkedHashSet<E> {
   final _equality;
   final _hasher;
   final _validKey;
@@ -683,7 +713,8 @@
   bool remove(Object? o) => _validKey(o) ? super.remove(o) : false;
 
   _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey)
-      : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test;
+      : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test,
+        super(_HashBase._INITIAL_INDEX_SIZE);
 
   Set<R> cast<R>() => Set.castFrom<E, R>(this);
   Set<E> toSet() =>
diff --git a/tests/language/const/map2_runtime_test.dart b/tests/language/const/map2_runtime_test.dart
index 9e1fe97..02e6a9e 100644
--- a/tests/language/const/map2_runtime_test.dart
+++ b/tests/language/const/map2_runtime_test.dart
@@ -13,12 +13,10 @@
 
 class B implements A {
   const B();
-
-
 }
 
 confuse(x) {
-  if (new DateTime.now() == 42) return confuse(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42) return confuse(2);
   return x;
 }
 
diff --git a/tests/language/const/map2_test.dart b/tests/language/const/map2_test.dart
index a5f3798..dd392be 100644
--- a/tests/language/const/map2_test.dart
+++ b/tests/language/const/map2_test.dart
@@ -15,7 +15,7 @@
 }
 
 confuse(x) {
-  if (new DateTime.now() == 42) return confuse(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42) return confuse(2);
   return x;
 }
 
diff --git a/tests/language/const/map_hashcode_override2_test.dart b/tests/language/const/map_hashcode_override2_test.dart
index b747a97..871b14a 100644
--- a/tests/language/const/map_hashcode_override2_test.dart
+++ b/tests/language/const/map_hashcode_override2_test.dart
@@ -9,7 +9,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language/const/map_hashcode_override_test.dart b/tests/language/const/map_hashcode_override_test.dart
index e378e05..a88d1a8 100644
--- a/tests/language/const/map_hashcode_override_test.dart
+++ b/tests/language/const/map_hashcode_override_test.dart
@@ -9,7 +9,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language/const/map_test.dart b/tests/language/const/map_test.dart
index 13c6720..3658459 100644
--- a/tests/language/const/map_test.dart
+++ b/tests/language/const/map_test.dart
@@ -9,7 +9,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language/const/set_hashcode_override2_test.dart b/tests/language/const/set_hashcode_override2_test.dart
index 1fc8665..0775822 100644
--- a/tests/language/const/set_hashcode_override2_test.dart
+++ b/tests/language/const/set_hashcode_override2_test.dart
@@ -9,7 +9,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language/regress/regress15720_test.dart b/tests/language/regress/regress15720_test.dart
index 638fc98..85c102c 100644
--- a/tests/language/regress/regress15720_test.dart
+++ b/tests/language/regress/regress15720_test.dart
@@ -7,7 +7,7 @@
 class B {}
 
 confuse(x) {
-  if (new DateTime.now() == 42) return confuse(x);
+  if (DateTime.now().millisecondsSinceEpoch == 42) return confuse(x);
   return x;
 }
 
diff --git a/tests/language/vm/regress_flutter_85311_test.dart b/tests/language/vm/regress_flutter_85311_test.dart
new file mode 100644
index 0000000..122d13a
--- /dev/null
+++ b/tests/language/vm/regress_flutter_85311_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, 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.
+
+// This is a regression test for the bug in
+// https://github.com/flutter/flutter/issues/51828.
+// Verifies that temporaries aren't incorrectly assigned types when they're
+// reused.
+
+import "package:expect/expect.dart";
+
+bool wasCalled = false;
+
+class Z {
+  bool operator ==(Object other) {
+    wasCalled = true;
+    return true;
+  }
+}
+
+class Y {
+  final dynamic v;
+  Y(this.v);
+}
+
+Future<bool> crash(dynamic y) async {
+  return (y.v == (await 7) || y == (await 9));
+}
+
+void main() async {
+  await crash(Y(Z()));
+
+  Expect.isTrue(wasCalled);
+}
diff --git a/tests/language_2/const/map2_runtime_test.dart b/tests/language_2/const/map2_runtime_test.dart
index 5ce67f2..d9a2e80 100644
--- a/tests/language_2/const/map2_runtime_test.dart
+++ b/tests/language_2/const/map2_runtime_test.dart
@@ -15,12 +15,10 @@
 
 class B implements A {
   const B();
-
-
 }
 
 confuse(x) {
-  if (new DateTime.now() == 42) return confuse(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42) return confuse(2);
   return x;
 }
 
diff --git a/tests/language_2/const/map2_test.dart b/tests/language_2/const/map2_test.dart
index 55f729e..216886c 100644
--- a/tests/language_2/const/map2_test.dart
+++ b/tests/language_2/const/map2_test.dart
@@ -17,7 +17,7 @@
 }
 
 confuse(x) {
-  if (new DateTime.now() == 42) return confuse(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42) return confuse(2);
   return x;
 }
 
diff --git a/tests/language_2/const/map_hashcode_override2_test.dart b/tests/language_2/const/map_hashcode_override2_test.dart
index 86ced20..26ffaf6 100644
--- a/tests/language_2/const/map_hashcode_override2_test.dart
+++ b/tests/language_2/const/map_hashcode_override2_test.dart
@@ -11,7 +11,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language_2/const/map_hashcode_override_test.dart b/tests/language_2/const/map_hashcode_override_test.dart
index 47223e7..c297c54 100644
--- a/tests/language_2/const/map_hashcode_override_test.dart
+++ b/tests/language_2/const/map_hashcode_override_test.dart
@@ -11,7 +11,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language_2/const/map_test.dart b/tests/language_2/const/map_test.dart
index bbd4a8f..543596a 100644
--- a/tests/language_2/const/map_test.dart
+++ b/tests/language_2/const/map_test.dart
@@ -11,7 +11,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language_2/const/set_hashcode_override2_test.dart b/tests/language_2/const/set_hashcode_override2_test.dart
index 7035373..d14e8e2 100644
--- a/tests/language_2/const/set_hashcode_override2_test.dart
+++ b/tests/language_2/const/set_hashcode_override2_test.dart
@@ -11,7 +11,8 @@
 /// Prevents static optimizations and inlining.
 getValueNonOptimized(x) {
   // DateTime.now() cannot be predicted statically, never equal to ASCII 42 '*'.
-  if (new DateTime.now() == 42) return getValueNonOptimized(2);
+  if (DateTime.now().millisecondsSinceEpoch == 42)
+    return getValueNonOptimized(2);
   return x;
 }
 
diff --git a/tests/language_2/regress/regress15720_test.dart b/tests/language_2/regress/regress15720_test.dart
index f07405e..14d5b18 100644
--- a/tests/language_2/regress/regress15720_test.dart
+++ b/tests/language_2/regress/regress15720_test.dart
@@ -9,7 +9,7 @@
 class B {}
 
 confuse(x) {
-  if (new DateTime.now() == 42) return confuse(x);
+  if (DateTime.now().millisecondsSinceEpoch == 42) return confuse(x);
   return x;
 }
 
diff --git a/tests/language_2/vm/regress_flutter_85311_test.dart b/tests/language_2/vm/regress_flutter_85311_test.dart
new file mode 100644
index 0000000..a3458f9
--- /dev/null
+++ b/tests/language_2/vm/regress_flutter_85311_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2021, 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.
+
+// @dart = 2.9
+
+// This is a regression test for the bug in
+// https://github.com/flutter/flutter/issues/51828.
+// Verifies that temporaries aren't incorrectly assigned types when they're
+// reused.
+
+import "package:expect/expect.dart";
+
+bool wasCalled = false;
+
+class Z {
+  bool operator ==(Object other) {
+    wasCalled = true;
+    return true;
+  }
+}
+
+class Y {
+  final dynamic v;
+  Y(this.v);
+}
+
+Future<bool> crash(dynamic y) async {
+  return (y.v == (await 7) || y == (await 9));
+}
+
+void main() async {
+  await crash(Y(Z()));
+
+  Expect.isTrue(wasCalled);
+}
diff --git a/tools/VERSION b/tools/VERSION
index addff9c..b0c12a4 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 304
+PRERELEASE 305
 PRERELEASE_PATCH 0
\ No newline at end of file