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

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: 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 4 pointers. When
Søren Gjesse 2016/06/14 08:33:49 4 -> kStatesLog2
erikcorry 2016/06/15 10:30:47 Done.
746 // a new pointer arrives, it discards half the possibilities, by making a
747 // decision on how to encode the pointer we had, 4 calls ago. Then it doubles
748 // the number of possibilities by picking either register 0 or register 1.
749 class SnapshotOracle : public PointerVisitor {
750 public:
751 SnapshotOracle(bool smi_mode, PortableAddressMap* map, SnapshotWriter* writer)
Søren Gjesse 2016/06/14 08:33:49 Would it be better to loose the smi_mode, and crea
erikcorry 2016/06/15 10:30:47 After discussion offline we agreed that this isn't
752 : smi_mode_(smi_mode), writer_(writer), map_(map) {
753 for (int i = 0; i < kStates; i++) {
Søren Gjesse 2016/06/14 08:33:49 Please mention somewhere that costs_ and regs_ hol
erikcorry 2016/06/15 10:30:48 Done.
754 costs_[i] = 0;
755 regs_[0][i] = 0;
756 regs_[1][i] = 0;
757 }
758 }
759
760 virtual void VisitInteger(uword slot) {
761 if (!smi_mode_) return;
762 word i = *reinterpret_cast<word*>(slot);
763 SimulateInput(i);
764 }
765
766 virtual void VisitLiteralInteger(int32 i) {
767 if (!smi_mode_) return;
768 SimulateInput(i);
769 }
770
771 virtual void VisitClass(Object** slot) { VisitBlock(slot, slot + 1); }
772
773 virtual void VisitBlock(Object** start, Object** end) {
774 for (Object** p = start; p < end; p++) {
775 Object* o = *p;
776 if (o->IsSmi()) {
777 if (!smi_mode_) continue;
778 SimulateInput(static_cast<int>(reinterpret_cast<word>(o)));
779 } else {
780 if (smi_mode_) continue;
781 int addr = map_->IdealizedAddress(o);
782 int popular_index = writer_->PopularityIndex(HeapObject::cast(o));
783 if (popular_index == -1) {
784 SimulateInput(addr);
785 }
786 }
787 }
788 }
789
790 void WrapUp() {
791 int bogus = kStatesLog2 - unused_;
792 for (int i = 0; i < bogus; i++) {
793 // Add four bogus entries to the list of pointers to be encoded. These
Søren Gjesse 2016/06/14 08:33:49 four -> final/enough?
erikcorry 2016/06/15 10:30:48 Done.
794 // have the effect of forcing the decision to be made on all pointers up
795 // to the last real one.
796 SimulateInput(0);
797 }
798 }
799
800 void SimulateInput(int addr) {
801 int best_cost = 1000000000;
802 int best_reg = -1;
803 for (int i = 0; i < kStates; i++) {
804 if (costs_[i] >= best_cost) continue; // Optimization.
805 for (int reg = 0; reg < 2; reg++) {
806 int diff = addr - regs_[reg][i];
807 int cost = ObjectWriter::OpcodeLength(diff >> (smi_mode_ ? 0 : 2));
808 if (costs_[i] + cost < best_cost) {
809 best_reg = ((i >> (kStatesLog2 - 1)) & 1);
810 best_cost = costs_[i] + cost;
811 }
812 }
813 }
814 // Oldest choice is in the most significant bit.
815 // Find a decision that is now made, using the oldest possibility.
816 int decision = best_reg;
817 if (unused_ == 0) {
818 script_.PushBack(decision);
819 } else {
820 unused_--;
821 }
822 for (int i = 0; i < kStatesLog2 - 1; i++) ideals_[i] = ideals_[i + 1];
823 ideals_[kStatesLog2 - 1] = addr;
824 if (decision == 0) {
825 // Keep entries 0-7, and spread them out.
Søren Gjesse 2016/06/14 08:33:49 0-7 -> lower half / left side
erikcorry 2016/06/15 10:30:48 Done.
826 for (int i = kStates - 1; i >= 0; i--) {
827 int j = i >> 1;
828 costs_[i] = costs_[j];
829 regs_[0][i] = regs_[0][j];
830 regs_[1][i] = regs_[1][j];
831 }
832 } else {
833 // Keep entries 8-15, and spread them out.
Søren Gjesse 2016/06/14 08:33:49 8-15 -> upper half / right side
erikcorry 2016/06/15 10:30:48 Done.
834 for (int i = 0; i < kStates; i++) {
835 int j = kStates / 2 + (i >> 1);
836 costs_[i] = costs_[j];
837 regs_[0][i] = regs_[0][j];
838 regs_[1][i] = regs_[1][j];
839 }
840 }
841 for (int i = 0; i < kStates; i++) {
842 int reg = (i & 1);
843 int diff = addr - regs_[reg][i];
844 int cost = ObjectWriter::OpcodeLength(diff >> (smi_mode_ ? 0 : 2));
845 costs_[i] += cost;
846 if (!smi_mode_ || reg == 1) regs_[reg][i] = addr;
847 }
848 }
849
850 int Consult() { return script_[oracular_pronouncements_++]; }
851
852 void DoneConsulting() { ASSERT(oracular_pronouncements_ == script_.size()); }
853
854 private:
855 static const int kStatesLog2 = 6;
856 static const int kStates = 1 << kStatesLog2;
857 bool smi_mode_;
858 SnapshotWriter* writer_;
859 int costs_[kStates];
860 int regs_[2][kStates];
861 int unused_ = kStatesLog2;
862 size_t oracular_pronouncements_ = 0;
863 int ideals_[kStatesLog2];
864 Vector<int> script_;
865 PortableAddressMap* map_;
866 };
867
868 class SnapshotDecisionObjectVisitor : public HeapObjectVisitor {
869 public:
870 explicit SnapshotDecisionObjectVisitor(SnapshotOracle* oracle)
871 : oracle_(oracle) {}
872
873 virtual uword Visit(HeapObject* object) {
874 object->IterateEverything(oracle_);
875 return object->Size();
876 }
877
878 private:
879 SnapshotOracle* oracle_;
880 };
881
882 void ObjectWriter::WriteInteger(word i) {
883 // Large Smis must be purged from the heap before we serialize, since
884 // they can't be represented on small devices.
885 ASSERT(i <= 0x7fffffff);
886 ASSERT(i >= -0x7fffffff - 1);
887 int reg = smi_oracle_->Consult();
888 if (reg == 0) {
889 WriteOpcode(kSnapshotSmi, i);
890 } else {
891 int32 offset = i - writer_->recent_smi();
892 WriteOpcode(kSnapshotRecentSmi, offset);
893 writer_->set_recent_smi(i);
894 }
895 }
896
897 void ObjectWriter::WriteWord(Object* object) {
898 if (object->IsSmi()) {
899 WriteInteger(reinterpret_cast<word>(object));
900 return;
901 }
902
903 HeapObject* heap_object = HeapObject::cast(object);
904 uword ideal = address_map_->IdealizedAddress(heap_object) -
905 address_map_->doubles_size();
906 int popular_index = writer_->PopularityIndex(heap_object);
907 if (popular_index != -1) {
908 ASSERT(popular_index < kSnapshotNumberOfPopularObjects &&
909 popular_index >= 0);
910 ASSERT(kSnapshotPopular == 0);
911 ASSERT((kSnapshotPopularMask & kSnapshotPopular) == 0);
912 ASSERT((kSnapshotPopularMask & (kSnapshotNumberOfPopularObjects - 1)) == 0);
913 writer_->WriteByte(popular_index);
914 } else {
915 int reg = pointer_oracle_->Consult();
916 int offset = ideal - writer_->recent(reg);
917 WriteOpcode(kSnapshotRecentPointer + reg, offset / kIdealWordSize);
918 writer_->set_recent(reg, ideal);
919 }
920 }
921
782 void SnapshotWriter::WriteSectionBoundary(ObjectWriter* writer) { 922 void SnapshotWriter::WriteSectionBoundary(ObjectWriter* writer) {
783 writer->WriteOpcode(kSnapshotRaw, -1); 923 writer->WriteOpcode(kSnapshotRaw, -1);
784 } 924 }
785 925
786 class SnapshotWriterVisitor : public HeapObjectVisitor { 926 class SnapshotWriterVisitor : public HeapObjectVisitor {
787 public: 927 public:
788 SnapshotWriterVisitor(PortableAddressMap* map, SnapshotWriter* writer) 928 SnapshotWriterVisitor(PortableAddressMap* map, SnapshotWriter* writer,
789 : address_map_(map), writer_(writer) {} 929 SnapshotOracle* pointer_oracle,
930 SnapshotOracle* smi_oracle)
931 : address_map_(map),
932 writer_(writer),
933 pointer_oracle_(pointer_oracle),
934 smi_oracle_(smi_oracle) {}
790 935
791 virtual uword Visit(HeapObject* object) { 936 virtual uword Visit(HeapObject* object) {
792 ASSERT(!object->IsStack()); 937 ASSERT(!object->IsStack());
793 int size = object->Size(); 938 int size = object->Size();
794 if (object->IsDouble()) { 939 if (object->IsDouble()) {
795 ASSERT(doubles_mode_); 940 ASSERT(doubles_mode_);
796 writer_->WriteDouble(Double::cast(object)->value()); 941 writer_->WriteDouble(Double::cast(object)->value());
942 // We have to consume one oracular pronouncement (for the class
943 // field of the double) to keep the oracle in sync with the
944 // writer.
945 pointer_oracle_->Consult();
797 return size; 946 return size;
798 } 947 }
799 doubles_mode_ = false; 948 doubles_mode_ = false;
800 ObjectWriter object_writer(writer_, address_map_, object); 949 ObjectWriter object_writer(writer_, address_map_, pointer_oracle_,
950 smi_oracle_, object);
801 object->IterateEverything(&object_writer); 951 object->IterateEverything(&object_writer);
802 object_writer.End(object->address() + size); 952 object_writer.End(object->address() + size);
803 return size; 953 return size;
804 } 954 }
805 955
806 private: 956 private:
807 bool doubles_mode_ = true; 957 bool doubles_mode_ = true;
808 PortableAddressMap* address_map_; 958 PortableAddressMap* address_map_;
809 SnapshotWriter* writer_; 959 SnapshotWriter* writer_;
960 SnapshotOracle* pointer_oracle_;
961 SnapshotOracle* smi_oracle_;
810 }; 962 };
811 963
812 void PopularityCounter::VisitClass(Object** slot) { 964 void PopularityCounter::VisitClass(Object** slot) {
813 VisitBlock(slot, slot + 1); 965 VisitBlock(slot, slot + 1);
814 } 966 }
815 967
816 void PopularityCounter::VisitBlock(Object** start, Object** end) { 968 void PopularityCounter::VisitBlock(Object** start, Object** end) {
817 for (Object** p = start; p < end; p++) { 969 for (Object** p = start; p < end; p++) {
818 if (!(*p)->IsSmi()) { 970 if (!(*p)->IsSmi()) {
819 HeapObject* h = HeapObject::cast(*p); 971 HeapObject* h = HeapObject::cast(*p);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
879 WriteSize(portable_addresses.total_floats()); 1031 WriteSize(portable_addresses.total_floats());
880 WriteSize(portable_addresses.total_size().ComputeSizeInBytes( 1032 WriteSize(portable_addresses.total_size().ComputeSizeInBytes(
881 kBigPointerSmallFloat)); 1033 kBigPointerSmallFloat));
882 WriteSize( 1034 WriteSize(
883 portable_addresses.total_size().ComputeSizeInBytes(kBigPointerBigFloat)); 1035 portable_addresses.total_size().ComputeSizeInBytes(kBigPointerBigFloat));
884 WriteSize(portable_addresses.total_size().ComputeSizeInBytes( 1036 WriteSize(portable_addresses.total_size().ComputeSizeInBytes(
885 kSmallPointerSmallFloat)); 1037 kSmallPointerSmallFloat));
886 WriteSize(portable_addresses.total_size().ComputeSizeInBytes( 1038 WriteSize(portable_addresses.total_size().ComputeSizeInBytes(
887 kSmallPointerBigFloat)); 1039 kSmallPointerBigFloat));
888 1040
889 ObjectWriter object_writer(this, &portable_addresses); 1041 SnapshotOracle pointer_oracle(false, &portable_addresses, this);
1042 emitting_popular_list_ = true;
1043 popularity_counter_.VisitMostPopular(&pointer_oracle);
1044 emitting_popular_list_ = false;
1045 program->IterateRootsIgnoringSession(&pointer_oracle);
1046 SnapshotDecisionObjectVisitor sdov(&pointer_oracle);
1047 program->heap()->IterateObjects(&sdov);
1048 pointer_oracle.WrapUp();
1049
1050 SnapshotOracle smi_oracle(true, NULL, this);
1051 popularity_counter_.VisitMostPopular(&smi_oracle);
1052 program->IterateRootsIgnoringSession(&smi_oracle);
1053 SnapshotDecisionObjectVisitor sdov2(&smi_oracle);
1054 program->heap()->IterateObjects(&sdov2);
1055 smi_oracle.WrapUp();
1056
1057 ObjectWriter object_writer(this, &portable_addresses, &pointer_oracle,
1058 &smi_oracle);
890 1059
891 WriteSectionBoundary(&object_writer); 1060 WriteSectionBoundary(&object_writer);
892 emitting_popular_list_ = true; 1061 emitting_popular_list_ = true;
893 popularity_counter_.VisitMostPopular(&object_writer); 1062 popularity_counter_.VisitMostPopular(&object_writer);
894 emitting_popular_list_ = false; 1063 emitting_popular_list_ = false;
895 1064
896 WriteSectionBoundary(&object_writer); 1065 WriteSectionBoundary(&object_writer);
897 program->IterateRootsIgnoringSession(&object_writer); 1066 program->IterateRootsIgnoringSession(&object_writer);
898 1067
899 WriteSectionBoundary(&object_writer); 1068 WriteSectionBoundary(&object_writer);
900 SnapshotWriterVisitor writer_visitor(&portable_addresses, this); 1069 SnapshotWriterVisitor writer_visitor(&portable_addresses, this,
1070 &pointer_oracle, &smi_oracle);
901 program->heap()->IterateObjects(&writer_visitor); 1071 program->heap()->IterateObjects(&writer_visitor);
902 1072
903 WriteSectionBoundary(&object_writer); 1073 WriteSectionBoundary(&object_writer);
904 1074
1075 smi_oracle.DoneConsulting();
1076 pointer_oracle.DoneConsulting();
1077
905 List<uint8> result = snapshot_.Sublist(0, position_); 1078 List<uint8> result = snapshot_.Sublist(0, position_);
906 1079
907 program->set_snapshot_hash(ComputeSnapshotHash(result)); 1080 program->set_snapshot_hash(ComputeSnapshotHash(result));
908 1081
909 return result; 1082 return result;
910 } 1083 }
911 1084
912 void SnapshotWriter::GrowCapacity(int extra) { 1085 void SnapshotWriter::GrowCapacity(int extra) {
913 int growth = Utils::Maximum(1 * MB, extra); 1086 int growth = Utils::Maximum(1 * MB, extra);
914 int capacity = snapshot_.length() + growth; 1087 int capacity = snapshot_.length() + growth;
915 uint8* data = static_cast<uint8*>(realloc(snapshot_.data(), capacity)); 1088 uint8* data = static_cast<uint8*>(realloc(snapshot_.data(), capacity));
916 snapshot_ = List<uint8>(data, capacity); 1089 snapshot_ = List<uint8>(data, capacity);
917 } 1090 }
918 1091
919 } // namespace dartino 1092 } // 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