OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |