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 |