Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: src/vm/snapshot.cc

Issue 2067483002: More compact snapshots. (Closed) Base URL: git@github.com:dartino/sdk.git@master
Patch Set: Feedback Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/vm/snapshot.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dartino project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dartino 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.md file. 3 // BSD-style license that can be found in the LICENSE.md file.
4 4
5 #include "src/vm/snapshot.h" 5 #include "src/vm/snapshot.h"
6 6
7 #include <stdio.h> 7 #include <stdio.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <stdarg.h> 9 #include <stdarg.h>
10 #include <string.h> 10 #include <string.h>
11 11
12 #include "src/shared/assert.h" 12 #include "src/shared/assert.h"
13 #include "src/shared/bytecodes.h" 13 #include "src/shared/bytecodes.h"
14 #include "src/shared/utils.h" 14 #include "src/shared/utils.h"
15 #include "src/shared/version.h" 15 #include "src/shared/version.h"
16 16
17 #include "src/vm/object.h" 17 #include "src/vm/object.h"
18 #include "src/vm/program.h" 18 #include "src/vm/program.h"
19 19
20 namespace dartino { 20 namespace dartino {
21 21
22 class SnapshotOracle;
23
22 void FixByteCodes(uint8* bcp, uword size, int old_shift, int new_shift); 24 void FixByteCodes(uint8* bcp, uword size, int old_shift, int new_shift);
23 25
24 class ReaderVisitor : public PointerVisitor { 26 class ReaderVisitor : public PointerVisitor {
25 public: 27 public:
26 explicit ReaderVisitor(SnapshotReader* reader) : reader_(reader) {} 28 explicit ReaderVisitor(SnapshotReader* reader) : reader_(reader) {}
27 29
28 void Visit(Object** p) { 30 void Visit(Object** p) {
29 *p = reinterpret_cast<Object*>(reader_->ReadWord()); 31 *p = reinterpret_cast<Object*>(reader_->ReadWord());
30 } 32 }
31 33
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 // FALL THROUGH! 201 // FALL THROUGH!
200 case kSnapshotRecentSmi: 202 case kSnapshotRecentSmi:
201 case kSnapshotSmi: 203 case kSnapshotSmi:
202 case kSnapshotExternal: { 204 case kSnapshotExternal: {
203 position += w; 205 position += w;
204 real_address += kWordSize; 206 real_address += kWordSize;
205 ideal_address += kIdealWordSize; 207 ideal_address += kIdealWordSize;
206 break; 208 break;
207 } 209 }
208 case kSnapshotRaw: { 210 case kSnapshotRaw: {
209 word x = (b & 7) + kSnapshotBias; 211 word x = ArgumentStart(b, w);
210 ASSERT(x >= 0);
211 while (w-- != 0) { 212 while (w-- != 0) {
212 x <<= 8; 213 x <<= 8;
213 x |= snapshot_[position++]; 214 x |= snapshot_[position++];
214 } 215 }
215 real_address += Utils::RoundUp(x, kWordSize); 216 real_address += Utils::RoundUp(x, kWordSize);
216 ideal_address += Utils::RoundUp(x, kIdealWordSize); 217 ideal_address += Utils::RoundUp(x, kIdealWordSize);
217 position += x; 218 position += x;
218 break; 219 break;
219 } 220 }
220 default: 221 default:
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 reinterpret_cast<uint8*>(&result)); 393 reinterpret_cast<uint8*>(&result));
393 raw_to_do_ -= kWordSize; 394 raw_to_do_ -= kWordSize;
394 return result; 395 return result;
395 } 396 }
396 uint8 b = ReadByte(); 397 uint8 b = ReadByte();
397 if ((b & kSnapshotPopularMask) == kSnapshotPopular) { 398 if ((b & kSnapshotPopularMask) == kSnapshotPopular) {
398 return reinterpret_cast<word>(popular_objects_[b]); 399 return reinterpret_cast<word>(popular_objects_[b]);
399 } else { 400 } else {
400 uint8 opcode = OpCode(b); 401 uint8 opcode = OpCode(b);
401 int w = ArgumentBytes(b); 402 int w = ArgumentBytes(b);
402 word x = (b & 7) + kSnapshotBias; 403 word x = ArgumentStart(b, w);
403 for (int i = 0; i < w; i++) { 404 for (int i = 0; i < w; i++) {
404 x <<= 8; 405 x <<= 8;
405 x |= ReadByte(); 406 x |= ReadByte();
406 } 407 }
407 if (opcode <= kSnapshotRecentSmi) { 408 if (opcode <= kSnapshotRecentSmi) {
408 int index = opcode - kSnapshotRecentPointer; 409 int index = opcode - kSnapshotRecentPointer;
409 ASSERT(index >= 0 && index <= 2); 410 ASSERT(index >= 0 && index <= 2);
410 word ideal = recents_[index]; 411 word ideal = recents_[index];
411 // For the pointers, multiply by 4. 412 // For the pointers, multiply by 4.
412 int pointer_flag = ((~opcode) & 4) >> 1; 413 int pointer_flag = ((~opcode) & 4) >> 1;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 default: 564 default:
564 i += Bytecode::Size(opcode); 565 i += Bytecode::Size(opcode);
565 break; 566 break;
566 } 567 }
567 } 568 }
568 } 569 }
569 570
570 class ObjectWriter : public PointerVisitor { 571 class ObjectWriter : public PointerVisitor {
571 public: 572 public:
572 ObjectWriter(SnapshotWriter* writer, PortableAddressMap* map, 573 ObjectWriter(SnapshotWriter* writer, PortableAddressMap* map,
574 SnapshotOracle* pointer_oracle, SnapshotOracle* smi_oracle,
573 HeapObject* current = NULL) 575 HeapObject* current = NULL)
574 : writer_(writer), 576 : writer_(writer),
575 address_map_(map), 577 address_map_(map),
578 pointer_oracle_(pointer_oracle),
579 smi_oracle_(smi_oracle),
576 current_(current == NULL ? 0 : reinterpret_cast<uint8*>( 580 current_(current == NULL ? 0 : reinterpret_cast<uint8*>(
577 current->address())) {} 581 current->address())) {}
578 582
579 virtual void VisitClass(Object** p) { 583 virtual void VisitClass(Object** p) {
580 ASSERT(current_ == reinterpret_cast<uint8*>(p)); 584 ASSERT(current_ == reinterpret_cast<uint8*>(p));
581 WriteWord(*p, reinterpret_cast<uword>(p)); 585 ASSERT(!(*p)->IsSmi());
586 WriteWord(*p);
582 current_ += kWordSize; 587 current_ += kWordSize;
583 } 588 }
584 589
585 void VisitBlock(Object** start, Object** end) { 590 void VisitBlock(Object** start, Object** end) {
586 if (start == end) return; 591 if (start == end) return;
587 uint8* block_start = reinterpret_cast<uint8*>(start); 592 uint8* block_start = reinterpret_cast<uint8*>(start);
588 ASSERT(current_ == 0 || block_start == current_); 593 ASSERT(current_ == 0 || block_start == current_);
589 for (Object** p = start; p < end; p++) { 594 for (Object** p = start; p < end; p++) {
590 WriteWord(*p, reinterpret_cast<uword>(p)); 595 WriteWord(*p);
591 } 596 }
592 if (current_ != NULL) current_ = reinterpret_cast<uint8*>(end); 597 if (current_ != NULL) current_ = reinterpret_cast<uint8*>(end);
593 } 598 }
594 599
595 void End(uword end_of_object) { 600 void End(uword end_of_object) {
596 ASSERT(current_ == reinterpret_cast<uint8*>(end_of_object)); 601 ASSERT(current_ == reinterpret_cast<uint8*>(end_of_object));
597 } 602 }
598 603
599 virtual void VisitInteger(uword slot) { 604 virtual void VisitInteger(uword slot) {
600 ASSERT(current_ = reinterpret_cast<uint8*>(slot)); 605 ASSERT(current_ = reinterpret_cast<uint8*>(slot));
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 } 657 }
653 658
654 void VisitRaw(uint8* start, uword size) { 659 void VisitRaw(uint8* start, uword size) {
655 if (size == 0) return; 660 if (size == 0) return;
656 ASSERT(start == current_); 661 ASSERT(start == current_);
657 current_ += Utils::RoundUp(size, kWordSize); 662 current_ += Utils::RoundUp(size, kWordSize);
658 WriteOpcode(kSnapshotRaw, size); 663 WriteOpcode(kSnapshotRaw, size);
659 writer_->WriteBytes(start, size); 664 writer_->WriteBytes(start, size);
660 } 665 }
661 666
662 int32 abs(int32 x) { 667 void WriteInteger(word i);
663 if (x < 0) return -x;
664 return x;
665 }
666 668
667 void WriteInteger(word i) { 669 void WriteWord(Object* object);
668 // Large Smis must be purged from the heap before we serialize, since
669 // they can't be represented on small devices.
670 ASSERT(i <= 0x7fffffff);
671 ASSERT(i >= -0x7fffffff - 1);
672 int32 offset = i - writer_->recent_smi();
673 if (offset < -2 || abs(i) < abs(offset)) {
674 WriteOpcode(kSnapshotSmi, i);
675 } else {
676 WriteOpcode(kSnapshotRecentSmi, offset);
677 writer_->set_recent_smi(i);
678 }
679 }
680 670
681 void WriteWord(Object* object, uword from = 0) { 671 static int OpcodeLength(word offset) {
682 if (object->IsSmi()) {
683 WriteInteger(reinterpret_cast<word>(object));
684 return;
685 }
686
687 HeapObject* heap_object = HeapObject::cast(object);
688 uword ideal = address_map_->IdealizedAddress(heap_object) -
689 address_map_->doubles_size();
690 int popular_index = writer_->PopularityIndex(heap_object);
691 if (popular_index != -1) {
692 ASSERT(popular_index < kSnapshotNumberOfPopularObjects &&
693 popular_index >= 0);
694 ASSERT(kSnapshotPopular == 0);
695 ASSERT((kSnapshotPopularMask & kSnapshotPopular) == 0);
696 ASSERT((kSnapshotPopularMask & (kSnapshotNumberOfPopularObjects - 1)) ==
697 0);
698 writer_->WriteByte(popular_index);
699 } else {
700 // If there's a register that we can use that gives a 1-byte encoding,
701 // then just use that.
702 for (int i = 0; i < 2; i++) {
703 word offset = ideal - writer_->recent(i);
704 if (OpcodeLength(offset / kIdealWordSize) == 1) {
705 WriteOpcode(kSnapshotRecentPointer + i, offset / kIdealWordSize);
706 writer_->set_recent(i, ideal);
707 return;
708 }
709 }
710 int reg = -1;
711 word offset0 = ideal - writer_->recent(0);
712 word offset1 = ideal - writer_->recent(1);
713 // For each encoding length, check if there is a register that we can
714 // pick that will give that length. If there are two, pick the least
715 // recently used.
716 for (int goal = 2; goal <= 5; goal++) {
717 word offset0 = ideal - writer_->recent(0);
718 word offset1 = ideal - writer_->recent(1);
719 if (OpcodeLength(offset0 / kIdealWordSize) == goal) {
720 if (OpcodeLength(offset1 / kIdealWordSize) == goal) {
721 if (writer_->lru(0) < writer_->lru(1)) {
722 reg = 0;
723 } else {
724 reg = 1;
725 }
726 } else {
727 reg = 0;
728 }
729 break;
730 } else if (OpcodeLength(offset1 / kIdealWordSize) == goal) {
731 reg = 1;
732 break;
733 }
734 }
735 word offset = reg ? offset1 : offset0;
736 ASSERT(reg != -1);
737 WriteOpcode(kSnapshotRecentPointer + reg, offset / kIdealWordSize);
738 writer_->set_recent(reg, ideal);
739 }
740 }
741
742 int OpcodeLength(word offset) {
743 int w = 0; 672 int w = 0;
744 // We can't code for a w with 3, so we keep going to 4 if we hit that one. 673 int first_byte_bits = 4;
745 while (offset < kSnapshotBias || offset > 7 + kSnapshotBias || w == 3) { 674 while (offset < kSnapshotBias ||
675 offset >= (1 << first_byte_bits) + kSnapshotBias) {
746 w++; 676 w++;
747 offset >>= 8; // Signed shift. 677 offset >>= 8; // Signed shift.
678 first_byte_bits--;
679 if (first_byte_bits == 0) {
680 ASSERT(w == 4);
681 ASSERT(offset <= 0 && offset >= kSnapshotBias);
682 return 5;
683 }
748 } 684 }
749 ASSERT(w >= 0 && w <= 4 && w != 3); 685 ASSERT(w <= 4);
750 return w + 1; 686 return w + 1;
751 } 687 }
752 688
753 void WriteOpcode(int opcode, word offset) { 689 void WriteOpcode(int opcode, word offset) {
754 int w = 0; 690 int w = OpcodeLength(offset) - 1;
755 uint8 bytes[4] = {0, 0, 0, 0}; 691 // bytecode has the opcode in the top 3 bits.
756 // We can't code for a w with 3, so we keep going to 4 if we hit that one. 692 uint8 opcode_byte = opcode << 5;
757 while (offset < kSnapshotBias || offset > 7 + kSnapshotBias || w == 3) { 693 // Move to 64 bit even on 32 bit platforms.
758 w++; 694 int64 x = offset;
759 bytes[3] = bytes[2]; 695 int64 bias = -kSnapshotBias;
760 bytes[2] = bytes[1]; 696 // We can do a shift of 32 on bias because it is a 64 bit value.
761 bytes[1] = bytes[0]; 697 x += bias << (8 * w);
762 bytes[0] = offset; 698 ASSERT(x >= 0 && (x >> 33) == 0); // Unsigned 33 bit value now.
763 offset >>= 8; // Signed shift. 699 // We can encode 4 bits for a 0-byte instruction. For each byte
700 // we add to the instruction we lose one bit in the initial word
701 // so we gain only 7 bits per extra byte. However for the 5-byte
702 // encoding where w == 4 we have an extra bit.
703 int64 one = 1; // Value that can legally be shifted by 32.
704 if (offset > 0 && w == 4) {
705 ASSERT(x == (x & ((one << 33) - 1)));
706 } else {
707 ASSERT(x == (x & ((one << (4 + 7 * w)) - 1)));
764 } 708 }
765 ASSERT(w >= 0 && w <= 4 && w != 3); 709 // The lower part of the bytecode has a unary encoding of the width
766 uint8 opcode_byte = (opcode << 5) | ((w == 4 ? 3 : w) << 3) | 710 // and the first few bits of the biased offset.
767 ((offset - kSnapshotBias) & 7); 711 // w == 0: 0xxxx
768 writer_->WriteByte(opcode_byte); 712 // w == 1: 10xxx
769 writer_->WriteBytes(bytes, w); 713 // w == 2: 110xx
714 // w == 3: 1110x
715 // w == 4: 1111x
716 uint8 width_indicator = 0x1f;
717 // Zap the low bits (the xs and the 0s).
718 width_indicator &= ~((1 << (5 - w)) - 1);
719 // The width indicator and the top part of the x may not overlap.
720 uint8 offset_top_part = x >> (8 * w);
721 ASSERT((width_indicator & offset_top_part) == 0);
722
723 writer_->WriteByte(opcode_byte | width_indicator | offset_top_part);
724 for (int i = w - 1; i >= 0; i--) {
725 writer_->WriteByte(x >> (8 * i));
726 }
770 } 727 }
771 728
772 private: 729 private:
773 SnapshotWriter* writer_; 730 SnapshotWriter* writer_;
774 PortableAddressMap* address_map_; 731 PortableAddressMap* address_map_;
732 SnapshotOracle* pointer_oracle_;
733 SnapshotOracle* smi_oracle_;
775 // This is the position in the current object we are serializing. If we 734 // This is the position in the current object we are serializing. If we
776 // are outputting roots, which are not inside any object, then it is null. 735 // are outputting roots, which are not inside any object, then it is null.
777 // Only used for asserts, to ensure we don't skip part of the object 736 // Only used for asserts, to ensure we don't skip part of the object
778 // without serializint it. 737 // without serializint it.
779 uint8* current_; 738 uint8* current_;
780 }; 739 };
781 740
741 // The oracle tells the snapshot encoder at each step, which register to use,
742 // using knowledge of the future pointers that the encoder will soon encounter.
743 // Like all good oracles, it does this by cheating: It runs through the
744 // pointers first, and remembers the order they arrived last time. In the first
745 // pass it keeps track of all possible decisions for the last kStatesLog2
746 // pointers. When a new pointer arrives, it discards half the possibilities, by
747 // making a decision on how to encode the pointer we had, kStatesLog2 calls
748 // ago. Then it doubles the number of possibilities by picking either register
749 // 0 or register 1. Similarly in the smi mode it does this for Smis, with the
750 // difference that here one of the registers is locked to zero (ie the choice
751 // is between register-relative and absolute encoding).
752 class SnapshotOracle : public PointerVisitor {
753 public:
754 SnapshotOracle(bool smi_mode, PortableAddressMap* map, SnapshotWriter* writer)
755 : smi_mode_(smi_mode), writer_(writer), map_(map) {
756 for (int i = 0; i < kStates; i++) {
757 costs_[i] = 0;
758 regs_[0][i] = 0;
759 regs_[1][i] = 0;
760 }
761 }
762
763 virtual void VisitInteger(uword slot) {
764 if (!smi_mode_) return;
765 word i = *reinterpret_cast<word*>(slot);
766 SimulateInput(i);
767 }
768
769 virtual void VisitLiteralInteger(int32 i) {
770 if (!smi_mode_) return;
771 SimulateInput(i);
772 }
773
774 virtual void VisitClass(Object** slot) { VisitBlock(slot, slot + 1); }
775
776 virtual void VisitBlock(Object** start, Object** end) {
777 for (Object** p = start; p < end; p++) {
778 Object* o = *p;
779 if (o->IsSmi()) {
780 if (!smi_mode_) continue;
781 SimulateInput(static_cast<int>(reinterpret_cast<word>(o)));
782 } else {
783 if (smi_mode_) continue;
784 int addr = map_->IdealizedAddress(o);
785 int popular_index = writer_->PopularityIndex(HeapObject::cast(o));
786 if (popular_index == -1) {
787 SimulateInput(addr);
788 }
789 }
790 }
791 }
792
793 void WrapUp() {
794 int bogus = kStatesLog2 - unused_;
795 for (int i = 0; i < bogus; i++) {
796 // Add enough bogus entries to the list of pointers to be encoded. These
797 // have the effect of forcing the decision to be made on all pointers up
798 // to the last real one.
799 SimulateInput(0);
800 }
801 }
802
803 void SimulateInput(int addr) {
804 int best_cost = 1000000000;
805 int best_reg = -1;
806 for (int i = 0; i < kStates; i++) {
807 if (costs_[i] >= best_cost) continue; // Optimization.
808 for (int reg = 0; reg < 2; reg++) {
809 int diff = addr - regs_[reg][i];
810 int cost = ObjectWriter::OpcodeLength(diff >> (smi_mode_ ? 0 : 2));
811 if (costs_[i] + cost < best_cost) {
812 best_reg = ((i >> (kStatesLog2 - 1)) & 1);
813 best_cost = costs_[i] + cost;
814 }
815 }
816 }
817 // Oldest choice is in the most significant bit.
818 // Find a decision that is now made, using the oldest possibility.
819 int decision = best_reg;
820 if (unused_ == 0) {
821 script_.PushBack(decision);
822 } else {
823 unused_--;
824 }
825 for (int i = 0; i < kStatesLog2 - 1; i++) ideals_[i] = ideals_[i + 1];
826 ideals_[kStatesLog2 - 1] = addr;
827 if (decision == 0) {
828 // Keep the left-hand-side entries (the lower half of the leaf arrays),
829 // and spread them out.
830 for (int i = kStates - 1; i >= 0; i--) {
831 int j = i >> 1;
832 costs_[i] = costs_[j];
833 regs_[0][i] = regs_[0][j];
834 regs_[1][i] = regs_[1][j];
835 }
836 } else {
837 // Keep the right-hand-side entries (the upper half of the leaf arrays),
838 // and spread them out.
839 for (int i = 0; i < kStates; i++) {
840 int j = kStates / 2 + (i >> 1);
841 costs_[i] = costs_[j];
842 regs_[0][i] = regs_[0][j];
843 regs_[1][i] = regs_[1][j];
844 }
845 }
846 for (int i = 0; i < kStates; i++) {
847 int reg = (i & 1);
848 int diff = addr - regs_[reg][i];
849 int cost = ObjectWriter::OpcodeLength(diff >> (smi_mode_ ? 0 : 2));
850 costs_[i] += cost;
851 if (!smi_mode_ || reg == 1) regs_[reg][i] = addr;
852 }
853 }
854
855 int Consult() { return script_[oracular_pronouncements_++]; }
856
857 void DoneConsulting() { ASSERT(oracular_pronouncements_ == script_.size()); }
858
859 private:
860 static const int kStatesLog2 = 6;
861 static const int kStates = 1 << kStatesLog2;
862 bool smi_mode_;
863 SnapshotWriter* writer_;
864 // We have a binary tree of k recent possible choices for choosing snapshot
865 // byte codes. The arrays represent the 2^k leaves, and the bits of the
866 // indices represent the potential choices made. For each leaf we record the
867 // cost (in bytes added to the snapshot) and the values of the two registers.
868 int costs_[kStates];
869 int regs_[2][kStates];
870 int unused_ = kStatesLog2;
871 size_t oracular_pronouncements_ = 0;
872 int ideals_[kStatesLog2];
873 Vector<int> script_;
874 PortableAddressMap* map_;
875 };
876
877 class SnapshotDecisionObjectVisitor : public HeapObjectVisitor {
878 public:
879 explicit SnapshotDecisionObjectVisitor(SnapshotOracle* oracle)
880 : oracle_(oracle) {}
881
882 virtual uword Visit(HeapObject* object) {
883 object->IterateEverything(oracle_);
884 return object->Size();
885 }
886
887 private:
888 SnapshotOracle* oracle_;
889 };
890
891 void ObjectWriter::WriteInteger(word i) {
892 // Large Smis must be purged from the heap before we serialize, since
893 // they can't be represented on small devices.
894 ASSERT(i <= 0x7fffffff);
895 ASSERT(i >= -0x7fffffff - 1);
896 int reg = smi_oracle_->Consult();
897 if (reg == 0) {
898 WriteOpcode(kSnapshotSmi, i);
899 } else {
900 int32 offset = i - writer_->recent_smi();
901 WriteOpcode(kSnapshotRecentSmi, offset);
902 writer_->set_recent_smi(i);
903 }
904 }
905
906 void ObjectWriter::WriteWord(Object* object) {
907 if (object->IsSmi()) {
908 WriteInteger(reinterpret_cast<word>(object));
909 return;
910 }
911
912 HeapObject* heap_object = HeapObject::cast(object);
913 uword ideal = address_map_->IdealizedAddress(heap_object) -
914 address_map_->doubles_size();
915 int popular_index = writer_->PopularityIndex(heap_object);
916 if (popular_index != -1) {
917 ASSERT(popular_index < kSnapshotNumberOfPopularObjects &&
918 popular_index >= 0);
919 ASSERT(kSnapshotPopular == 0);
920 ASSERT((kSnapshotPopularMask & kSnapshotPopular) == 0);
921 ASSERT((kSnapshotPopularMask & (kSnapshotNumberOfPopularObjects - 1)) == 0);
922 writer_->WriteByte(popular_index);
923 } else {
924 int reg = pointer_oracle_->Consult();
925 int offset = ideal - writer_->recent(reg);
926 WriteOpcode(kSnapshotRecentPointer + reg, offset / kIdealWordSize);
927 writer_->set_recent(reg, ideal);
928 }
929 }
930
782 void SnapshotWriter::WriteSectionBoundary(ObjectWriter* writer) { 931 void SnapshotWriter::WriteSectionBoundary(ObjectWriter* writer) {
783 writer->WriteOpcode(kSnapshotRaw, -1); 932 writer->WriteOpcode(kSnapshotRaw, -1);
784 } 933 }
785 934
786 class SnapshotWriterVisitor : public HeapObjectVisitor { 935 class SnapshotWriterVisitor : public HeapObjectVisitor {
787 public: 936 public:
788 SnapshotWriterVisitor(PortableAddressMap* map, SnapshotWriter* writer) 937 SnapshotWriterVisitor(PortableAddressMap* map, SnapshotWriter* writer,
789 : address_map_(map), writer_(writer) {} 938 SnapshotOracle* pointer_oracle,
939 SnapshotOracle* smi_oracle)
940 : address_map_(map),
941 writer_(writer),
942 pointer_oracle_(pointer_oracle),
943 smi_oracle_(smi_oracle) {}
790 944
791 virtual uword Visit(HeapObject* object) { 945 virtual uword Visit(HeapObject* object) {
792 ASSERT(!object->IsStack()); 946 ASSERT(!object->IsStack());
793 int size = object->Size(); 947 int size = object->Size();
794 if (object->IsDouble()) { 948 if (object->IsDouble()) {
795 ASSERT(doubles_mode_); 949 ASSERT(doubles_mode_);
796 writer_->WriteDouble(Double::cast(object)->value()); 950 writer_->WriteDouble(Double::cast(object)->value());
951 // We have to consume one oracular pronouncement (for the class
952 // field of the double) to keep the oracle in sync with the
953 // writer.
954 pointer_oracle_->Consult();
797 return size; 955 return size;
798 } 956 }
799 doubles_mode_ = false; 957 doubles_mode_ = false;
800 ObjectWriter object_writer(writer_, address_map_, object); 958 ObjectWriter object_writer(writer_, address_map_, pointer_oracle_,
959 smi_oracle_, object);
801 object->IterateEverything(&object_writer); 960 object->IterateEverything(&object_writer);
802 object_writer.End(object->address() + size); 961 object_writer.End(object->address() + size);
803 return size; 962 return size;
804 } 963 }
805 964
806 private: 965 private:
807 bool doubles_mode_ = true; 966 bool doubles_mode_ = true;
808 PortableAddressMap* address_map_; 967 PortableAddressMap* address_map_;
809 SnapshotWriter* writer_; 968 SnapshotWriter* writer_;
969 SnapshotOracle* pointer_oracle_;
970 SnapshotOracle* smi_oracle_;
810 }; 971 };
811 972
812 void PopularityCounter::VisitClass(Object** slot) { 973 void PopularityCounter::VisitClass(Object** slot) {
813 VisitBlock(slot, slot + 1); 974 VisitBlock(slot, slot + 1);
814 } 975 }
815 976
816 void PopularityCounter::VisitBlock(Object** start, Object** end) { 977 void PopularityCounter::VisitBlock(Object** start, Object** end) {
817 for (Object** p = start; p < end; p++) { 978 for (Object** p = start; p < end; p++) {
818 if (!(*p)->IsSmi()) { 979 if (!(*p)->IsSmi()) {
819 HeapObject* h = HeapObject::cast(*p); 980 HeapObject* h = HeapObject::cast(*p);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
879 WriteSize(portable_addresses.total_floats()); 1040 WriteSize(portable_addresses.total_floats());
880 WriteSize(portable_addresses.total_size().ComputeSizeInBytes( 1041 WriteSize(portable_addresses.total_size().ComputeSizeInBytes(
881 kBigPointerSmallFloat)); 1042 kBigPointerSmallFloat));
882 WriteSize( 1043 WriteSize(
883 portable_addresses.total_size().ComputeSizeInBytes(kBigPointerBigFloat)); 1044 portable_addresses.total_size().ComputeSizeInBytes(kBigPointerBigFloat));
884 WriteSize(portable_addresses.total_size().ComputeSizeInBytes( 1045 WriteSize(portable_addresses.total_size().ComputeSizeInBytes(
885 kSmallPointerSmallFloat)); 1046 kSmallPointerSmallFloat));
886 WriteSize(portable_addresses.total_size().ComputeSizeInBytes( 1047 WriteSize(portable_addresses.total_size().ComputeSizeInBytes(
887 kSmallPointerBigFloat)); 1048 kSmallPointerBigFloat));
888 1049
889 ObjectWriter object_writer(this, &portable_addresses); 1050 SnapshotOracle pointer_oracle(false, &portable_addresses, this);
1051 emitting_popular_list_ = true;
1052 popularity_counter_.VisitMostPopular(&pointer_oracle);
1053 emitting_popular_list_ = false;
1054 program->IterateRootsIgnoringSession(&pointer_oracle);
1055 SnapshotDecisionObjectVisitor sdov(&pointer_oracle);
1056 program->heap()->IterateObjects(&sdov);
1057 pointer_oracle.WrapUp();
1058
1059 SnapshotOracle smi_oracle(true, NULL, this);
1060 popularity_counter_.VisitMostPopular(&smi_oracle);
1061 program->IterateRootsIgnoringSession(&smi_oracle);
1062 SnapshotDecisionObjectVisitor sdov2(&smi_oracle);
1063 program->heap()->IterateObjects(&sdov2);
1064 smi_oracle.WrapUp();
1065
1066 ObjectWriter object_writer(this, &portable_addresses, &pointer_oracle,
1067 &smi_oracle);
890 1068
891 WriteSectionBoundary(&object_writer); 1069 WriteSectionBoundary(&object_writer);
892 emitting_popular_list_ = true; 1070 emitting_popular_list_ = true;
893 popularity_counter_.VisitMostPopular(&object_writer); 1071 popularity_counter_.VisitMostPopular(&object_writer);
894 emitting_popular_list_ = false; 1072 emitting_popular_list_ = false;
895 1073
896 WriteSectionBoundary(&object_writer); 1074 WriteSectionBoundary(&object_writer);
897 program->IterateRootsIgnoringSession(&object_writer); 1075 program->IterateRootsIgnoringSession(&object_writer);
898 1076
899 WriteSectionBoundary(&object_writer); 1077 WriteSectionBoundary(&object_writer);
900 SnapshotWriterVisitor writer_visitor(&portable_addresses, this); 1078 SnapshotWriterVisitor writer_visitor(&portable_addresses, this,
1079 &pointer_oracle, &smi_oracle);
901 program->heap()->IterateObjects(&writer_visitor); 1080 program->heap()->IterateObjects(&writer_visitor);
902 1081
903 WriteSectionBoundary(&object_writer); 1082 WriteSectionBoundary(&object_writer);
904 1083
1084 smi_oracle.DoneConsulting();
1085 pointer_oracle.DoneConsulting();
1086
905 List<uint8> result = snapshot_.Sublist(0, position_); 1087 List<uint8> result = snapshot_.Sublist(0, position_);
906 1088
907 program->set_snapshot_hash(ComputeSnapshotHash(result)); 1089 program->set_snapshot_hash(ComputeSnapshotHash(result));
908 1090
909 return result; 1091 return result;
910 } 1092 }
911 1093
912 void SnapshotWriter::GrowCapacity(int extra) { 1094 void SnapshotWriter::GrowCapacity(int extra) {
913 int growth = Utils::Maximum(1 * MB, extra); 1095 int growth = Utils::Maximum(1 * MB, extra);
914 int capacity = snapshot_.length() + growth; 1096 int capacity = snapshot_.length() + growth;
915 uint8* data = static_cast<uint8*>(realloc(snapshot_.data(), capacity)); 1097 uint8* data = static_cast<uint8*>(realloc(snapshot_.data(), capacity));
916 snapshot_ = List<uint8>(data, capacity); 1098 snapshot_ = List<uint8>(data, capacity);
917 } 1099 }
918 1100
919 } // namespace dartino 1101 } // namespace dartino
OLDNEW
« no previous file with comments | « src/vm/snapshot.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698