OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include "vm/object_graph.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "vm/dart.h" | |
10 #include "vm/isolate.h" | |
11 #include "vm/object.h" | |
12 #include "vm/raw_object.h" | |
13 #include "vm/visitor.h" | |
14 | |
15 namespace dart { | |
16 | |
17 // The state of a pre-order, depth-first traversal of an object graph. | |
18 // When a node is visited, *all* its children are pushed to the stack at once. | |
19 // We insert a sentinel between the node and its children on the stack, to | |
20 // remember that the node has been visited. The node is kept on the stack while | |
21 // its children are processed, to give the visitor a complete chain of parents. | |
22 // | |
23 // TODO(koda): Potential optimizations: | |
24 // - Linked chunks instead of std::vector. | |
25 // - Use smi/heap tag bit instead of full-word sentinel. | |
26 // - Extend RawObject with incremental iteration (one child at a time). | |
27 class ObjectGraph::Stack : public ObjectPointerVisitor { | |
28 public: | |
29 explicit Stack(Isolate* isolate) : ObjectPointerVisitor(isolate) { } | |
30 | |
31 // Marks and pushes. | |
32 virtual void VisitPointers(RawObject** first, RawObject** last) { | |
33 for (RawObject** current = first; current <= last; ++current) { | |
34 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { | |
35 (*current)->SetMarkBit(); | |
36 data_.push_back(*current); | |
37 } | |
38 } | |
39 } | |
40 | |
41 void Drain(ObjectGraph::Visitor* visitor) { | |
Cutch
2014/05/02 18:23:42
I would rename this to something like "VisitGraph"
koda
2014/05/02 18:51:34
Done.
| |
42 while (!data_.empty()) { | |
43 RawObject* obj = data_.back(); | |
44 if (obj == kSentinel) { | |
45 data_.pop_back(); | |
46 // The node below the sentinel has already been visited. | |
47 data_.pop_back(); | |
48 continue; | |
49 } | |
50 ASSERT(obj->IsHeapObject()); | |
51 data_.push_back(kSentinel); | |
52 StackIterator it(this, data_.size() - 2); | |
53 switch (visitor->VisitObject(&it)) { | |
54 case ObjectGraph::Visitor::kProceed: | |
55 obj->VisitPointers(this); | |
56 break; | |
57 case ObjectGraph::Visitor::kBacktrack: | |
58 break; | |
59 case ObjectGraph::Visitor::kAbort: | |
60 return; | |
61 } | |
62 } | |
63 } | |
64 | |
65 private: | |
66 static RawObject* const kSentinel; | |
67 std::vector<RawObject*> data_; | |
68 friend class StackIterator; | |
69 DISALLOW_COPY_AND_ASSIGN(Stack); | |
70 }; | |
71 | |
72 | |
73 // We only visit heap objects, so any Smi works as the sentinel. | |
74 RawObject* const ObjectGraph::Stack::kSentinel = Smi::New(0); | |
75 | |
76 | |
77 RawObject* ObjectGraph::StackIterator::Get() const { | |
78 return stack_->data_[index_]; | |
79 } | |
80 | |
81 | |
82 bool ObjectGraph::StackIterator::MoveToParent() { | |
83 // The parent is just below the next sentinel. | |
84 for (int i = index_; i >= 1; --i) { | |
85 if (stack_->data_[i] == Stack::kSentinel) { | |
86 index_ = i - 1; | |
87 return true; | |
88 } | |
89 } | |
90 return false; | |
91 } | |
92 | |
93 | |
94 class Unmarker : public ObjectVisitor { | |
95 public: | |
96 explicit Unmarker(Isolate* isolate) : ObjectVisitor(isolate) { } | |
97 | |
98 void VisitObject(RawObject* obj) { | |
99 if (obj->IsMarked()) { | |
100 obj->ClearMarkBit(); | |
101 } | |
102 } | |
103 | |
104 static void UnmarkAll(Isolate* isolate) { | |
105 Unmarker unmarker(isolate); | |
106 isolate->heap()->IterateObjects(&unmarker); | |
107 } | |
108 | |
109 private: | |
110 DISALLOW_COPY_AND_ASSIGN(Unmarker); | |
111 }; | |
112 | |
113 | |
114 ObjectGraph::ObjectGraph(Isolate* isolate) : isolate_(isolate) { | |
115 // The VM isolate has all its objects pre-marked, so iterating over it | |
116 // would be a no-op. | |
117 ASSERT(isolate_ != Dart::vm_isolate()); | |
118 isolate_->heap()->WriteProtectCode(false); | |
119 } | |
120 | |
121 | |
122 ObjectGraph::~ObjectGraph() { | |
123 isolate_->heap()->WriteProtectCode(true); | |
124 } | |
125 | |
126 | |
127 void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) { | |
128 Stack stack(isolate_); | |
129 isolate_->VisitObjectPointers(&stack, false, false); | |
130 stack.Drain(visitor); | |
131 Unmarker::UnmarkAll(isolate_); | |
132 } | |
133 | |
134 | |
135 void ObjectGraph::IterateObjectsFrom(RawObject* root, | |
136 ObjectGraph::Visitor* visitor) { | |
137 Stack stack(isolate_); | |
138 stack.VisitPointer(&root); | |
139 stack.Drain(visitor); | |
140 // TODO(koda): Optimize if we only visited a small subgraph. | |
141 Unmarker::UnmarkAll(isolate_); | |
142 } | |
143 | |
144 } // namespace dart | |
OLD | NEW |