OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/object_graph.h" | 5 #include "vm/object_graph.h" |
6 | 6 |
7 #include "vm/dart.h" | 7 #include "vm/dart.h" |
8 #include "vm/growable_array.h" | 8 #include "vm/growable_array.h" |
9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
10 #include "vm/object.h" | 10 #include "vm/object.h" |
11 #include "vm/raw_object.h" | 11 #include "vm/raw_object.h" |
12 #include "vm/visitor.h" | 12 #include "vm/visitor.h" |
13 | 13 |
14 namespace dart { | 14 namespace dart { |
15 | 15 |
16 // The state of a pre-order, depth-first traversal of an object graph. | 16 // The state of a pre-order, depth-first traversal of an object graph. |
17 // When a node is visited, *all* its children are pushed to the stack at once. | 17 // When a node is visited, *all* its children are pushed to the stack at once. |
18 // We insert a sentinel between the node and its children on the stack, to | 18 // We insert a sentinel between the node and its children on the stack, to |
19 // remember that the node has been visited. The node is kept on the stack while | 19 // remember that the node has been visited. The node is kept on the stack while |
20 // its children are processed, to give the visitor a complete chain of parents. | 20 // its children are processed, to give the visitor a complete chain of parents. |
21 // | 21 // |
22 // TODO(koda): Potential optimizations: | 22 // TODO(koda): Potential optimizations: |
23 // - Linked chunks instead of std::vector. | 23 // - Use tag bits for compact Node and sentinel representations. |
24 // - Use smi/heap tag bit instead of full-word sentinel. | |
25 // - Extend RawObject with incremental iteration (one child at a time). | |
26 class ObjectGraph::Stack : public ObjectPointerVisitor { | 24 class ObjectGraph::Stack : public ObjectPointerVisitor { |
27 public: | 25 public: |
28 explicit Stack(Isolate* isolate) | 26 explicit Stack(Isolate* isolate) |
29 : ObjectPointerVisitor(isolate), data_(kInitialCapacity) { } | 27 : ObjectPointerVisitor(isolate), data_(kInitialCapacity) { } |
30 | 28 |
31 // Marks and pushes. Used to initialize this stack with roots. | 29 // Marks and pushes. Used to initialize this stack with roots. |
32 virtual void VisitPointers(RawObject** first, RawObject** last) { | 30 virtual void VisitPointers(RawObject** first, RawObject** last) { |
33 for (RawObject** current = first; current <= last; ++current) { | 31 for (RawObject** current = first; current <= last; ++current) { |
34 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { | 32 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { |
35 (*current)->SetMarkBit(); | 33 (*current)->SetMarkBit(); |
36 data_.Add(*current); | 34 Node node; |
| 35 node.ptr = current; |
| 36 node.obj = *current; |
| 37 data_.Add(node); |
37 } | 38 } |
38 } | 39 } |
39 } | 40 } |
40 | 41 |
41 // Traverses the object graph from the current state. | 42 // Traverses the object graph from the current state. |
42 void TraverseGraph(ObjectGraph::Visitor* visitor) { | 43 void TraverseGraph(ObjectGraph::Visitor* visitor) { |
43 while (!data_.is_empty()) { | 44 while (!data_.is_empty()) { |
44 RawObject* obj = data_.Last(); | 45 Node node = data_.Last(); |
45 if (obj == kSentinel) { | 46 if (node.ptr == kSentinel) { |
46 data_.RemoveLast(); | 47 data_.RemoveLast(); |
47 // The node below the sentinel has already been visited. | 48 // The node below the sentinel has already been visited. |
48 data_.RemoveLast(); | 49 data_.RemoveLast(); |
49 continue; | 50 continue; |
50 } | 51 } |
| 52 RawObject* obj = node.obj; |
51 ASSERT(obj->IsHeapObject()); | 53 ASSERT(obj->IsHeapObject()); |
52 data_.Add(kSentinel); | 54 Node sentinel; |
| 55 sentinel.ptr = kSentinel; |
| 56 data_.Add(sentinel); |
53 StackIterator it(this, data_.length() - 2); | 57 StackIterator it(this, data_.length() - 2); |
54 switch (visitor->VisitObject(&it)) { | 58 switch (visitor->VisitObject(&it)) { |
55 case ObjectGraph::Visitor::kProceed: | 59 case ObjectGraph::Visitor::kProceed: |
56 obj->VisitPointers(this); | 60 obj->VisitPointers(this); |
57 break; | 61 break; |
58 case ObjectGraph::Visitor::kBacktrack: | 62 case ObjectGraph::Visitor::kBacktrack: |
59 break; | 63 break; |
60 case ObjectGraph::Visitor::kAbort: | 64 case ObjectGraph::Visitor::kAbort: |
61 return; | 65 return; |
62 } | 66 } |
63 } | 67 } |
64 } | 68 } |
65 | 69 |
66 private: | 70 private: |
67 static RawObject* const kSentinel; | 71 struct Node { |
| 72 RawObject** ptr; // kSentinel for the sentinel node. |
| 73 RawObject* obj; |
| 74 }; |
| 75 |
| 76 static RawObject** const kSentinel; |
68 static const intptr_t kInitialCapacity = 1024; | 77 static const intptr_t kInitialCapacity = 1024; |
69 GrowableArray<RawObject*> data_; | 78 static const intptr_t kNoParent = -1; |
| 79 |
| 80 intptr_t Parent(intptr_t index) const { |
| 81 // The parent is just below the next sentinel. |
| 82 for (intptr_t i = index; i >= 1; --i) { |
| 83 if (data_[i].ptr == kSentinel) { |
| 84 return i - 1; |
| 85 } |
| 86 } |
| 87 return kNoParent; |
| 88 } |
| 89 |
| 90 GrowableArray<Node> data_; |
70 friend class StackIterator; | 91 friend class StackIterator; |
71 DISALLOW_COPY_AND_ASSIGN(Stack); | 92 DISALLOW_COPY_AND_ASSIGN(Stack); |
72 }; | 93 }; |
73 | 94 |
74 | 95 |
75 // We only visit heap objects, so any Smi works as the sentinel. | 96 RawObject** const ObjectGraph::Stack::kSentinel = NULL; |
76 RawObject* const ObjectGraph::Stack::kSentinel = Smi::New(0); | |
77 | 97 |
78 | 98 |
79 RawObject* ObjectGraph::StackIterator::Get() const { | 99 RawObject* ObjectGraph::StackIterator::Get() const { |
80 return stack_->data_[index_]; | 100 return stack_->data_[index_].obj; |
81 } | 101 } |
82 | 102 |
83 | 103 |
84 bool ObjectGraph::StackIterator::MoveToParent() { | 104 bool ObjectGraph::StackIterator::MoveToParent() { |
85 // The parent is just below the next sentinel. | 105 intptr_t parent = stack_->Parent(index_); |
86 for (int i = index_; i >= 1; --i) { | 106 if (parent == Stack::kNoParent) { |
87 if (stack_->data_[i] == Stack::kSentinel) { | 107 return false; |
88 index_ = i - 1; | 108 } else { |
89 return true; | 109 index_ = parent; |
90 } | 110 return true; |
91 } | 111 } |
92 return false; | 112 } |
| 113 |
| 114 |
| 115 intptr_t ObjectGraph::StackIterator::OffsetFromParentInWords() const { |
| 116 intptr_t parent_index = stack_->Parent(index_); |
| 117 if (parent_index == Stack::kNoParent) { |
| 118 return -1; |
| 119 } |
| 120 Stack::Node parent = stack_->data_[parent_index]; |
| 121 uword parent_start = RawObject::ToAddr(parent.obj); |
| 122 Stack::Node child = stack_->data_[index_]; |
| 123 ASSERT(child.obj == *child.ptr); |
| 124 uword child_ptr_addr = reinterpret_cast<uword>(child.ptr); |
| 125 intptr_t offset = child_ptr_addr - parent_start; |
| 126 if (offset > 0 && offset < parent.obj->Size()) { |
| 127 ASSERT(Utils::IsAligned(offset, kWordSize)); |
| 128 return offset >> kWordSizeLog2; |
| 129 } else { |
| 130 // Some internal VM objects visit pointers not contained within the parent. |
| 131 // For instance, RawCode::VisitCodePointers visits pointers in instructions. |
| 132 ASSERT(!parent.obj->IsDartInstance()); |
| 133 return -1; |
| 134 } |
93 } | 135 } |
94 | 136 |
95 | 137 |
96 class Unmarker : public ObjectVisitor { | 138 class Unmarker : public ObjectVisitor { |
97 public: | 139 public: |
98 explicit Unmarker(Isolate* isolate) : ObjectVisitor(isolate) { } | 140 explicit Unmarker(Isolate* isolate) : ObjectVisitor(isolate) { } |
99 | 141 |
100 void VisitObject(RawObject* obj) { | 142 void VisitObject(RawObject* obj) { |
101 if (obj->IsMarked()) { | 143 if (obj->IsMarked()) { |
102 obj->ClearMarkBit(); | 144 obj->ClearMarkBit(); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 } | 259 } |
218 | 260 |
219 intptr_t length() const { return length_; } | 261 intptr_t length() const { return length_; } |
220 | 262 |
221 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { | 263 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { |
222 if (it->Get() != obj_) { | 264 if (it->Get() != obj_) { |
223 return kProceed; | 265 return kProceed; |
224 } else { | 266 } else { |
225 HANDLESCOPE(Isolate::Current()); | 267 HANDLESCOPE(Isolate::Current()); |
226 Object& current = Object::Handle(); | 268 Object& current = Object::Handle(); |
| 269 Smi& offset_from_parent = Smi::Handle(); |
227 do { | 270 do { |
228 if (!path_.IsNull() && length_ < path_.Length()) { | 271 intptr_t obj_index = length_ * 2; |
| 272 intptr_t offset_index = obj_index + 1; |
| 273 if (!path_.IsNull() && offset_index < path_.Length()) { |
229 current = it->Get(); | 274 current = it->Get(); |
230 path_.SetAt(length_, current); | 275 path_.SetAt(obj_index, current); |
| 276 offset_from_parent = Smi::New(it->OffsetFromParentInWords()); |
| 277 path_.SetAt(offset_index, offset_from_parent); |
231 } | 278 } |
232 ++length_; | 279 ++length_; |
233 } while (it->MoveToParent()); | 280 } while (it->MoveToParent()); |
234 return kAbort; | 281 return kAbort; |
235 } | 282 } |
236 } | 283 } |
237 | 284 |
238 private: | 285 private: |
239 RawObject* obj_; | 286 RawObject* obj_; |
240 const Array& path_; | 287 const Array& path_; |
241 intptr_t length_; | 288 intptr_t length_; |
242 }; | 289 }; |
243 | 290 |
244 | 291 |
245 intptr_t ObjectGraph::RetainingPath(Object* obj, const Array& path) { | 292 intptr_t ObjectGraph::RetainingPath(Object* obj, const Array& path) { |
246 NoGCScope no_gc_scope_; | 293 NoGCScope no_gc_scope_; |
247 // To break the trivial path, the handle 'obj' is temporarily cleared during | 294 // To break the trivial path, the handle 'obj' is temporarily cleared during |
248 // the search, but restored before returning. | 295 // the search, but restored before returning. |
249 RawObject* raw = obj->raw(); | 296 RawObject* raw = obj->raw(); |
250 *obj = Object::null(); | 297 *obj = Object::null(); |
251 RetainingPathVisitor visitor(raw, path); | 298 RetainingPathVisitor visitor(raw, path); |
252 IterateObjects(&visitor); | 299 IterateObjects(&visitor); |
253 *obj = raw; | 300 *obj = raw; |
254 return visitor.length(); | 301 return visitor.length(); |
255 } | 302 } |
256 | 303 |
257 } // namespace dart | 304 } // namespace dart |
OLD | NEW |