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/raw_object.h" | 12 #include "vm/raw_object.h" |
12 #include "vm/reusable_handles.h" | 13 #include "vm/reusable_handles.h" |
13 #include "vm/visitor.h" | 14 #include "vm/visitor.h" |
14 | 15 |
15 namespace dart { | 16 namespace dart { |
16 | 17 |
17 // 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. |
18 // 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. |
19 // 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 |
20 // 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 |
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
480 ASSERT(Utils::IsAligned(addr, kObjectAlignment)); | 481 ASSERT(Utils::IsAligned(addr, kObjectAlignment)); |
481 // Using units of kObjectAlignment makes the ids fit into Smis when parsed | 482 // Using units of kObjectAlignment makes the ids fit into Smis when parsed |
482 // in the Dart code of the Observatory. | 483 // in the Dart code of the Observatory. |
483 // TODO(koda): Use delta-encoding/back-references to further compress this. | 484 // TODO(koda): Use delta-encoding/back-references to further compress this. |
484 stream->WriteUnsigned(addr / kObjectAlignment); | 485 stream->WriteUnsigned(addr / kObjectAlignment); |
485 } | 486 } |
486 | 487 |
487 | 488 |
488 class WritePointerVisitor : public ObjectPointerVisitor { | 489 class WritePointerVisitor : public ObjectPointerVisitor { |
489 public: | 490 public: |
490 WritePointerVisitor(Isolate* isolate, WriteStream* stream) | 491 WritePointerVisitor(Isolate* isolate, |
491 : ObjectPointerVisitor(isolate), stream_(stream), count_(0) {} | 492 WriteStream* stream, |
493 bool only_instances) | |
494 : ObjectPointerVisitor(isolate), | |
495 stream_(stream), | |
496 only_instances_(only_instances), | |
497 count_(0) {} | |
492 virtual void VisitPointers(RawObject** first, RawObject** last) { | 498 virtual void VisitPointers(RawObject** first, RawObject** last) { |
493 for (RawObject** current = first; current <= last; ++current) { | 499 for (RawObject** current = first; current <= last; ++current) { |
494 RawObject* object = *current; | 500 RawObject* object = *current; |
495 if (!object->IsHeapObject() || object->IsVMHeapObject()) { | 501 if (!object->IsHeapObject() || object->IsVMHeapObject()) { |
496 // Ignore smis and objects in the VM isolate for now. | 502 // Ignore smis and objects in the VM isolate for now. |
497 // TODO(koda): To track which field each pointer corresponds to, | 503 // TODO(koda): To track which field each pointer corresponds to, |
498 // we'll need to encode which fields were omitted here. | 504 // we'll need to encode which fields were omitted here. |
499 continue; | 505 continue; |
500 } | 506 } |
507 if (only_instances_ && (object->GetClassId() < kInstanceCid)) { | |
508 continue; | |
509 } | |
501 WritePtr(object, stream_); | 510 WritePtr(object, stream_); |
502 ++count_; | 511 ++count_; |
503 } | 512 } |
504 } | 513 } |
505 | 514 |
506 intptr_t count() const { return count_; } | 515 intptr_t count() const { return count_; } |
507 | 516 |
508 private: | 517 private: |
509 WriteStream* stream_; | 518 WriteStream* stream_; |
519 bool only_instances_; | |
510 intptr_t count_; | 520 intptr_t count_; |
511 }; | 521 }; |
512 | 522 |
513 | 523 |
514 static void WriteHeader(RawObject* raw, | 524 static void WriteHeader(RawObject* raw, |
515 intptr_t size, | 525 intptr_t size, |
516 intptr_t cid, | 526 intptr_t cid, |
517 WriteStream* stream) { | 527 WriteStream* stream) { |
518 WritePtr(raw, stream); | 528 WritePtr(raw, stream); |
519 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 529 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
520 stream->WriteUnsigned(size); | 530 stream->WriteUnsigned(size); |
521 stream->WriteUnsigned(cid); | 531 stream->WriteUnsigned(cid); |
522 } | 532 } |
523 | 533 |
524 | 534 |
525 class WriteGraphVisitor : public ObjectGraph::Visitor { | 535 class WriteGraphVisitor : public ObjectGraph::Visitor { |
526 public: | 536 public: |
527 WriteGraphVisitor(Isolate* isolate, WriteStream* stream) | 537 WriteGraphVisitor(Isolate* isolate, |
528 : stream_(stream), ptr_writer_(isolate, stream), count_(0) {} | 538 WriteStream* stream, |
539 ObjectGraph::SnapshotRoots roots) | |
540 : stream_(stream), | |
541 ptr_writer_(isolate, stream, roots == ObjectGraph::kUser), | |
542 roots_(roots), | |
543 count_(0) {} | |
529 | 544 |
530 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { | 545 virtual Direction VisitObject(ObjectGraph::StackIterator* it) { |
531 RawObject* raw_obj = it->Get(); | 546 RawObject* raw_obj = it->Get(); |
532 Thread* thread = Thread::Current(); | 547 Thread* thread = Thread::Current(); |
533 REUSABLE_OBJECT_HANDLESCOPE(thread); | 548 REUSABLE_OBJECT_HANDLESCOPE(thread); |
534 Object& obj = thread->ObjectHandle(); | 549 Object& obj = thread->ObjectHandle(); |
535 obj = raw_obj; | 550 obj = raw_obj; |
536 // Each object is a header + a zero-terminated list of its neighbors. | 551 if ((roots_ == ObjectGraph::kVM) || obj.IsField() || obj.IsInstance()) { |
537 WriteHeader(raw_obj, raw_obj->Size(), obj.GetClassId(), stream_); | 552 // Each object is a header + a zero-terminated list of its neighbors. |
538 raw_obj->VisitPointers(&ptr_writer_); | 553 WriteHeader(raw_obj, raw_obj->Size(), obj.GetClassId(), stream_); |
539 stream_->WriteUnsigned(0); | 554 raw_obj->VisitPointers(&ptr_writer_); |
540 ++count_; | 555 stream_->WriteUnsigned(0); |
556 ++count_; | |
557 } | |
541 return kProceed; | 558 return kProceed; |
542 } | 559 } |
543 | 560 |
544 intptr_t count() const { return count_; } | 561 intptr_t count() const { return count_; } |
545 | 562 |
546 private: | 563 private: |
547 WriteStream* stream_; | 564 WriteStream* stream_; |
548 WritePointerVisitor ptr_writer_; | 565 WritePointerVisitor ptr_writer_; |
566 ObjectGraph::SnapshotRoots roots_; | |
549 intptr_t count_; | 567 intptr_t count_; |
550 }; | 568 }; |
551 | 569 |
552 | 570 |
553 intptr_t ObjectGraph::Serialize(WriteStream* stream, bool collect_garbage) { | 571 static void IterateUserFields(ObjectPointerVisitor* visitor) { |
572 Thread* thread = Thread::Current(); | |
573 // Scope to prevent handles create here from appearing as stack references. | |
574 HANDLESCOPE(thread); | |
575 Zone* zone = thread->zone(); | |
576 const GrowableObjectArray& libraries = GrowableObjectArray::Handle( | |
577 zone, thread->isolate()->object_store()->libraries()); | |
578 Library& library = Library::Handle(zone); | |
579 Object& entry = Object::Handle(zone); | |
580 Class& cls = Class::Handle(zone); | |
581 Array& fields = Array::Handle(zone); | |
582 Field& field = Field::Handle(zone); | |
583 for (intptr_t i = 0; i < libraries.Length(); i++) { | |
584 library ^= libraries.At(i); | |
585 DictionaryIterator entries(library); | |
586 while (entries.HasNext()) { | |
587 entry = entries.GetNext(); | |
588 if (entry.IsClass()) { | |
589 cls ^= entry.raw(); | |
590 fields = cls.fields(); | |
591 for (intptr_t j = 0; j < fields.Length(); j++) { | |
592 field ^= fields.At(j); | |
593 RawObject* ptr = field.raw(); | |
594 visitor->VisitPointer(&ptr); | |
595 } | |
596 } else if (entry.IsField()) { | |
597 field ^= entry.raw(); | |
598 RawObject* ptr = field.raw(); | |
599 visitor->VisitPointer(&ptr); | |
600 } | |
601 } | |
602 } | |
603 } | |
604 | |
605 | |
606 intptr_t ObjectGraph::Serialize(WriteStream* stream, | |
607 SnapshotRoots roots, | |
608 bool collect_garbage) { | |
554 if (collect_garbage) { | 609 if (collect_garbage) { |
555 isolate()->heap()->CollectAllGarbage(); | 610 isolate()->heap()->CollectAllGarbage(); |
556 } | 611 } |
557 // Current encoding assumes objects do not move, so promote everything to old. | 612 // Current encoding assumes objects do not move, so promote everything to old. |
558 isolate()->heap()->new_space()->Evacuate(); | 613 isolate()->heap()->new_space()->Evacuate(); |
559 | 614 |
560 WriteGraphVisitor visitor(isolate(), stream); | 615 RawObject* kRootAddress = reinterpret_cast<RawObject*>(kHeapObjectTag); |
616 const intptr_t kRootCid = 0; | |
Cutch
2016/11/18 20:40:31
maybe move this and kStackCid into the real class
rmacnak
2016/11/18 22:34:02
Done.
| |
617 RawObject* kStackAddress = | |
618 reinterpret_cast<RawObject*>(kObjectAlignment + kHeapObjectTag); | |
619 // Keep in sync with runtime/observatory/lib/object_graph.dart. | |
620 const intptr_t kStackCid = 1; | |
621 | |
561 stream->WriteUnsigned(kObjectAlignment); | 622 stream->WriteUnsigned(kObjectAlignment); |
562 stream->WriteUnsigned(0); | 623 |
563 stream->WriteUnsigned(0); | 624 if (roots == kVM) { |
564 stream->WriteUnsigned(0); | 625 // Write root "object". |
565 { | 626 WriteHeader(kRootAddress, 0, kRootCid, stream); |
566 WritePointerVisitor ptr_writer(isolate(), stream); | 627 WritePointerVisitor ptr_writer(isolate(), stream, false); |
567 isolate()->IterateObjectPointers(&ptr_writer, false); | 628 isolate()->IterateObjectPointers(&ptr_writer, false); |
629 stream->WriteUnsigned(0); | |
630 } else { | |
631 { | |
632 // Write root "object". | |
633 WriteHeader(kRootAddress, 0, kRootCid, stream); | |
634 WritePointerVisitor ptr_writer(isolate(), stream, false); | |
635 IterateUserFields(&ptr_writer); | |
636 WritePtr(kStackAddress, stream); | |
637 stream->WriteUnsigned(0); | |
638 } | |
639 | |
640 { | |
641 // Write stack "object". | |
642 WriteHeader(kStackAddress, 0, kStackCid, stream); | |
643 WritePointerVisitor ptr_writer(isolate(), stream, true); | |
644 isolate()->IterateStackPointers(&ptr_writer, false); | |
645 stream->WriteUnsigned(0); | |
646 } | |
568 } | 647 } |
569 stream->WriteUnsigned(0); | 648 |
649 WriteGraphVisitor visitor(isolate(), stream, roots); | |
570 IterateObjects(&visitor); | 650 IterateObjects(&visitor); |
571 return visitor.count() + 1; // + root | 651 |
652 intptr_t object_count = visitor.count(); | |
653 if (roots == kVM) { | |
654 object_count += 1; // root | |
655 } else { | |
656 object_count += 2; // root and stack | |
657 } | |
658 return object_count; | |
572 } | 659 } |
573 | 660 |
574 } // namespace dart | 661 } // namespace dart |
OLD | NEW |