Chromium Code Reviews| 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 |