Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(643)

Side by Side Diff: runtime/vm/object_graph.cc

Issue 2990643002: Calculates retaining paths through user fields and ignores VM objects (Closed)
Patch Set: Adds new test that expects a simple path for const and top level functions Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/object_graph.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/object_graph.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698