[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));
+}