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/object_store.h" | 11 #include "vm/object_store.h" |
12 #include "vm/raw_object.h" | 12 #include "vm/raw_object.h" |
13 #include "vm/reusable_handles.h" | 13 #include "vm/reusable_handles.h" |
14 #include "vm/visitor.h" | 14 #include "vm/visitor.h" |
15 | 15 |
16 namespace dart { | 16 namespace dart { |
17 | 17 |
18 // The state of a pre-order, depth-first traversal of an object graph. | 18 // The state of a pre-order, depth-first traversal of an object graph. |
19 // When a node is visited, *all* its children are pushed to the stack at once. | 19 // When a node is visited, *all* its children are pushed to the stack at once. |
20 // We insert a sentinel between the node and its children on the stack, to | 20 // We insert a sentinel between the node and its children on the stack, to |
21 // remember that the node has been visited. The node is kept on the stack while | 21 // remember that the node has been visited. The node is kept on the stack while |
22 // its children are processed, to give the visitor a complete chain of parents. | 22 // its children are processed, to give the visitor a complete chain of parents. |
23 // | 23 // |
24 // TODO(koda): Potential optimizations: | 24 // TODO(koda): Potential optimizations: |
25 // - Use tag bits for compact Node and sentinel representations. | 25 // - Use tag bits for compact Node and sentinel representations. |
26 class ObjectGraph::Stack : public ObjectPointerVisitor { | 26 class ObjectGraph::Stack : public ObjectPointerVisitor { |
27 public: | 27 public: |
28 explicit Stack(Isolate* isolate) | 28 explicit Stack(Isolate* isolate) |
29 : ObjectPointerVisitor(isolate), data_(kInitialCapacity) {} | 29 : ObjectPointerVisitor(isolate), |
| 30 include_vm_objects_(true), |
| 31 data_(kInitialCapacity) {} |
30 | 32 |
31 // Marks and pushes. Used to initialize this stack with roots. | 33 // Marks and pushes. Used to initialize this stack with roots. |
32 virtual void VisitPointers(RawObject** first, RawObject** last) { | 34 virtual void VisitPointers(RawObject** first, RawObject** last) { |
33 for (RawObject** current = first; current <= last; ++current) { | 35 for (RawObject** current = first; current <= last; ++current) { |
34 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { | 36 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { |
| 37 if (!include_vm_objects_) { |
| 38 intptr_t cid = (*current)->GetClassId(); |
| 39 if ((cid < kInstanceCid) && (cid != kContextCid) && |
| 40 (cid != kFieldCid)) { |
| 41 continue; |
| 42 } |
| 43 } |
35 (*current)->SetMarkBit(); | 44 (*current)->SetMarkBit(); |
36 Node node; | 45 Node node; |
37 node.ptr = current; | 46 node.ptr = current; |
38 node.obj = *current; | 47 node.obj = *current; |
39 data_.Add(node); | 48 data_.Add(node); |
40 } | 49 } |
41 } | 50 } |
42 } | 51 } |
43 | 52 |
44 // Traverses the object graph from the current state. | 53 // Traverses the object graph from the current state. |
(...skipping 17 matching lines...) Expand all Loading... |
62 obj->VisitPointers(this); | 71 obj->VisitPointers(this); |
63 break; | 72 break; |
64 case ObjectGraph::Visitor::kBacktrack: | 73 case ObjectGraph::Visitor::kBacktrack: |
65 break; | 74 break; |
66 case ObjectGraph::Visitor::kAbort: | 75 case ObjectGraph::Visitor::kAbort: |
67 return; | 76 return; |
68 } | 77 } |
69 } | 78 } |
70 } | 79 } |
71 | 80 |
| 81 bool include_vm_objects_; |
| 82 |
72 private: | 83 private: |
73 struct Node { | 84 struct Node { |
74 RawObject** ptr; // kSentinel for the sentinel node. | 85 RawObject** ptr; // kSentinel for the sentinel node. |
75 RawObject* obj; | 86 RawObject* obj; |
76 }; | 87 }; |
77 | 88 |
78 static RawObject** const kSentinel; | 89 static RawObject** const kSentinel; |
79 static const intptr_t kInitialCapacity = 1024; | 90 static const intptr_t kInitialCapacity = 1024; |
80 static const intptr_t kNoParent = -1; | 91 static const intptr_t kNoParent = -1; |
81 | 92 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 | 155 |
145 static void UnmarkAll(Isolate* isolate) { | 156 static void UnmarkAll(Isolate* isolate) { |
146 Unmarker unmarker; | 157 Unmarker unmarker; |
147 isolate->heap()->VisitObjectsNoImagePages(&unmarker); | 158 isolate->heap()->VisitObjectsNoImagePages(&unmarker); |
148 } | 159 } |
149 | 160 |
150 private: | 161 private: |
151 DISALLOW_COPY_AND_ASSIGN(Unmarker); | 162 DISALLOW_COPY_AND_ASSIGN(Unmarker); |
152 }; | 163 }; |
153 | 164 |
| 165 static void IterateUserFields(ObjectPointerVisitor* visitor) { |
| 166 Thread* thread = Thread::Current(); |
| 167 // Scope to prevent handles create here from appearing as stack references. |
| 168 HANDLESCOPE(thread); |
| 169 Zone* zone = thread->zone(); |
| 170 const GrowableObjectArray& libraries = GrowableObjectArray::Handle( |
| 171 zone, thread->isolate()->object_store()->libraries()); |
| 172 Library& library = Library::Handle(zone); |
| 173 Object& entry = Object::Handle(zone); |
| 174 Class& cls = Class::Handle(zone); |
| 175 Array& fields = Array::Handle(zone); |
| 176 Field& field = Field::Handle(zone); |
| 177 for (intptr_t i = 0; i < libraries.Length(); i++) { |
| 178 library ^= libraries.At(i); |
| 179 DictionaryIterator entries(library); |
| 180 while (entries.HasNext()) { |
| 181 entry = entries.GetNext(); |
| 182 if (entry.IsClass()) { |
| 183 cls ^= entry.raw(); |
| 184 fields = cls.fields(); |
| 185 for (intptr_t j = 0; j < fields.Length(); j++) { |
| 186 field ^= fields.At(j); |
| 187 RawObject* ptr = field.raw(); |
| 188 visitor->VisitPointer(&ptr); |
| 189 } |
| 190 } else if (entry.IsField()) { |
| 191 field ^= entry.raw(); |
| 192 RawObject* ptr = field.raw(); |
| 193 visitor->VisitPointer(&ptr); |
| 194 } |
| 195 } |
| 196 } |
| 197 } |
| 198 |
154 ObjectGraph::ObjectGraph(Thread* thread) : StackResource(thread) { | 199 ObjectGraph::ObjectGraph(Thread* thread) : StackResource(thread) { |
155 // The VM isolate has all its objects pre-marked, so iterating over it | 200 // The VM isolate has all its objects pre-marked, so iterating over it |
156 // would be a no-op. | 201 // would be a no-op. |
157 ASSERT(thread->isolate() != Dart::vm_isolate()); | 202 ASSERT(thread->isolate() != Dart::vm_isolate()); |
158 } | 203 } |
159 | 204 |
160 ObjectGraph::~ObjectGraph() {} | 205 ObjectGraph::~ObjectGraph() {} |
161 | 206 |
162 void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) { | 207 void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) { |
163 NoSafepointScope no_safepoint_scope_; | 208 NoSafepointScope no_safepoint_scope_; |
164 Stack stack(isolate()); | 209 Stack stack(isolate()); |
165 isolate()->VisitObjectPointers(&stack, false); | 210 isolate()->VisitObjectPointers(&stack, false); |
166 stack.TraverseGraph(visitor); | 211 stack.TraverseGraph(visitor); |
167 Unmarker::UnmarkAll(isolate()); | 212 Unmarker::UnmarkAll(isolate()); |
168 } | 213 } |
169 | 214 |
| 215 void ObjectGraph::IterateUserObjects(ObjectGraph::Visitor* visitor) { |
| 216 NoSafepointScope no_safepoint_scope_; |
| 217 Stack stack(isolate()); |
| 218 IterateUserFields(&stack); |
| 219 stack.include_vm_objects_ = false; |
| 220 stack.TraverseGraph(visitor); |
| 221 Unmarker::UnmarkAll(isolate()); |
| 222 } |
| 223 |
170 void ObjectGraph::IterateObjectsFrom(const Object& root, | 224 void ObjectGraph::IterateObjectsFrom(const Object& root, |
171 ObjectGraph::Visitor* visitor) { | 225 ObjectGraph::Visitor* visitor) { |
172 NoSafepointScope no_safepoint_scope_; | 226 NoSafepointScope no_safepoint_scope_; |
173 Stack stack(isolate()); | 227 Stack stack(isolate()); |
174 RawObject* root_raw = root.raw(); | 228 RawObject* root_raw = root.raw(); |
175 stack.VisitPointer(&root_raw); | 229 stack.VisitPointer(&root_raw); |
176 stack.TraverseGraph(visitor); | 230 stack.TraverseGraph(visitor); |
177 Unmarker::UnmarkAll(isolate()); | 231 Unmarker::UnmarkAll(isolate()); |
178 } | 232 } |
179 | 233 |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 }; | 424 }; |
371 | 425 |
372 intptr_t ObjectGraph::RetainingPath(Object* obj, const Array& path) { | 426 intptr_t ObjectGraph::RetainingPath(Object* obj, const Array& path) { |
373 NoSafepointScope no_safepoint_scope_; | 427 NoSafepointScope no_safepoint_scope_; |
374 HeapIterationScope iteration_scope(true); | 428 HeapIterationScope iteration_scope(true); |
375 // To break the trivial path, the handle 'obj' is temporarily cleared during | 429 // To break the trivial path, the handle 'obj' is temporarily cleared during |
376 // the search, but restored before returning. | 430 // the search, but restored before returning. |
377 RawObject* raw = obj->raw(); | 431 RawObject* raw = obj->raw(); |
378 *obj = Object::null(); | 432 *obj = Object::null(); |
379 RetainingPathVisitor visitor(raw, path); | 433 RetainingPathVisitor visitor(raw, path); |
380 IterateObjects(&visitor); | 434 IterateUserObjects(&visitor); |
| 435 if (visitor.length() == 0) { |
| 436 IterateObjects(&visitor); |
| 437 } |
381 *obj = raw; | 438 *obj = raw; |
382 return visitor.length(); | 439 return visitor.length(); |
383 } | 440 } |
384 | 441 |
385 class InboundReferencesVisitor : public ObjectVisitor, | 442 class InboundReferencesVisitor : public ObjectVisitor, |
386 public ObjectPointerVisitor { | 443 public ObjectPointerVisitor { |
387 public: | 444 public: |
388 // We cannot use a GrowableObjectArray, since we must not trigger GC. | 445 // We cannot use a GrowableObjectArray, since we must not trigger GC. |
389 InboundReferencesVisitor(Isolate* isolate, | 446 InboundReferencesVisitor(Isolate* isolate, |
390 RawObject* target, | 447 RawObject* target, |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 | 594 |
538 intptr_t count() const { return count_; } | 595 intptr_t count() const { return count_; } |
539 | 596 |
540 private: | 597 private: |
541 WriteStream* stream_; | 598 WriteStream* stream_; |
542 WritePointerVisitor ptr_writer_; | 599 WritePointerVisitor ptr_writer_; |
543 ObjectGraph::SnapshotRoots roots_; | 600 ObjectGraph::SnapshotRoots roots_; |
544 intptr_t count_; | 601 intptr_t count_; |
545 }; | 602 }; |
546 | 603 |
547 static void IterateUserFields(ObjectPointerVisitor* visitor) { | |
548 Thread* thread = Thread::Current(); | |
549 // Scope to prevent handles create here from appearing as stack references. | |
550 HANDLESCOPE(thread); | |
551 Zone* zone = thread->zone(); | |
552 const GrowableObjectArray& libraries = GrowableObjectArray::Handle( | |
553 zone, thread->isolate()->object_store()->libraries()); | |
554 Library& library = Library::Handle(zone); | |
555 Object& entry = Object::Handle(zone); | |
556 Class& cls = Class::Handle(zone); | |
557 Array& fields = Array::Handle(zone); | |
558 Field& field = Field::Handle(zone); | |
559 for (intptr_t i = 0; i < libraries.Length(); i++) { | |
560 library ^= libraries.At(i); | |
561 DictionaryIterator entries(library); | |
562 while (entries.HasNext()) { | |
563 entry = entries.GetNext(); | |
564 if (entry.IsClass()) { | |
565 cls ^= entry.raw(); | |
566 fields = cls.fields(); | |
567 for (intptr_t j = 0; j < fields.Length(); j++) { | |
568 field ^= fields.At(j); | |
569 RawObject* ptr = field.raw(); | |
570 visitor->VisitPointer(&ptr); | |
571 } | |
572 } else if (entry.IsField()) { | |
573 field ^= entry.raw(); | |
574 RawObject* ptr = field.raw(); | |
575 visitor->VisitPointer(&ptr); | |
576 } | |
577 } | |
578 } | |
579 } | |
580 | |
581 intptr_t ObjectGraph::Serialize(WriteStream* stream, | 604 intptr_t ObjectGraph::Serialize(WriteStream* stream, |
582 SnapshotRoots roots, | 605 SnapshotRoots roots, |
583 bool collect_garbage) { | 606 bool collect_garbage) { |
584 if (collect_garbage) { | 607 if (collect_garbage) { |
585 isolate()->heap()->CollectAllGarbage(); | 608 isolate()->heap()->CollectAllGarbage(); |
586 } | 609 } |
587 // Current encoding assumes objects do not move, so promote everything to old. | 610 // Current encoding assumes objects do not move, so promote everything to old. |
588 isolate()->heap()->new_space()->Evacuate(); | 611 isolate()->heap()->new_space()->Evacuate(); |
589 HeapIterationScope iteration_scope(true); | 612 HeapIterationScope iteration_scope(true); |
590 | 613 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 intptr_t object_count = visitor.count(); | 650 intptr_t object_count = visitor.count(); |
628 if (roots == kVM) { | 651 if (roots == kVM) { |
629 object_count += 1; // root | 652 object_count += 1; // root |
630 } else { | 653 } else { |
631 object_count += 2; // root and stack | 654 object_count += 2; // root and stack |
632 } | 655 } |
633 return object_count; | 656 return object_count; |
634 } | 657 } |
635 | 658 |
636 } // namespace dart | 659 } // namespace dart |
OLD | NEW |