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> | |
Ivan Posva
2014/05/02 21:20:53
Please use a GrowableArray here.
koda
2014/05/02 21:31:40
Done.
| |
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. Used to initialize this stack with roots. | |
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 // Traverses the object graph from the current state. | |
42 void TraverseGraph(ObjectGraph::Visitor* visitor) { | |
43 while (!data_.empty()) { | |
44 RawObject* obj = data_.back(); | |
45 if (obj == kSentinel) { | |
46 data_.pop_back(); | |
47 // The node below the sentinel has already been visited. | |
48 data_.pop_back(); | |
49 continue; | |
50 } | |
51 ASSERT(obj->IsHeapObject()); | |
52 data_.push_back(kSentinel); | |
53 StackIterator it(this, data_.size() - 2); | |
54 switch (visitor->VisitObject(&it)) { | |
55 case ObjectGraph::Visitor::kProceed: | |
56 obj->VisitPointers(this); | |
57 break; | |
58 case ObjectGraph::Visitor::kBacktrack: | |
59 break; | |
60 case ObjectGraph::Visitor::kAbort: | |
61 return; | |
62 } | |
63 } | |
64 } | |
65 | |
66 private: | |
67 static RawObject* const kSentinel; | |
68 std::vector<RawObject*> data_; | |
69 friend class StackIterator; | |
70 DISALLOW_COPY_AND_ASSIGN(Stack); | |
71 }; | |
72 | |
73 | |
74 // We only visit heap objects, so any Smi works as the sentinel. | |
75 RawObject* const ObjectGraph::Stack::kSentinel = Smi::New(0); | |
76 | |
77 | |
78 RawObject* ObjectGraph::StackIterator::Get() const { | |
79 return stack_->data_[index_]; | |
80 } | |
81 | |
82 | |
83 bool ObjectGraph::StackIterator::MoveToParent() { | |
84 // The parent is just below the next sentinel. | |
85 for (int i = index_; i >= 1; --i) { | |
86 if (stack_->data_[i] == Stack::kSentinel) { | |
87 index_ = i - 1; | |
88 return true; | |
89 } | |
90 } | |
91 return false; | |
92 } | |
93 | |
94 | |
95 class Unmarker : public ObjectVisitor { | |
96 public: | |
97 explicit Unmarker(Isolate* isolate) : ObjectVisitor(isolate) { } | |
98 | |
99 void VisitObject(RawObject* obj) { | |
100 if (obj->IsMarked()) { | |
101 obj->ClearMarkBit(); | |
102 } | |
103 } | |
104 | |
105 static void UnmarkAll(Isolate* isolate) { | |
106 Unmarker unmarker(isolate); | |
107 isolate->heap()->IterateObjects(&unmarker); | |
108 } | |
109 | |
110 private: | |
111 DISALLOW_COPY_AND_ASSIGN(Unmarker); | |
112 }; | |
113 | |
114 | |
115 ObjectGraph::ObjectGraph(Isolate* isolate) : isolate_(isolate) { | |
116 // The VM isolate has all its objects pre-marked, so iterating over it | |
117 // would be a no-op. | |
118 ASSERT(isolate_ != Dart::vm_isolate()); | |
119 isolate_->heap()->WriteProtectCode(false); | |
120 } | |
121 | |
122 | |
123 ObjectGraph::~ObjectGraph() { | |
124 isolate_->heap()->WriteProtectCode(true); | |
125 } | |
126 | |
127 | |
128 void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) { | |
129 NoGCScope no_gc_scope_; | |
130 Stack stack(isolate_); | |
131 isolate_->VisitObjectPointers(&stack, false, false); | |
132 stack.TraverseGraph(visitor); | |
133 Unmarker::UnmarkAll(isolate_); | |
134 } | |
135 | |
136 | |
137 void ObjectGraph::IterateObjectsFrom(const Object& root, | |
138 ObjectGraph::Visitor* visitor) { | |
139 NoGCScope no_gc_scope_; | |
140 Stack stack(isolate_); | |
141 RawObject* root_raw = root.raw(); | |
142 stack.VisitPointer(&root_raw); | |
143 stack.TraverseGraph(visitor); | |
144 // TODO(koda): Optimize if we only visited a small subgraph. | |
145 Unmarker::UnmarkAll(isolate_); | |
146 } | |
147 | |
148 } // namespace dart | |
OLD | NEW |