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/reusable_handles.h" | 12 #include "vm/reusable_handles.h" |
13 #include "vm/visitor.h" | 13 #include "vm/visitor.h" |
14 | 14 |
15 namespace dart { | 15 namespace dart { |
16 | 16 |
17 // The state of a pre-order, depth-first traversal of an object graph. | 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. | 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 | 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 | 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. | 21 // its children are processed, to give the visitor a complete chain of parents. |
22 // | 22 // |
23 // TODO(koda): Potential optimizations: | 23 // TODO(koda): Potential optimizations: |
24 // - Use tag bits for compact Node and sentinel representations. | 24 // - Use tag bits for compact Node and sentinel representations. |
25 class ObjectGraph::Stack : public ObjectPointerVisitor { | 25 class ObjectGraph::Stack : public ObjectPointerVisitor { |
26 public: | 26 public: |
27 explicit Stack(Isolate* isolate) | 27 explicit Stack(Isolate* isolate) |
28 : ObjectPointerVisitor(isolate), data_(kInitialCapacity) { } | 28 : ObjectPointerVisitor(isolate), data_(kInitialCapacity) {} |
29 | 29 |
30 // Marks and pushes. Used to initialize this stack with roots. | 30 // Marks and pushes. Used to initialize this stack with roots. |
31 virtual void VisitPointers(RawObject** first, RawObject** last) { | 31 virtual void VisitPointers(RawObject** first, RawObject** last) { |
32 for (RawObject** current = first; current <= last; ++current) { | 32 for (RawObject** current = first; current <= last; ++current) { |
33 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { | 33 if ((*current)->IsHeapObject() && !(*current)->IsMarked()) { |
34 (*current)->SetMarkBit(); | 34 (*current)->SetMarkBit(); |
35 Node node; | 35 Node node; |
36 node.ptr = current; | 36 node.ptr = current; |
37 node.obj = *current; | 37 node.obj = *current; |
38 data_.Add(node); | 38 data_.Add(node); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 // Some internal VM objects visit pointers not contained within the parent. | 131 // Some internal VM objects visit pointers not contained within the parent. |
132 // For instance, RawCode::VisitCodePointers visits pointers in instructions. | 132 // For instance, RawCode::VisitCodePointers visits pointers in instructions. |
133 ASSERT(!parent.obj->IsDartInstance()); | 133 ASSERT(!parent.obj->IsDartInstance()); |
134 return -1; | 134 return -1; |
135 } | 135 } |
136 } | 136 } |
137 | 137 |
138 | 138 |
139 class Unmarker : public ObjectVisitor { | 139 class Unmarker : public ObjectVisitor { |
140 public: | 140 public: |
141 Unmarker() { } | 141 Unmarker() {} |
142 | 142 |
143 void VisitObject(RawObject* obj) { | 143 void VisitObject(RawObject* obj) { |
144 if (obj->IsMarked()) { | 144 if (obj->IsMarked()) { |
145 obj->ClearMarkBit(); | 145 obj->ClearMarkBit(); |
146 } | 146 } |
147 } | 147 } |
148 | 148 |
149 static void UnmarkAll(Isolate* isolate) { | 149 static void UnmarkAll(Isolate* isolate) { |
150 Unmarker unmarker; | 150 Unmarker unmarker; |
151 isolate->heap()->IterateObjects(&unmarker); | 151 isolate->heap()->IterateObjects(&unmarker); |
152 } | 152 } |
153 | 153 |
154 private: | 154 private: |
155 DISALLOW_COPY_AND_ASSIGN(Unmarker); | 155 DISALLOW_COPY_AND_ASSIGN(Unmarker); |
156 }; | 156 }; |
157 | 157 |
158 | 158 |
159 ObjectGraph::ObjectGraph(Thread* thread) | 159 ObjectGraph::ObjectGraph(Thread* thread) : StackResource(thread) { |
160 : StackResource(thread) { | |
161 // The VM isolate has all its objects pre-marked, so iterating over it | 160 // The VM isolate has all its objects pre-marked, so iterating over it |
162 // would be a no-op. | 161 // would be a no-op. |
163 ASSERT(thread->isolate() != Dart::vm_isolate()); | 162 ASSERT(thread->isolate() != Dart::vm_isolate()); |
164 thread->isolate()->heap()->WriteProtectCode(false); | 163 thread->isolate()->heap()->WriteProtectCode(false); |
165 } | 164 } |
166 | 165 |
167 | 166 |
168 ObjectGraph::~ObjectGraph() { | 167 ObjectGraph::~ObjectGraph() { |
169 isolate()->heap()->WriteProtectCode(true); | 168 isolate()->heap()->WriteProtectCode(true); |
170 } | 169 } |
(...skipping 15 matching lines...) Expand all Loading... |
186 RawObject* root_raw = root.raw(); | 185 RawObject* root_raw = root.raw(); |
187 stack.VisitPointer(&root_raw); | 186 stack.VisitPointer(&root_raw); |
188 stack.TraverseGraph(visitor); | 187 stack.TraverseGraph(visitor); |
189 Unmarker::UnmarkAll(isolate()); | 188 Unmarker::UnmarkAll(isolate()); |
190 } | 189 } |
191 | 190 |
192 | 191 |
193 class InstanceAccumulator : public ObjectVisitor { | 192 class InstanceAccumulator : public ObjectVisitor { |
194 public: | 193 public: |
195 InstanceAccumulator(ObjectGraph::Stack* stack, intptr_t class_id) | 194 InstanceAccumulator(ObjectGraph::Stack* stack, intptr_t class_id) |
196 : stack_(stack), class_id_(class_id) { } | 195 : stack_(stack), class_id_(class_id) {} |
197 | 196 |
198 void VisitObject(RawObject* obj) { | 197 void VisitObject(RawObject* obj) { |
199 if (obj->GetClassId() == class_id_) { | 198 if (obj->GetClassId() == class_id_) { |
200 RawObject* rawobj = obj; | 199 RawObject* rawobj = obj; |
201 stack_->VisitPointer(&rawobj); | 200 stack_->VisitPointer(&rawobj); |
202 } | 201 } |
203 } | 202 } |
204 | 203 |
205 private: | 204 private: |
206 ObjectGraph::Stack* stack_; | 205 ObjectGraph::Stack* stack_; |
(...skipping 11 matching lines...) Expand all Loading... |
218 InstanceAccumulator accumulator(&stack, class_id); | 217 InstanceAccumulator accumulator(&stack, class_id); |
219 isolate()->heap()->IterateObjects(&accumulator); | 218 isolate()->heap()->IterateObjects(&accumulator); |
220 | 219 |
221 stack.TraverseGraph(visitor); | 220 stack.TraverseGraph(visitor); |
222 Unmarker::UnmarkAll(isolate()); | 221 Unmarker::UnmarkAll(isolate()); |
223 } | 222 } |
224 | 223 |
225 | 224 |
226 class SizeVisitor : public ObjectGraph::Visitor { | 225 class SizeVisitor : public ObjectGraph::Visitor { |
227 public: | 226 public: |
228 SizeVisitor() : size_(0) { } | 227 SizeVisitor() : size_(0) {} |
229 intptr_t size() const { return size_; } | 228 intptr_t size() const { return size_; } |
230 virtual bool ShouldSkip(RawObject* obj) const { return false; } | 229 virtual bool ShouldSkip(RawObject* obj) const { return false; } |
231 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { | 230 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { |
232 RawObject* obj = it->Get(); | 231 RawObject* obj = it->Get(); |
233 if (ShouldSkip(obj)) { | 232 if (ShouldSkip(obj)) { |
234 return kBacktrack; | 233 return kBacktrack; |
235 } | 234 } |
236 size_ += obj->Size(); | 235 size_ += obj->Size(); |
237 return kProceed; | 236 return kProceed; |
238 } | 237 } |
| 238 |
239 private: | 239 private: |
240 intptr_t size_; | 240 intptr_t size_; |
241 }; | 241 }; |
242 | 242 |
243 | 243 |
244 class SizeExcludingObjectVisitor : public SizeVisitor { | 244 class SizeExcludingObjectVisitor : public SizeVisitor { |
245 public: | 245 public: |
246 explicit SizeExcludingObjectVisitor(const Object& skip) : skip_(skip) { } | 246 explicit SizeExcludingObjectVisitor(const Object& skip) : skip_(skip) {} |
247 virtual bool ShouldSkip(RawObject* obj) const { return obj == skip_.raw(); } | 247 virtual bool ShouldSkip(RawObject* obj) const { return obj == skip_.raw(); } |
| 248 |
248 private: | 249 private: |
249 const Object& skip_; | 250 const Object& skip_; |
250 }; | 251 }; |
251 | 252 |
252 | 253 |
253 class SizeExcludingClassVisitor : public SizeVisitor { | 254 class SizeExcludingClassVisitor : public SizeVisitor { |
254 public: | 255 public: |
255 explicit SizeExcludingClassVisitor(intptr_t skip) : skip_(skip) { } | 256 explicit SizeExcludingClassVisitor(intptr_t skip) : skip_(skip) {} |
256 virtual bool ShouldSkip(RawObject* obj) const { | 257 virtual bool ShouldSkip(RawObject* obj) const { |
257 return obj->GetClassId() == skip_; | 258 return obj->GetClassId() == skip_; |
258 } | 259 } |
| 260 |
259 private: | 261 private: |
260 const intptr_t skip_; | 262 const intptr_t skip_; |
261 }; | 263 }; |
262 | 264 |
263 | 265 |
264 intptr_t ObjectGraph::SizeRetainedByInstance(const Object& obj) { | 266 intptr_t ObjectGraph::SizeRetainedByInstance(const Object& obj) { |
265 SizeVisitor total; | 267 SizeVisitor total; |
266 IterateObjects(&total); | 268 IterateObjects(&total); |
267 intptr_t size_total = total.size(); | 269 intptr_t size_total = total.size(); |
268 SizeExcludingObjectVisitor excluding_obj(obj); | 270 SizeExcludingObjectVisitor excluding_obj(obj); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0); | 307 ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0); |
306 } | 308 } |
307 | 309 |
308 intptr_t length() const { return length_; } | 310 intptr_t length() const { return length_; } |
309 | 311 |
310 bool ShouldSkip(RawObject* obj) { | 312 bool ShouldSkip(RawObject* obj) { |
311 // A retaining path through ICData is never the only retaining path, | 313 // A retaining path through ICData is never the only retaining path, |
312 // and it is less informative than its alternatives. | 314 // and it is less informative than its alternatives. |
313 intptr_t cid = obj->GetClassId(); | 315 intptr_t cid = obj->GetClassId(); |
314 switch (cid) { | 316 switch (cid) { |
315 case kICDataCid: | 317 case kICDataCid: |
316 return true; | 318 return true; |
317 default: | 319 default: |
318 return false; | 320 return false; |
319 } | 321 } |
320 } | 322 } |
321 | 323 |
322 bool ShouldStop(RawObject* obj) { | 324 bool ShouldStop(RawObject* obj) { |
323 // A static field is considered a root from a language point of view. | 325 // A static field is considered a root from a language point of view. |
324 if (obj->IsField()) { | 326 if (obj->IsField()) { |
325 const Field& field = Field::Handle(static_cast<RawField*>(obj)); | 327 const Field& field = Field::Handle(static_cast<RawField*>(obj)); |
326 return field.is_static(); | 328 return field.is_static(); |
327 } | 329 } |
328 return false; | 330 return false; |
329 } | 331 } |
330 | 332 |
331 void StartList() { | 333 void StartList() { was_last_array_ = false; } |
332 was_last_array_ = false; | |
333 } | |
334 | 334 |
335 intptr_t HideNDescendant(RawObject* obj) { | 335 intptr_t HideNDescendant(RawObject* obj) { |
336 // A GrowableObjectArray overwrites its internal storage. | 336 // A GrowableObjectArray overwrites its internal storage. |
337 // Keeping both of them in the list is redundant. | 337 // Keeping both of them in the list is redundant. |
338 if (was_last_array_ && obj->IsGrowableObjectArray()) { | 338 if (was_last_array_ && obj->IsGrowableObjectArray()) { |
339 was_last_array_ = false; | 339 was_last_array_ = false; |
340 return 1; | 340 return 1; |
341 } | 341 } |
342 // A LinkedHasMap overwrites its internal storage. | 342 // A LinkedHasMap overwrites its internal storage. |
343 // Keeping both of them in the list is redundant. | 343 // Keeping both of them in the list is redundant. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 | 401 |
402 | 402 |
403 class InboundReferencesVisitor : public ObjectVisitor, | 403 class InboundReferencesVisitor : public ObjectVisitor, |
404 public ObjectPointerVisitor { | 404 public ObjectPointerVisitor { |
405 public: | 405 public: |
406 // We cannot use a GrowableObjectArray, since we must not trigger GC. | 406 // We cannot use a GrowableObjectArray, since we must not trigger GC. |
407 InboundReferencesVisitor(Isolate* isolate, | 407 InboundReferencesVisitor(Isolate* isolate, |
408 RawObject* target, | 408 RawObject* target, |
409 const Array& references, | 409 const Array& references, |
410 Object* scratch) | 410 Object* scratch) |
411 : ObjectPointerVisitor(isolate), source_(NULL), | 411 : ObjectPointerVisitor(isolate), |
412 target_(target), references_(references), scratch_(scratch), length_(0) { | 412 source_(NULL), |
| 413 target_(target), |
| 414 references_(references), |
| 415 scratch_(scratch), |
| 416 length_(0) { |
413 ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0); | 417 ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0); |
414 } | 418 } |
415 | 419 |
416 intptr_t length() const { return length_; } | 420 intptr_t length() const { return length_; } |
417 | 421 |
418 virtual void VisitObject(RawObject* raw_obj) { | 422 virtual void VisitObject(RawObject* raw_obj) { |
419 source_ = raw_obj; | 423 source_ = raw_obj; |
420 raw_obj->VisitPointers(this); | 424 raw_obj->VisitPointers(this); |
421 } | 425 } |
422 | 426 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 } | 503 } |
500 | 504 |
501 intptr_t count() const { return count_; } | 505 intptr_t count() const { return count_; } |
502 | 506 |
503 private: | 507 private: |
504 WriteStream* stream_; | 508 WriteStream* stream_; |
505 intptr_t count_; | 509 intptr_t count_; |
506 }; | 510 }; |
507 | 511 |
508 | 512 |
509 static void WriteHeader(RawObject* raw, intptr_t size, intptr_t cid, | 513 static void WriteHeader(RawObject* raw, |
510 WriteStream* stream) { | 514 intptr_t size, |
| 515 intptr_t cid, |
| 516 WriteStream* stream) { |
511 WritePtr(raw, stream); | 517 WritePtr(raw, stream); |
512 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 518 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
513 stream->WriteUnsigned(size); | 519 stream->WriteUnsigned(size); |
514 stream->WriteUnsigned(cid); | 520 stream->WriteUnsigned(cid); |
515 } | 521 } |
516 | 522 |
517 | 523 |
518 class WriteGraphVisitor : public ObjectGraph::Visitor { | 524 class WriteGraphVisitor : public ObjectGraph::Visitor { |
519 public: | 525 public: |
520 WriteGraphVisitor(Isolate* isolate, WriteStream* stream) | 526 WriteGraphVisitor(Isolate* isolate, WriteStream* stream) |
521 : stream_(stream), ptr_writer_(isolate, stream), count_(0) {} | 527 : stream_(stream), ptr_writer_(isolate, stream), count_(0) {} |
522 | 528 |
523 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { | 529 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { |
524 RawObject* raw_obj = it->Get(); | 530 RawObject* raw_obj = it->Get(); |
525 Thread* thread = Thread::Current(); | 531 Thread* thread = Thread::Current(); |
526 REUSABLE_OBJECT_HANDLESCOPE(thread); | 532 REUSABLE_OBJECT_HANDLESCOPE(thread); |
527 Object& obj = thread->ObjectHandle(); | 533 Object& obj = thread->ObjectHandle(); |
528 obj = raw_obj; | 534 obj = raw_obj; |
529 // Each object is a header + a zero-terminated list of its neighbors. | 535 // Each object is a header + a zero-terminated list of its neighbors. |
530 WriteHeader(raw_obj, raw_obj->Size(), obj.GetClassId(), stream_); | 536 WriteHeader(raw_obj, raw_obj->Size(), obj.GetClassId(), stream_); |
531 raw_obj->VisitPointers(&ptr_writer_); | 537 raw_obj->VisitPointers(&ptr_writer_); |
(...skipping 26 matching lines...) Expand all Loading... |
558 { | 564 { |
559 WritePointerVisitor ptr_writer(isolate(), stream); | 565 WritePointerVisitor ptr_writer(isolate(), stream); |
560 isolate()->IterateObjectPointers(&ptr_writer, false); | 566 isolate()->IterateObjectPointers(&ptr_writer, false); |
561 } | 567 } |
562 stream->WriteUnsigned(0); | 568 stream->WriteUnsigned(0); |
563 IterateObjects(&visitor); | 569 IterateObjects(&visitor); |
564 return visitor.count() + 1; // + root | 570 return visitor.count() + 1; // + root |
565 } | 571 } |
566 | 572 |
567 } // namespace dart | 573 } // namespace dart |
OLD | NEW |