Index: runtime/vm/object_graph.cc |
=================================================================== |
--- runtime/vm/object_graph.cc (revision 37949) |
+++ runtime/vm/object_graph.cc (working copy) |
@@ -20,9 +20,7 @@ |
// its children are processed, to give the visitor a complete chain of parents. |
// |
// TODO(koda): Potential optimizations: |
-// - Linked chunks instead of std::vector. |
-// - Use smi/heap tag bit instead of full-word sentinel. |
-// - Extend RawObject with incremental iteration (one child at a time). |
+// - Use tag bits for compact Node and sentinel representations. |
class ObjectGraph::Stack : public ObjectPointerVisitor { |
public: |
explicit Stack(Isolate* isolate) |
@@ -33,7 +31,10 @@ |
for (RawObject** current = first; current <= last; ++current) { |
if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { |
(*current)->SetMarkBit(); |
- data_.Add(*current); |
+ Node node; |
+ node.ptr = current; |
+ node.obj = *current; |
+ data_.Add(node); |
} |
} |
} |
@@ -41,15 +42,18 @@ |
// Traverses the object graph from the current state. |
void TraverseGraph(ObjectGraph::Visitor* visitor) { |
while (!data_.is_empty()) { |
- RawObject* obj = data_.Last(); |
- if (obj == kSentinel) { |
+ Node node = data_.Last(); |
+ if (node.ptr == kSentinel) { |
data_.RemoveLast(); |
// The node below the sentinel has already been visited. |
data_.RemoveLast(); |
continue; |
} |
+ RawObject* obj = node.obj; |
ASSERT(obj->IsHeapObject()); |
- data_.Add(kSentinel); |
+ Node sentinel; |
+ sentinel.ptr = kSentinel; |
+ data_.Add(sentinel); |
StackIterator it(this, data_.length() - 2); |
switch (visitor->VisitObject(&it)) { |
case ObjectGraph::Visitor::kProceed: |
@@ -64,35 +68,73 @@ |
} |
private: |
- static RawObject* const kSentinel; |
+ struct Node { |
+ RawObject** ptr; // kSentinel for the sentinel node. |
+ RawObject* obj; |
+ }; |
+ |
+ static RawObject** const kSentinel; |
static const intptr_t kInitialCapacity = 1024; |
- GrowableArray<RawObject*> data_; |
+ static const intptr_t kNoParent = -1; |
+ |
+ intptr_t Parent(intptr_t index) const { |
+ // The parent is just below the next sentinel. |
+ for (intptr_t i = index; i >= 1; --i) { |
+ if (data_[i].ptr == kSentinel) { |
+ return i - 1; |
+ } |
+ } |
+ return kNoParent; |
+ } |
+ |
+ GrowableArray<Node> data_; |
friend class StackIterator; |
DISALLOW_COPY_AND_ASSIGN(Stack); |
}; |
-// We only visit heap objects, so any Smi works as the sentinel. |
-RawObject* const ObjectGraph::Stack::kSentinel = Smi::New(0); |
+RawObject** const ObjectGraph::Stack::kSentinel = NULL; |
RawObject* ObjectGraph::StackIterator::Get() const { |
- return stack_->data_[index_]; |
+ return stack_->data_[index_].obj; |
} |
bool ObjectGraph::StackIterator::MoveToParent() { |
- // The parent is just below the next sentinel. |
- for (int i = index_; i >= 1; --i) { |
- if (stack_->data_[i] == Stack::kSentinel) { |
- index_ = i - 1; |
- return true; |
- } |
+ intptr_t parent = stack_->Parent(index_); |
+ if (parent == Stack::kNoParent) { |
+ return false; |
+ } else { |
+ index_ = parent; |
+ return true; |
} |
- return false; |
} |
+intptr_t ObjectGraph::StackIterator::OffsetFromParentInWords() const { |
+ intptr_t parent_index = stack_->Parent(index_); |
+ if (parent_index == Stack::kNoParent) { |
+ return -1; |
+ } |
+ Stack::Node parent = stack_->data_[parent_index]; |
+ uword parent_start = RawObject::ToAddr(parent.obj); |
+ Stack::Node child = stack_->data_[index_]; |
+ ASSERT(child.obj == *child.ptr); |
+ uword child_ptr_addr = reinterpret_cast<uword>(child.ptr); |
+ intptr_t offset = child_ptr_addr - parent_start; |
+ if (offset > 0 && offset < parent.obj->Size()) { |
+ ASSERT(Utils::IsAligned(offset, kWordSize)); |
+ return offset >> kWordSizeLog2; |
+ } else { |
+ // Some internal VM objects visit pointers not contained within the parent. |
+ // For instance, RawCode::VisitCodePointers visits pointers in instructions. |
+ ASSERT(!parent.obj->IsDartInstance()); |
+ return -1; |
+ } |
+} |
+ |
+ |
class Unmarker : public ObjectVisitor { |
public: |
explicit Unmarker(Isolate* isolate) : ObjectVisitor(isolate) { } |
@@ -224,10 +266,15 @@ |
} else { |
HANDLESCOPE(Isolate::Current()); |
Object& current = Object::Handle(); |
+ Smi& offset_from_parent = Smi::Handle(); |
do { |
- if (!path_.IsNull() && length_ < path_.Length()) { |
+ intptr_t obj_index = length_ * 2; |
+ intptr_t offset_index = obj_index + 1; |
+ if (!path_.IsNull() && offset_index < path_.Length()) { |
current = it->Get(); |
- path_.SetAt(length_, current); |
+ path_.SetAt(obj_index, current); |
+ offset_from_parent = Smi::New(it->OffsetFromParentInWords()); |
+ path_.SetAt(offset_index, offset_from_parent); |
} |
++length_; |
} while (it->MoveToParent()); |