Index: runtime/vm/raw_object_snapshot.cc |
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc |
index 27ec70df7f8bf49e65ec7b0e3f029a72bf6df90a..fcb7b0a47669edeeab5055c027d7529d6bab092d 100644 |
--- a/runtime/vm/raw_object_snapshot.cc |
+++ b/runtime/vm/raw_object_snapshot.cc |
@@ -2204,9 +2204,9 @@ void RawGrowableObjectArray::WriteTo(SnapshotWriter* writer, |
RawLinkedHashMap* LinkedHashMap::ReadFrom(SnapshotReader* reader, |
- intptr_t object_id, |
- intptr_t tags, |
- Snapshot::Kind kind) { |
+ intptr_t object_id, |
+ intptr_t tags, |
+ Snapshot::Kind kind) { |
ASSERT(reader != NULL); |
LinkedHashMap& map = LinkedHashMap::ZoneHandle( |
@@ -2222,20 +2222,46 @@ RawLinkedHashMap* LinkedHashMap::ReadFrom(SnapshotReader* reader, |
reader->AddBackRef(object_id, &map, kIsDeserialized); |
// Set the object tags. |
map.set_tags(tags); |
- // Read and set the fields. |
- intptr_t num_flds = (map.raw()->to() - map.raw()->from()); |
- for (intptr_t i = 0; i <= num_flds; i++) { |
- (*reader->PassiveObjectHandle()) = reader->ReadObjectRef(); |
- map.StorePointer((map.raw()->from() + i), |
- reader->PassiveObjectHandle()->raw()); |
+ |
+ // Read the type arguments. |
+ *reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl(); |
+ map.SetTypeArguments(*reader->TypeArgumentsHandle()); |
+ |
+ // 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, HEAP_SPACE(kind))); |
+ 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() != Dart::vm_isolate()); |
+ map.SetHashMask(0); // Prefer sentinel 0 over null for better type feedback. |
+ |
+ // Read the keys and values. |
+ bool is_canonical = RawObject::IsCanonical(tags); |
+ for (intptr_t i = 0; i < used_data; i++) { |
+ *reader->PassiveObjectHandle() = |
+ is_canonical ? reader->ReadObjectImpl() : reader->ReadObjectRef(); |
+ data.SetAt(i, *reader->PassiveObjectHandle()); |
} |
return map.raw(); |
} |
void RawLinkedHashMap::WriteTo(SnapshotWriter* writer, |
- intptr_t object_id, |
- Snapshot::Kind kind) { |
+ intptr_t object_id, |
+ Snapshot::Kind kind) { |
if (kind == Snapshot::kFull || kind == Snapshot::kScript) { |
// The immutable maps that seed map literals are not yet VM-internal, so |
// we don't reach this. |
@@ -2248,14 +2274,45 @@ void RawLinkedHashMap::WriteTo(SnapshotWriter* writer, |
// Write out the class and tags information. |
writer->WriteIndexedObject(kLinkedHashMapCid); |
- writer->WriteTags(writer->GetObjectTags(this)); |
+ const uword tags = writer->GetObjectTags(this); |
+ writer->WriteTags(tags); |
- // Write out all the object pointer fields. |
- // TODO(koda): Serialize only used parts of data_ (after compaction), to |
- // reduce space and support per-isolate salted hash codes. All allowed keys |
- // have types for which we can rehash without running Dart code. |
- SnapshotWriterVisitor visitor(writer); |
- visitor.VisitPointers(from(), to()); |
+ // Write out the type arguments. |
+ writer->WriteObjectImpl(ptr()->type_arguments_); |
+ |
+ const intptr_t used_data = Smi::Value(ptr()->used_data_); |
+ ASSERT((used_data & 1) == 0); // Keys + values, so must be even. |
+ const intptr_t deleted_keys = Smi::Value(ptr()->deleted_keys_); |
+ |
+ // Write out the number of (not deleted) key/value pairs that will follow. |
+ writer->Write<RawObject*>(Smi::New((used_data >> 1) - deleted_keys)); |
+ |
+ // Write out the keys and values. |
+ const bool is_canonical = RawObject::IsCanonical(tags); |
+ RawArray* data_array = ptr()->data_; |
+ RawObject** data_elements = data_array->ptr()->data(); |
+ ASSERT(used_data <= Smi::Value(data_array->ptr()->length_)); |
+#if defined(DEBUG) |
+ intptr_t deleted_keys_found = 0; |
+#endif // DEBUG |
+ for (intptr_t i = 0; i < used_data; i += 2) { |
+ RawObject* key = data_elements[i]; |
+ if (key == data_array) { |
+#if defined(DEBUG) |
+ ++deleted_keys_found; |
+#endif // DEBUG |
+ continue; |
+ } |
+ RawObject* value = data_elements[i + 1]; |
+ if (is_canonical) { |
+ writer->WriteObjectImpl(key); |
+ writer->WriteObjectImpl(value); |
+ } else { |
+ writer->WriteObjectRef(key); |
+ writer->WriteObjectRef(value); |
+ } |
+ } |
+ DEBUG_ASSERT(deleted_keys_found == deleted_keys); |
} |