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