Index: runtime/vm/object_graph.cc |
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc |
index c80c80c4f3e33e9b9c2c02b8b078a0718e42c728..2352bd8890964f3b687cbf8ffd50e8eec8ce826b 100644 |
--- a/runtime/vm/object_graph.cc |
+++ b/runtime/vm/object_graph.cc |
@@ -8,6 +8,7 @@ |
#include "vm/growable_array.h" |
#include "vm/isolate.h" |
#include "vm/object.h" |
+#include "vm/object_store.h" |
#include "vm/raw_object.h" |
#include "vm/reusable_handles.h" |
#include "vm/visitor.h" |
@@ -487,8 +488,13 @@ static void WritePtr(RawObject* raw, WriteStream* stream) { |
class WritePointerVisitor : public ObjectPointerVisitor { |
public: |
- WritePointerVisitor(Isolate* isolate, WriteStream* stream) |
- : ObjectPointerVisitor(isolate), stream_(stream), count_(0) {} |
+ WritePointerVisitor(Isolate* isolate, |
+ WriteStream* stream, |
+ bool only_instances) |
+ : ObjectPointerVisitor(isolate), |
+ stream_(stream), |
+ only_instances_(only_instances), |
+ count_(0) {} |
virtual void VisitPointers(RawObject** first, RawObject** last) { |
for (RawObject** current = first; current <= last; ++current) { |
RawObject* object = *current; |
@@ -498,6 +504,9 @@ class WritePointerVisitor : public ObjectPointerVisitor { |
// we'll need to encode which fields were omitted here. |
continue; |
} |
+ if (only_instances_ && (object->GetClassId() < kInstanceCid)) { |
+ continue; |
+ } |
WritePtr(object, stream_); |
++count_; |
} |
@@ -507,6 +516,7 @@ class WritePointerVisitor : public ObjectPointerVisitor { |
private: |
WriteStream* stream_; |
+ bool only_instances_; |
intptr_t count_; |
}; |
@@ -524,8 +534,13 @@ static void WriteHeader(RawObject* raw, |
class WriteGraphVisitor : public ObjectGraph::Visitor { |
public: |
- WriteGraphVisitor(Isolate* isolate, WriteStream* stream) |
- : stream_(stream), ptr_writer_(isolate, stream), count_(0) {} |
+ WriteGraphVisitor(Isolate* isolate, |
+ WriteStream* stream, |
+ ObjectGraph::SnapshotRoots roots) |
+ : stream_(stream), |
+ ptr_writer_(isolate, stream, roots == ObjectGraph::kUser), |
+ roots_(roots), |
+ count_(0) {} |
virtual Direction VisitObject(ObjectGraph::StackIterator* it) { |
RawObject* raw_obj = it->Get(); |
@@ -533,11 +548,13 @@ class WriteGraphVisitor : public ObjectGraph::Visitor { |
REUSABLE_OBJECT_HANDLESCOPE(thread); |
Object& obj = thread->ObjectHandle(); |
obj = raw_obj; |
- // Each object is a header + a zero-terminated list of its neighbors. |
- WriteHeader(raw_obj, raw_obj->Size(), obj.GetClassId(), stream_); |
- raw_obj->VisitPointers(&ptr_writer_); |
- stream_->WriteUnsigned(0); |
- ++count_; |
+ if ((roots_ == ObjectGraph::kVM) || obj.IsField() || obj.IsInstance()) { |
+ // Each object is a header + a zero-terminated list of its neighbors. |
+ WriteHeader(raw_obj, raw_obj->Size(), obj.GetClassId(), stream_); |
+ raw_obj->VisitPointers(&ptr_writer_); |
+ stream_->WriteUnsigned(0); |
+ ++count_; |
+ } |
return kProceed; |
} |
@@ -546,29 +563,98 @@ class WriteGraphVisitor : public ObjectGraph::Visitor { |
private: |
WriteStream* stream_; |
WritePointerVisitor ptr_writer_; |
+ ObjectGraph::SnapshotRoots roots_; |
intptr_t count_; |
}; |
-intptr_t ObjectGraph::Serialize(WriteStream* stream, bool collect_garbage) { |
+static void IterateUserFields(ObjectPointerVisitor* visitor) { |
+ Thread* thread = Thread::Current(); |
+ // Scope to prevent handles create here from appearing as stack references. |
+ HANDLESCOPE(thread); |
+ Zone* zone = thread->zone(); |
+ const GrowableObjectArray& libraries = GrowableObjectArray::Handle( |
+ zone, thread->isolate()->object_store()->libraries()); |
+ Library& library = Library::Handle(zone); |
+ Object& entry = Object::Handle(zone); |
+ Class& cls = Class::Handle(zone); |
+ Array& fields = Array::Handle(zone); |
+ Field& field = Field::Handle(zone); |
+ for (intptr_t i = 0; i < libraries.Length(); i++) { |
+ library ^= libraries.At(i); |
+ DictionaryIterator entries(library); |
+ while (entries.HasNext()) { |
+ entry = entries.GetNext(); |
+ if (entry.IsClass()) { |
+ cls ^= entry.raw(); |
+ fields = cls.fields(); |
+ for (intptr_t j = 0; j < fields.Length(); j++) { |
+ field ^= fields.At(j); |
+ RawObject* ptr = field.raw(); |
+ visitor->VisitPointer(&ptr); |
+ } |
+ } else if (entry.IsField()) { |
+ field ^= entry.raw(); |
+ RawObject* ptr = field.raw(); |
+ visitor->VisitPointer(&ptr); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+intptr_t ObjectGraph::Serialize(WriteStream* stream, |
+ SnapshotRoots roots, |
+ bool collect_garbage) { |
if (collect_garbage) { |
isolate()->heap()->CollectAllGarbage(); |
} |
// Current encoding assumes objects do not move, so promote everything to old. |
isolate()->heap()->new_space()->Evacuate(); |
- WriteGraphVisitor visitor(isolate(), stream); |
+ RawObject* kRootAddress = reinterpret_cast<RawObject*>(kHeapObjectTag); |
+ const intptr_t kRootCid = kIllegalCid; |
+ RawObject* kStackAddress = |
+ reinterpret_cast<RawObject*>(kObjectAlignment + kHeapObjectTag); |
+ |
stream->WriteUnsigned(kObjectAlignment); |
- stream->WriteUnsigned(0); |
- stream->WriteUnsigned(0); |
- stream->WriteUnsigned(0); |
- { |
- WritePointerVisitor ptr_writer(isolate(), stream); |
+ stream->WriteUnsigned(kStackCid); |
+ |
+ if (roots == kVM) { |
+ // Write root "object". |
+ WriteHeader(kRootAddress, 0, kRootCid, stream); |
+ WritePointerVisitor ptr_writer(isolate(), stream, false); |
isolate()->IterateObjectPointers(&ptr_writer, false); |
+ stream->WriteUnsigned(0); |
+ } else { |
+ { |
+ // Write root "object". |
+ WriteHeader(kRootAddress, 0, kRootCid, stream); |
+ WritePointerVisitor ptr_writer(isolate(), stream, false); |
+ IterateUserFields(&ptr_writer); |
+ WritePtr(kStackAddress, stream); |
+ stream->WriteUnsigned(0); |
+ } |
+ |
+ { |
+ // Write stack "object". |
+ WriteHeader(kStackAddress, 0, kStackCid, stream); |
+ WritePointerVisitor ptr_writer(isolate(), stream, true); |
+ isolate()->IterateStackPointers(&ptr_writer, false); |
+ stream->WriteUnsigned(0); |
+ } |
} |
- stream->WriteUnsigned(0); |
+ |
+ WriteGraphVisitor visitor(isolate(), stream, roots); |
IterateObjects(&visitor); |
- return visitor.count() + 1; // + root |
+ |
+ intptr_t object_count = visitor.count(); |
+ if (roots == kVM) { |
+ object_count += 1; // root |
+ } else { |
+ object_count += 2; // root and stack |
+ } |
+ return object_count; |
} |
} // namespace dart |