| 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 = kIllegalCid; |
| 617 RawObject* kStackAddress = |
| 618 reinterpret_cast<RawObject*>(kObjectAlignment + kHeapObjectTag); |
| 619 |
| 561 stream->WriteUnsigned(kObjectAlignment); | 620 stream->WriteUnsigned(kObjectAlignment); |
| 562 stream->WriteUnsigned(0); | 621 stream->WriteUnsigned(kStackCid); |
| 563 stream->WriteUnsigned(0); | 622 |
| 564 stream->WriteUnsigned(0); | 623 if (roots == kVM) { |
| 565 { | 624 // Write root "object". |
| 566 WritePointerVisitor ptr_writer(isolate(), stream); | 625 WriteHeader(kRootAddress, 0, kRootCid, stream); |
| 626 WritePointerVisitor ptr_writer(isolate(), stream, false); |
| 567 isolate()->IterateObjectPointers(&ptr_writer, false); | 627 isolate()->IterateObjectPointers(&ptr_writer, false); |
| 628 stream->WriteUnsigned(0); |
| 629 } else { |
| 630 { |
| 631 // Write root "object". |
| 632 WriteHeader(kRootAddress, 0, kRootCid, stream); |
| 633 WritePointerVisitor ptr_writer(isolate(), stream, false); |
| 634 IterateUserFields(&ptr_writer); |
| 635 WritePtr(kStackAddress, stream); |
| 636 stream->WriteUnsigned(0); |
| 637 } |
| 638 |
| 639 { |
| 640 // Write stack "object". |
| 641 WriteHeader(kStackAddress, 0, kStackCid, stream); |
| 642 WritePointerVisitor ptr_writer(isolate(), stream, true); |
| 643 isolate()->IterateStackPointers(&ptr_writer, false); |
| 644 stream->WriteUnsigned(0); |
| 645 } |
| 568 } | 646 } |
| 569 stream->WriteUnsigned(0); | 647 |
| 648 WriteGraphVisitor visitor(isolate(), stream, roots); |
| 570 IterateObjects(&visitor); | 649 IterateObjects(&visitor); |
| 571 return visitor.count() + 1; // + root | 650 |
| 651 intptr_t object_count = visitor.count(); |
| 652 if (roots == kVM) { |
| 653 object_count += 1; // root |
| 654 } else { |
| 655 object_count += 2; // root and stack |
| 656 } |
| 657 return object_count; |
| 572 } | 658 } |
| 573 | 659 |
| 574 } // namespace dart | 660 } // namespace dart |
| OLD | NEW |