Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Unified Diff: vm/snapshot.cc

Issue 10535066: 1. Remove recursion during snapshot writing and reading (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « vm/snapshot.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: vm/snapshot.cc
===================================================================
--- vm/snapshot.cc (revision 8515)
+++ vm/snapshot.cc (working copy)
@@ -89,12 +89,14 @@
RawObject* SnapshotReader::ReadObject() {
- int64_t value = Read<int64_t>();
- if ((value & kSmiTagMask) == 0) {
- return Integer::New((value >> kSmiTagShift));
+ Object& obj = Object::Handle(ReadObjectImpl());
+ for (intptr_t i = 0; i < backward_references_.length(); i++) {
+ if (!backward_references_[i]->is_deserialized()) {
+ ReadObjectImpl();
+ backward_references_[i]->set_state(kIsDeserialized);
+ }
}
- ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
- return ReadObjectImpl(value);
+ return obj.raw();
}
@@ -105,13 +107,13 @@
ASSERT((class_header & kSmiTagMask) != 0);
Class& cls = Class::ZoneHandle(isolate(), Class::null());
cls ^= LookupInternalClass(class_header);
- AddBackwardReference(object_id, &cls);
+ AddBackRef(object_id, &cls, kIsDeserialized);
if (cls.IsNull()) {
// Read the library/class information and lookup the class.
str_ ^= ReadObjectImpl(class_header);
library_ = Library::LookupLibrary(str_);
ASSERT(!library_.IsNull());
- str_ ^= ReadObject();
+ str_ ^= ReadObjectImpl();
cls ^= library_.LookupClass(str_);
}
ASSERT(!cls.IsNull());
@@ -119,12 +121,135 @@
}
-void SnapshotReader::AddBackwardReference(intptr_t id, Object* obj) {
- ASSERT((id - kMaxPredefinedObjectIds) == backward_references_.length());
- backward_references_.Add(obj);
+RawObject* SnapshotReader::ReadObjectImpl() {
+ int64_t value = Read<int64_t>();
+ if ((value & kSmiTagMask) == 0) {
+ return Integer::New((value >> kSmiTagShift));
+ }
+ return ReadObjectImpl(value);
}
+RawObject* SnapshotReader::ReadObjectImpl(intptr_t value) {
+ ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
+ SerializedHeaderType header_type = SerializedHeaderTag::decode(value);
+ intptr_t header_value = SerializedHeaderData::decode(value);
+
+ if (header_type == kObjectId) {
+ return ReadIndexedObject(header_value);
+ }
+ ASSERT(header_type == kInlined);
+ return ReadInlinedObject(header_value);
+}
+
+
+RawObject* SnapshotReader::ReadObjectRef() {
+ int64_t value = Read<int64_t>();
+ if ((value & kSmiTagMask) == 0) {
+ return Integer::New((value >> kSmiTagShift));
+ }
+ ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
+ SerializedHeaderType header_type = SerializedHeaderTag::decode(value);
+ intptr_t header_value = SerializedHeaderData::decode(value);
+
+ if (header_type == kObjectId) {
+ return ReadIndexedObject(header_value);
+ }
+ ASSERT(header_type == kInlined);
+ intptr_t object_id = header_value;
+ ASSERT(GetBackRef(object_id) == NULL);
+
+ // Read the class header information and lookup the class.
+ intptr_t class_header = ReadIntptrValue();
+
+ // Since we are only reading an object reference, If it is an instance kind
+ // then we only need to figure out the class of the object and allocate an
+ // instance of it. The individual fields will be read later.
+ if (SerializedHeaderData::decode(class_header) == kInstanceId) {
+ Instance& result = Instance::ZoneHandle(isolate(), Instance::null());
+ AddBackRef(object_id, &result, kIsNotDeserialized);
+
+ cls_ ^= ReadObjectImpl(); // Read class information.
+ ASSERT(!cls_.IsNull());
+ intptr_t instance_size = cls_.instance_size();
+ ASSERT(instance_size > 0);
+ if (kind_ == Snapshot::kFull) {
+ result ^= AllocateUninitialized(cls_, instance_size);
+ } else {
+ result ^= Object::Allocate(cls_, instance_size, Heap::kNew);
+ }
+ return result.raw();
+ } else {
+ ASSERT((class_header & kSmiTagMask) != 0);
+ cls_ ^= LookupInternalClass(class_header);
+ ASSERT(!cls_.IsNull());
+ }
+
+ // Similarly Array and ImmutableArray objects are also similarly only
+ // allocated here, the individual array elements are read later.
+ ObjectKind obj_kind = cls_.instance_kind();
+ if (obj_kind == Array::kInstanceKind) {
+ // Read the length and allocate an object based on the len.
+ intptr_t len = ReadSmiValue();
+ Array& array = Array::ZoneHandle(
+ isolate(),
+ (kind_ == Snapshot::kFull) ? NewArray(len) : Array::New(len));
+ AddBackRef(object_id, &array, kIsNotDeserialized);
+
+ return array.raw();
+ }
+ if (obj_kind == ImmutableArray::kInstanceKind) {
+ // Read the length and allocate an object based on the len.
+ intptr_t len = ReadSmiValue();
+ ImmutableArray& array = ImmutableArray::ZoneHandle(
+ isolate(),
+ (kind_ == Snapshot::kFull) ?
+ NewImmutableArray(len) : ImmutableArray::New(len));
+ AddBackRef(object_id, &array, kIsNotDeserialized);
+
+ return array.raw();
+ }
+
+ // For all other internal VM classes we read the object inline.
+ intptr_t tags = ReadIntptrValue();
+ switch (obj_kind) {
+#define SNAPSHOT_READ(clazz) \
+ case clazz::kInstanceKind: { \
+ obj_ = clazz::ReadFrom(this, object_id, tags, kind_); \
+ break; \
+ }
+ CLASS_LIST_NO_OBJECT(SNAPSHOT_READ)
+#undef SNAPSHOT_READ
+ default: UNREACHABLE(); break;
+ }
+ if (kind_ == Snapshot::kFull) {
+ obj_.SetCreatedFromSnapshot();
+ }
+ return obj_.raw();
+}
+
+
+void SnapshotReader::AddBackRef(intptr_t id,
+ Object* obj,
+ DeserializeState state) {
+ intptr_t index = (id - kMaxPredefinedObjectIds);
+ ASSERT(index == backward_references_.length());
+ BackRefNode* node = new BackRefNode(obj, state);
+ ASSERT(node != NULL);
+ backward_references_.Add(node);
+}
+
+
+Object* SnapshotReader::GetBackRef(intptr_t id) {
+ ASSERT(id >= kMaxPredefinedObjectIds);
+ intptr_t index = (id - kMaxPredefinedObjectIds);
+ if (index < backward_references_.length()) {
+ return backward_references_[index]->reference();
+ }
+ return NULL;
+}
+
+
void SnapshotReader::ReadFullSnapshot() {
ASSERT(kind_ == Snapshot::kFull);
Isolate* isolate = Isolate::Current();
@@ -139,8 +264,14 @@
// Read in all the objects stored in the object store.
intptr_t num_flds = (object_store->to() - object_store->from());
for (intptr_t i = 0; i <= num_flds; i++) {
- *(object_store->from() + i) = ReadObject();
+ *(object_store->from() + i) = ReadObjectImpl();
}
+ for (intptr_t i = 0; i < backward_references_.length(); i++) {
+ if (!backward_references_[i]->is_deserialized()) {
+ ReadObjectImpl();
+ backward_references_[i]->set_state(kIsDeserialized);
+ }
+ }
// Setup native resolver for bootstrap impl.
Bootstrap::SetupNativeResolver();
@@ -378,18 +509,6 @@
}
-RawObject* SnapshotReader::ReadObjectImpl(intptr_t header) {
- SerializedHeaderType header_type = SerializedHeaderTag::decode(header);
- intptr_t header_value = SerializedHeaderData::decode(header);
-
- if (header_type == kObjectId) {
- return ReadIndexedObject(header_value);
- }
- ASSERT(header_type == kInlined);
- return ReadInlinedObject(header_value);
-}
-
-
RawObject* SnapshotReader::ReadIndexedObject(intptr_t object_id) {
if (object_id == Object::kNullObject) {
// This is a singleton null object, return it.
@@ -412,10 +531,8 @@
}
}
- ASSERT(object_id >= kMaxPredefinedObjectIds);
- intptr_t index = object_id - kMaxPredefinedObjectIds;
- ASSERT(index < backward_references_.length());
- return backward_references_[index]->raw();
+ Object* object = GetBackRef(object_id);
+ return object->raw();
}
@@ -425,31 +542,38 @@
intptr_t tags = ReadIntptrValue();
if (SerializedHeaderData::decode(class_header) == kInstanceId) {
// Object is regular dart instance.
- Instance& result = Instance::ZoneHandle(isolate(), Instance::null());
- AddBackwardReference(object_id, &result);
-
- cls_ ^= ReadObject();
- ASSERT(!cls_.IsNull());
- intptr_t instance_size = cls_.instance_size();
- ASSERT(instance_size > 0);
- // Allocate the instance and read in all the fields for the object.
- if (kind_ == Snapshot::kFull) {
- result ^= AllocateUninitialized(cls_, instance_size);
+ Instance* result = reinterpret_cast<Instance*>(GetBackRef(object_id));
+ intptr_t instance_size = 0;
+ if (result == NULL) {
+ result = &(Instance::ZoneHandle(isolate(), Instance::null()));
+ AddBackRef(object_id, result, kIsDeserialized);
+ cls_ ^= ReadObjectImpl();
+ ASSERT(!cls_.IsNull());
+ instance_size = cls_.instance_size();
+ ASSERT(instance_size > 0);
+ // Allocate the instance and read in all the fields for the object.
+ if (kind_ == Snapshot::kFull) {
+ *result ^= AllocateUninitialized(cls_, instance_size);
+ } else {
+ *result ^= Object::Allocate(cls_, instance_size, Heap::kNew);
+ }
} else {
- result ^= Object::Allocate(cls_, instance_size, Heap::kNew);
+ cls_ ^= ReadObjectImpl();
+ ASSERT(!cls_.IsNull());
+ instance_size = cls_.instance_size();
}
intptr_t offset = Object::InstanceSize();
while (offset < instance_size) {
- obj_ = ReadObject();
- result.SetFieldAtOffset(offset, obj_);
+ obj_ = ReadObjectRef();
+ result->SetFieldAtOffset(offset, obj_);
offset += kWordSize;
}
if (kind_ == Snapshot::kFull) {
- result.SetCreatedFromSnapshot();
- } else if (result.IsCanonical()) {
- result = result.Canonicalize();
+ result->SetCreatedFromSnapshot();
+ } else if (result->IsCanonical()) {
+ *result = result->Canonicalize();
}
- return result.raw();
+ return result->raw();
} else {
ASSERT((class_header & kSmiTagMask) != 0);
cls_ ^= LookupInternalClass(class_header);
@@ -472,26 +596,123 @@
}
+void SnapshotReader::ArrayReadFrom(const Array& result,
+ intptr_t len,
+ intptr_t tags) {
+ // Set the object tags.
+ result.set_tags(tags);
+
+ // Setup the object fields.
+ *TypeArgumentsHandle() ^= ReadObjectImpl();
+ result.SetTypeArguments(*TypeArgumentsHandle());
+
+ for (intptr_t i = 0; i < len; i++) {
+ *ObjectHandle() = ReadObjectRef();
+ result.SetAt(i, *ObjectHandle());
+ }
+}
+
+
void SnapshotWriter::WriteObject(RawObject* rawobj) {
+ WriteObjectImpl(rawobj);
+ WriteForwardedObjects();
+}
+
+
+void SnapshotWriter::WriteObjectRef(RawObject* raw) {
// First check if object can be written as a simple predefined type.
- if (CheckAndWritePredefinedObject(rawobj)) {
+ if (CheckAndWritePredefinedObject(raw)) {
return;
}
- // Now write the object out inline in the stream as follows:
- // - Object is seen for the first time (inlined as follows):
- // (object size in multiples of kObjectAlignment | 0x1)
- // serialized fields of the object
- // ......
- WriteInlinedObject(rawobj);
-}
+ // Check if object has already been serialized, in that
+ // case just write the object id out.
+ uword tags = raw->ptr()->tags_;
+ if (SerializedHeaderTag::decode(tags) == kObjectId) {
+ intptr_t id = SerializedHeaderData::decode(tags);
+ WriteIndexedObject(id);
+ return;
+ }
+ NoGCScope no_gc;
+ RawClass* cls = class_table_->At(RawObject::ClassIdTag::decode(tags));
-void SnapshotWriter::UnmarkAll() {
- NoGCScope no_gc;
- for (intptr_t i = 0; i < forward_list_.length(); i++) {
- RawObject* raw = forward_list_[i]->raw();
- raw->ptr()->tags_ = forward_list_[i]->tags(); // Restore original tags.
+ ObjectKind obj_kind = cls->ptr()->instance_kind_;
+ if (obj_kind == Instance::kInstanceKind) {
+ // Object is being referenced, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // this object id. Mark it as not having been serialized yet so that we
+ // will serialize the object when we go through the forward list.
+ intptr_t object_id = MarkObject(raw, kIsNotSerialized);
+
+ // Write out the serialization header value for this object.
+ WriteSerializationMarker(kInlined, object_id);
+
+ // Indicate this is an instance object.
+ WriteIntptrValue(SerializedHeaderData::encode(kInstanceId));
+
+ // Write out the class information for this object.
+ WriteObjectImpl(cls);
+
+ return;
}
+ if (obj_kind == Array::kInstanceKind) {
+ // Object is being referenced, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // this object id. Mark it as not having been serialized yet so that we
+ // will serialize the object when we go through the forward list.
+ intptr_t object_id = MarkObject(raw, kIsNotSerialized);
+
+ RawArray* rawarray = reinterpret_cast<RawArray*>(raw);
+
+ // Write out the serialization header value for this object.
+ WriteSerializationMarker(kInlined, object_id);
+
+ // Write out the class information.
+ WriteIndexedObject(ObjectStore::kArrayClass);
+
+ // Write out the length field.
+ Write<RawObject*>(rawarray->ptr()->length_);
+
+ return;
+ }
+ if (obj_kind == ImmutableArray::kInstanceKind) {
+ // Object is being referenced, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // this object id. Mark it as not having been serialized yet so that we
+ // will serialize the object when we go through the forward list.
+ intptr_t object_id = MarkObject(raw, kIsNotSerialized);
+
+ RawArray* rawarray = reinterpret_cast<RawArray*>(raw);
+
+ // Write out the serialization header value for this object.
+ WriteSerializationMarker(kInlined, object_id);
+
+ // Write out the class information.
+ WriteIndexedObject(ObjectStore::kImmutableArrayClass);
+
+ // Write out the length field.
+ Write<RawObject*>(rawarray->ptr()->length_);
+
+ return;
+ }
+ // Object is being referenced, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // this object id. Mark it as not having been serialized yet so that we
+ // will serialize the object when we go through the forward list.
+ intptr_t object_id = MarkObject(raw, kIsSerialized);
+ switch (obj_kind) {
+#define SNAPSHOT_WRITE(clazz) \
+ case clazz::kInstanceKind: { \
+ Raw##clazz* raw_obj = reinterpret_cast<Raw##clazz*>(raw); \
+ raw_obj->WriteTo(this, object_id, kind_); \
+ return; \
+ } \
+
+ CLASS_LIST_NO_OBJECT(SNAPSHOT_WRITE)
+#undef SNAPSHOT_WRITE
+ default: break;
+ }
+ UNREACHABLE();
}
@@ -504,9 +725,12 @@
// Write out all the objects in the object store of the isolate which
// is the root set for all dart allocated objects at this point.
- SnapshotWriterVisitor visitor(this);
+ SnapshotWriterVisitor visitor(this, false);
object_store->VisitObjectPointers(&visitor);
+ // Write out all forwarded objects.
+ WriteForwardedObjects();
+
// Finalize the snapshot buffer.
FinalizeBuffer();
}
@@ -523,7 +747,7 @@
}
-intptr_t SnapshotWriter::MarkObject(RawObject* raw) {
+intptr_t SnapshotWriter::MarkObject(RawObject* raw, SerializeState state) {
NoGCScope no_gc;
intptr_t object_id = forward_list_.length() + kMaxPredefinedObjectIds;
ASSERT(object_id <= kMaxObjectId);
@@ -532,13 +756,22 @@
value = SerializedHeaderData::update(object_id, value);
uword tags = raw->ptr()->tags_;
raw->ptr()->tags_ = value;
- ForwardObjectNode* node = new ForwardObjectNode(raw, tags);
+ ForwardObjectNode* node = new ForwardObjectNode(raw, tags, state);
ASSERT(node != NULL);
forward_list_.Add(node);
return object_id;
}
+void SnapshotWriter::UnmarkAll() {
+ NoGCScope no_gc;
+ for (intptr_t i = 0; i < forward_list_.length(); i++) {
+ RawObject* raw = forward_list_[i]->raw();
+ raw->ptr()->tags_ = forward_list_[i]->tags(); // Restore original tags.
+ }
+}
+
+
bool SnapshotWriter::CheckAndWritePredefinedObject(RawObject* rawobj) {
// Check if object can be written in one of the following ways:
// - Smi: the Smi value is written as is (last bit is not tagged).
@@ -603,30 +836,51 @@
}
}
+ return false;
+}
+
+
+void SnapshotWriter::WriteObjectImpl(RawObject* raw) {
+ // First check if object can be written as a simple predefined type.
+ if (CheckAndWritePredefinedObject(raw)) {
+ return;
+ }
+
// Check if object has already been serialized, in that
// case just write the object id out.
- uword tags = rawobj->ptr()->tags_;
+ uword tags = raw->ptr()->tags_;
if (SerializedHeaderTag::decode(tags) == kObjectId) {
intptr_t id = SerializedHeaderData::decode(tags);
WriteIndexedObject(id);
- return true;
+ return;
}
- return false;
+ // Object is being serialized, add it to the forward ref list and mark
+ // it so that future references to this object in the snapshot will use
+ // an object id, instead of trying to serialize it again.
+ MarkObject(raw, kIsSerialized);
+
+ WriteInlinedObject(raw);
}
void SnapshotWriter::WriteInlinedObject(RawObject* raw) {
+ // Assert object is not a simple predefined type.
+ ASSERT(!CheckAndWritePredefinedObject(raw));
+
+ // Now write the object out inline in the stream as follows:
+ // - Object is seen for the first time (inlined as follows):
+ // (object size in multiples of kObjectAlignment | 0x1)
+ // serialized fields of the object
+ // ......
NoGCScope no_gc;
uword tags = raw->ptr()->tags_;
+ ASSERT(SerializedHeaderTag::decode(tags) == kObjectId);
+ intptr_t object_id = SerializedHeaderData::decode(tags);
+ tags = forward_list_[object_id - kMaxPredefinedObjectIds]->tags();
RawClass* cls = class_table_->At(RawObject::ClassIdTag::decode(tags));
+ ObjectKind kind = cls->ptr()->instance_kind_;
- // Object is being serialized, add it to the forward ref list and mark
- // it so that future references to this object in the snapshot will use
- // an object id, instead of trying to serialize it again.
- intptr_t object_id = MarkObject(raw);
-
- ObjectKind kind = cls->ptr()->instance_kind_;
if (kind == Instance::kInstanceKind) {
// Object is regular dart instance.
// TODO(5411462): figure out what we need to do if an object with native
@@ -645,12 +899,12 @@
WriteIntptrValue(tags);
// Write out the class information for this object.
- WriteObject(cls);
+ WriteObjectImpl(cls);
// Write out all the fields for the object.
intptr_t offset = Object::InstanceSize();
while (offset < instance_size) {
- WriteObject(*reinterpret_cast<RawObject**>(
+ WriteObjectRef(*reinterpret_cast<RawObject**>(
reinterpret_cast<uword>(raw->ptr()) + offset));
offset += kWordSize;
}
@@ -672,6 +926,25 @@
}
+void SnapshotWriter::WriteForwardedObjects() {
+ // Write out all objects that were added to the forward list and have
+ // not been serialized yet. These would typically be fields of instance
+ // objects, arrays or immutable arrays (this is done in order to avoid
+ // deep recursive calls to WriteObjectImpl).
+ // NOTE: The forward list might grow as we process the list.
+ for (intptr_t i = 0; i < forward_list_.length(); i++) {
+ if (!forward_list_[i]->is_serialized()) {
+ // Write the object out in the stream.
+ RawObject* raw = forward_list_[i]->raw();
+ WriteInlinedObject(raw);
+
+ // Mark object as serialized.
+ forward_list_[i]->set_state(kIsSerialized);
+ }
+ }
+}
+
+
void SnapshotWriter::WriteClassId(RawClass* cls) {
ASSERT(kind_ != Snapshot::kFull);
int id = object_store()->GetClassIndex(cls);
@@ -681,17 +954,44 @@
// TODO(5411462): Should restrict this to only core-lib classes in this
// case.
// Write out the class and tags information.
- WriteObjectHeader(Object::kClassClass, cls->ptr()->tags_);
+ WriteObjectHeader(Object::kClassClass, GetObjectTags(cls));
// Write out the library url and class name.
RawLibrary* library = cls->ptr()->library_;
ASSERT(library != Library::null());
- WriteObject(library->ptr()->url_);
- WriteObject(cls->ptr()->name_);
+ WriteObjectImpl(library->ptr()->url_);
+ WriteObjectImpl(cls->ptr()->name_);
}
}
+void SnapshotWriter::ArrayWriteTo(intptr_t object_id,
+ intptr_t array_kind,
+ intptr_t tags,
+ RawSmi* length,
+ RawAbstractTypeArguments* type_arguments,
+ RawObject* data[]) {
+ intptr_t len = Smi::Value(length);
+
+ // Write out the serialization header value for this object.
+ WriteSerializationMarker(kInlined, object_id);
+
+ // Write out the class and tags information.
+ WriteObjectHeader(array_kind, tags);
+
+ // Write out the length field.
+ Write<RawObject*>(length);
+
+ // Write out the type arguments.
+ WriteObjectImpl(type_arguments);
+
+ // Write out the individual object ids.
+ for (intptr_t i = 0; i < len; i++) {
+ WriteObjectRef(data[i]);
+ }
+}
+
+
void ScriptSnapshotWriter::WriteScriptSnapshot(const Library& lib) {
ASSERT(kind() == Snapshot::kScript);
@@ -706,7 +1006,11 @@
void SnapshotWriterVisitor::VisitPointers(RawObject** first, RawObject** last) {
for (RawObject** current = first; current <= last; current++) {
RawObject* raw_obj = *current;
- writer_->WriteObject(raw_obj);
+ if (as_references_) {
+ writer_->WriteObjectRef(raw_obj);
+ } else {
+ writer_->WriteObjectImpl(raw_obj);
+ }
}
}
« no previous file with comments | « vm/snapshot.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698