Chromium Code Reviews| 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 |