[VM] Rehash sets after they are read from a snapshot.

Fixes: https://github.com/dart-lang/sdk/issues/35626
Bug: https://github.com/dart-lang/sdk/issues/35626
Change-Id: I4d5b3799072faf8abb16e9eac15b834dbecce07b
Reviewed-on: https://dart-review.googlesource.com/c/93843
Commit-Queue: Liam Appelbe <liama@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/lib/compact_hash.dart b/runtime/lib/compact_hash.dart
index c5d143d..e73a551 100644
--- a/runtime/lib/compact_hash.dart
+++ b/runtime/lib/compact_hash.dart
@@ -614,6 +614,11 @@
   // 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() {
+    _rehash();
+  }
 }
 
 class _CompactLinkedIdentityHashSet<E> extends _CompactLinkedHashSet<E>
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index cecbe27..2d080e3 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -131,18 +131,23 @@
 }
 
 void ObjectStore::InitKnownObjects() {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Class& cls = Class::Handle(zone);
+  const Library& collection_lib = Library::Handle(collection_library());
+  cls = collection_lib.LookupClassAllowPrivate(Symbols::_LinkedHashSet());
+  ASSERT(!cls.IsNull());
+  set_linked_hash_set_class(cls);
+
 #ifdef DART_PRECOMPILED_RUNTIME
   // These objects are only needed for code generation.
   return;
 #else
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL && isolate->object_store() == this);
 
   const Library& async_lib = Library::Handle(async_library());
   ASSERT(!async_lib.IsNull());
-  Class& cls = Class::Handle(zone);
   cls = async_lib.LookupClass(Symbols::Future());
   ASSERT(!cls.IsNull());
   set_future_class(cls);
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index a4f0227..3b9a10b 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -76,6 +76,7 @@
   RW(Class, immutable_array_class)                                             \
   RW(Class, growable_object_array_class)                                       \
   RW(Class, linked_hash_map_class)                                             \
+  RW(Class, linked_hash_set_class)                                             \
   RW(Class, float32x4_class)                                                   \
   RW(Class, int32x4_class)                                                     \
   RW(Class, float64x2_class)                                                   \
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index f43b9aa..bf62b08 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -223,6 +223,9 @@
       typed_data_(TypedData::Handle(zone_)),
       function_(Function::Handle(zone_)),
       error_(UnhandledException::Handle(zone_)),
+      set_class_(Class::ZoneHandle(
+          zone_,
+          thread_->isolate()->object_store()->linked_hash_set_class())),
       max_vm_isolate_object_id_(
           (Snapshot::IsFull(kind))
               ? Object::vm_isolate_snapshot_object_table().Length()
@@ -487,6 +490,10 @@
   return pobj_.raw();
 }
 
+void SnapshotReader::EnqueueRehashingOfSet(const Object& set) {
+  objects_to_rehash_.Add(set);
+}
+
 RawObject* SnapshotReader::ReadInstance(intptr_t object_id,
                                         intptr_t tags,
                                         bool as_reference) {
@@ -516,6 +523,9 @@
     ASSERT(!cls_.IsNull());
     instance_size = cls_.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_.next_field_offset();
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 04e0cd6..5a4ab63 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -343,6 +343,7 @@
   void RunDelayedTypePostprocessing();
 
   void EnqueueRehashingOfMap(const LinkedHashMap& map);
+  void EnqueueRehashingOfSet(const Object& set);
   RawObject* RunDelayedRehashingOfMaps();
 
   RawClass* ReadClassId(intptr_t object_id);
@@ -399,6 +400,7 @@
   TypedData& typed_data_;          // Temporary typed data handle.
   Function& function_;             // Temporary function 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_;
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 662a052..279cb99 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -221,6 +221,7 @@
   V(_GrowableListWithData, "_GrowableList.withData")                           \
   V(_ImmutableList, "_ImmutableList")                                          \
   V(_LinkedHashMap, "_InternalLinkedHashMap")                                  \
+  V(_LinkedHashSet, "_CompactLinkedHashSet")                                   \
   V(_rehashObjects, "_rehashObjects")                                          \
   V(_String, "String")                                                         \
   V(OneByteString, "_OneByteString")                                           \
diff --git a/tests/lib_2/isolate/issue_35626_test.dart b/tests/lib_2/isolate/issue_35626_test.dart
new file mode 100644
index 0000000..2873d83
--- /dev/null
+++ b/tests/lib_2/isolate/issue_35626_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests that sets of enums can be set through ports.
+// https://github.com/dart-lang/sdk/issues/35626
+
+library spawn_tests;
+
+import "dart:io";
+import "dart:isolate";
+import "package:expect/expect.dart";
+
+enum MyEnum { foo, bar, baz }
+
+void sendSetOfEnums(SendPort port) {
+  Set<MyEnum> remoteSet = Set()..add(MyEnum.bar);
+  port.send(remoteSet);
+}
+
+void main() async {
+  Set<MyEnum> localSet = Set()..add(MyEnum.foo)..add(MyEnum.bar);
+  localSet.lookup(MyEnum.foo);
+
+  final port = ReceivePort();
+  await Isolate.spawn(sendSetOfEnums, port.sendPort);
+  Set<MyEnum> remoteSet = await port.first;
+
+  print(localSet);
+  print(remoteSet);
+  Expect.setEquals([MyEnum.bar], localSet.intersection(remoteSet));
+  Expect.setEquals([MyEnum.bar], remoteSet.intersection(localSet));
+}