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