summaryrefslogtreecommitdiff
path: root/deps/v8/src/serialize.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/serialize.cc')
-rw-r--r--deps/v8/src/serialize.cc1890
1 files changed, 401 insertions, 1489 deletions
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index 6eedeef37b..de87022e00 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -39,353 +39,11 @@
#include "stub-cache.h"
#include "v8threads.h"
#include "top.h"
+#include "bootstrapper.h"
namespace v8 {
namespace internal {
-// 32-bit encoding: a RelativeAddress must be able to fit in a
-// pointer: it is encoded as an Address with (from LS to MS bits):
-// - 2 bits identifying this as a HeapObject.
-// - 4 bits to encode the AllocationSpace (including special values for
-// code and fixed arrays in LO space)
-// - 27 bits identifying a word in the space, in one of three formats:
-// - paged spaces: 16 bits of page number, 11 bits of word offset in page
-// - NEW space: 27 bits of word offset
-// - LO space: 27 bits of page number
-
-const int kSpaceShift = kHeapObjectTagSize;
-const int kSpaceBits = 4;
-const int kSpaceMask = (1 << kSpaceBits) - 1;
-
-const int kOffsetShift = kSpaceShift + kSpaceBits;
-const int kOffsetBits = 11;
-const int kOffsetMask = (1 << kOffsetBits) - 1;
-
-const int kPageShift = kOffsetShift + kOffsetBits;
-const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);
-const int kPageMask = (1 << kPageBits) - 1;
-
-const int kPageAndOffsetShift = kOffsetShift;
-const int kPageAndOffsetBits = kPageBits + kOffsetBits;
-const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1;
-
-// These values are special allocation space tags used for
-// serialization.
-// Mark the pages executable on platforms that support it.
-const int kLargeCode = LAST_SPACE + 1;
-// Allocate extra remembered-set bits.
-const int kLargeFixedArray = LAST_SPACE + 2;
-
-
-static inline AllocationSpace GetSpace(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- int space_number = (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
- if (space_number > LAST_SPACE) space_number = LO_SPACE;
- return static_cast<AllocationSpace>(space_number);
-}
-
-
-static inline bool IsLargeExecutableObject(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- const int space_number =
- (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
- return (space_number == kLargeCode);
-}
-
-
-static inline bool IsLargeFixedArray(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- const int space_number =
- (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
- return (space_number == kLargeFixedArray);
-}
-
-
-static inline int PageIndex(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- return static_cast<int>(encoded >> kPageShift) & kPageMask;
-}
-
-
-static inline int PageOffset(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- const int offset = static_cast<int>(encoded >> kOffsetShift) & kOffsetMask;
- return offset << kObjectAlignmentBits;
-}
-
-
-static inline int NewSpaceOffset(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- const int page_offset =
- static_cast<int>(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;
- return page_offset << kObjectAlignmentBits;
-}
-
-
-static inline int LargeObjectIndex(Address addr) {
- const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
- return static_cast<int>(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;
-}
-
-
-// A RelativeAddress encodes a heap address that is independent of
-// the actual memory addresses in real heap. The general case (for the
-// OLD, CODE and MAP spaces) is as a (space id, page number, page offset)
-// triple. The NEW space has page number == 0, because there are no
-// pages. The LARGE_OBJECT space has page offset = 0, since there is
-// exactly one object per page. RelativeAddresses are encodable as
-// Addresses, so that they can replace the map() pointers of
-// HeapObjects. The encoded Addresses are also encoded as HeapObjects
-// and allow for marking (is_marked() see mark(), clear_mark()...) as
-// used by the Mark-Compact collector.
-
-class RelativeAddress {
- public:
- RelativeAddress(AllocationSpace space,
- int page_index,
- int page_offset)
- : space_(space), page_index_(page_index), page_offset_(page_offset) {
- // Assert that the space encoding (plus the two pseudo-spaces for
- // special large objects) fits in the available bits.
- ASSERT(((LAST_SPACE + 2) & ~kSpaceMask) == 0);
- ASSERT(space <= LAST_SPACE && space >= 0);
- }
-
- // Return the encoding of 'this' as an Address. Decode with constructor.
- Address Encode() const;
-
- AllocationSpace space() const {
- if (space_ > LAST_SPACE) return LO_SPACE;
- return static_cast<AllocationSpace>(space_);
- }
- int page_index() const { return page_index_; }
- int page_offset() const { return page_offset_; }
-
- bool in_paged_space() const {
- return space_ == CODE_SPACE ||
- space_ == OLD_POINTER_SPACE ||
- space_ == OLD_DATA_SPACE ||
- space_ == MAP_SPACE ||
- space_ == CELL_SPACE;
- }
-
- void next_address(int offset) { page_offset_ += offset; }
- void next_page(int init_offset = 0) {
- page_index_++;
- page_offset_ = init_offset;
- }
-
-#ifdef DEBUG
- void Verify();
-#endif
-
- void set_to_large_code_object() {
- ASSERT(space_ == LO_SPACE);
- space_ = kLargeCode;
- }
- void set_to_large_fixed_array() {
- ASSERT(space_ == LO_SPACE);
- space_ = kLargeFixedArray;
- }
-
-
- private:
- int space_;
- int page_index_;
- int page_offset_;
-};
-
-
-Address RelativeAddress::Encode() const {
- ASSERT(page_index_ >= 0);
- int word_offset = 0;
- int result = 0;
- switch (space_) {
- case MAP_SPACE:
- case CELL_SPACE:
- case OLD_POINTER_SPACE:
- case OLD_DATA_SPACE:
- case CODE_SPACE:
- ASSERT_EQ(0, page_index_ & ~kPageMask);
- word_offset = page_offset_ >> kObjectAlignmentBits;
- ASSERT_EQ(0, word_offset & ~kOffsetMask);
- result = (page_index_ << kPageShift) | (word_offset << kOffsetShift);
- break;
- case NEW_SPACE:
- ASSERT_EQ(0, page_index_);
- word_offset = page_offset_ >> kObjectAlignmentBits;
- ASSERT_EQ(0, word_offset & ~kPageAndOffsetMask);
- result = word_offset << kPageAndOffsetShift;
- break;
- case LO_SPACE:
- case kLargeCode:
- case kLargeFixedArray:
- ASSERT_EQ(0, page_offset_);
- ASSERT_EQ(0, page_index_ & ~kPageAndOffsetMask);
- result = page_index_ << kPageAndOffsetShift;
- break;
- }
- // OR in AllocationSpace and kHeapObjectTag
- ASSERT_EQ(0, space_ & ~kSpaceMask);
- result |= (space_ << kSpaceShift) | kHeapObjectTag;
- return reinterpret_cast<Address>(result);
-}
-
-
-#ifdef DEBUG
-void RelativeAddress::Verify() {
- ASSERT(page_offset_ >= 0 && page_index_ >= 0);
- switch (space_) {
- case MAP_SPACE:
- case CELL_SPACE:
- case OLD_POINTER_SPACE:
- case OLD_DATA_SPACE:
- case CODE_SPACE:
- ASSERT(Page::kObjectStartOffset <= page_offset_ &&
- page_offset_ <= Page::kPageSize);
- break;
- case NEW_SPACE:
- ASSERT(page_index_ == 0);
- break;
- case LO_SPACE:
- case kLargeCode:
- case kLargeFixedArray:
- ASSERT(page_offset_ == 0);
- break;
- }
-}
-#endif
-
-enum GCTreatment {
- DataObject, // Object that cannot contain a reference to new space.
- PointerObject, // Object that can contain a reference to new space.
- CodeObject // Object that contains executable code.
-};
-
-// A SimulatedHeapSpace simulates the allocation of objects in a page in
-// the heap. It uses linear allocation - that is, it doesn't simulate the
-// use of a free list. This simulated
-// allocation must exactly match that done by Heap.
-
-class SimulatedHeapSpace {
- public:
- // The default constructor initializes to an invalid state.
- SimulatedHeapSpace(): current_(LAST_SPACE, -1, -1) {}
-
- // Sets 'this' to the first address in 'space' that would be
- // returned by allocation in an empty heap.
- void InitEmptyHeap(AllocationSpace space);
-
- // Sets 'this' to the next address in 'space' that would be returned
- // by allocation in the current heap. Intended only for testing
- // serialization and deserialization in the current address space.
- void InitCurrentHeap(AllocationSpace space);
-
- // Returns the RelativeAddress where the next
- // object of 'size' bytes will be allocated, and updates 'this' to
- // point to the next free address beyond that object.
- RelativeAddress Allocate(int size, GCTreatment special_gc_treatment);
-
- private:
- RelativeAddress current_;
-};
-
-
-void SimulatedHeapSpace::InitEmptyHeap(AllocationSpace space) {
- switch (space) {
- case MAP_SPACE:
- case CELL_SPACE:
- case OLD_POINTER_SPACE:
- case OLD_DATA_SPACE:
- case CODE_SPACE:
- current_ = RelativeAddress(space, 0, Page::kObjectStartOffset);
- break;
- case NEW_SPACE:
- case LO_SPACE:
- current_ = RelativeAddress(space, 0, 0);
- break;
- }
-}
-
-
-void SimulatedHeapSpace::InitCurrentHeap(AllocationSpace space) {
- switch (space) {
- case MAP_SPACE:
- case CELL_SPACE:
- case OLD_POINTER_SPACE:
- case OLD_DATA_SPACE:
- case CODE_SPACE: {
- PagedSpace* ps;
- if (space == MAP_SPACE) {
- ps = Heap::map_space();
- } else if (space == CELL_SPACE) {
- ps = Heap::cell_space();
- } else if (space == OLD_POINTER_SPACE) {
- ps = Heap::old_pointer_space();
- } else if (space == OLD_DATA_SPACE) {
- ps = Heap::old_data_space();
- } else {
- ASSERT(space == CODE_SPACE);
- ps = Heap::code_space();
- }
- Address top = ps->top();
- Page* top_page = Page::FromAllocationTop(top);
- int page_index = 0;
- PageIterator it(ps, PageIterator::PAGES_IN_USE);
- while (it.has_next()) {
- if (it.next() == top_page) break;
- page_index++;
- }
- current_ = RelativeAddress(space,
- page_index,
- top_page->Offset(top));
- break;
- }
- case NEW_SPACE:
- current_ = RelativeAddress(space,
- 0,
- Heap::NewSpaceTop() - Heap::NewSpaceStart());
- break;
- case LO_SPACE:
- int page_index = 0;
- for (LargeObjectIterator it(Heap::lo_space()); it.has_next(); it.next()) {
- page_index++;
- }
- current_ = RelativeAddress(space, page_index, 0);
- break;
- }
-}
-
-
-RelativeAddress SimulatedHeapSpace::Allocate(int size,
- GCTreatment special_gc_treatment) {
-#ifdef DEBUG
- current_.Verify();
-#endif
- int alloc_size = OBJECT_SIZE_ALIGN(size);
- if (current_.in_paged_space() &&
- current_.page_offset() + alloc_size > Page::kPageSize) {
- ASSERT(alloc_size <= Page::kMaxHeapObjectSize);
- current_.next_page(Page::kObjectStartOffset);
- }
- RelativeAddress result = current_;
- if (current_.space() == LO_SPACE) {
- current_.next_page();
- if (special_gc_treatment == CodeObject) {
- result.set_to_large_code_object();
- } else if (special_gc_treatment == PointerObject) {
- result.set_to_large_fixed_array();
- }
- } else {
- current_.next_address(alloc_size);
- }
-#ifdef DEBUG
- current_.Verify();
- result.Verify();
-#endif
- return result;
-}
-
// -----------------------------------------------------------------------------
// Coding of external references.
@@ -489,12 +147,12 @@ void ExternalReferenceTable::Add(Address address,
TypeCode type,
uint16_t id,
const char* name) {
- CHECK_NE(NULL, address);
+ ASSERT_NE(NULL, address);
ExternalReferenceEntry entry;
entry.address = address;
entry.code = EncodeExternal(type, id);
entry.name = name;
- CHECK_NE(0, entry.code);
+ ASSERT_NE(0, entry.code);
refs_.Add(entry);
if (id > max_id_[type]) max_id_[type] = id;
}
@@ -575,7 +233,7 @@ void ExternalReferenceTable::PopulateTable() {
Debug::k_debug_break_return_address << kDebugIdShift,
"Debug::debug_break_return_address()");
const char* debug_register_format = "Debug::register_address(%i)";
- size_t dr_format_length = strlen(debug_register_format);
+ int dr_format_length = StrLength(debug_register_format);
for (int i = 0; i < kNumJSCallerSaved; ++i) {
Vector<char> name = Vector<char>::New(dr_format_length + 1);
OS::SNPrintF(name, debug_register_format, i);
@@ -623,11 +281,11 @@ void ExternalReferenceTable::PopulateTable() {
#undef C
};
- size_t top_format_length = strlen(top_address_format) - 2;
+ int top_format_length = StrLength(top_address_format) - 2;
for (uint16_t i = 0; i < Top::k_top_address_count; ++i) {
const char* address_name = AddressNames[i];
Vector<char> name =
- Vector<char>::New(top_format_length + strlen(address_name) + 1);
+ Vector<char>::New(top_format_length + StrLength(address_name) + 1);
const char* chars = name.start();
OS::SNPrintF(name, top_address_format, address_name);
Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
@@ -688,76 +346,80 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED,
3,
"Heap::roots_address()");
- Add(ExternalReference::address_of_stack_guard_limit().address(),
+ Add(ExternalReference::address_of_stack_limit().address(),
UNCLASSIFIED,
4,
"StackGuard::address_of_jslimit()");
- Add(ExternalReference::address_of_regexp_stack_limit().address(),
+ Add(ExternalReference::address_of_real_stack_limit().address(),
UNCLASSIFIED,
5,
+ "StackGuard::address_of_real_jslimit()");
+ Add(ExternalReference::address_of_regexp_stack_limit().address(),
+ UNCLASSIFIED,
+ 6,
"RegExpStack::limit_address()");
Add(ExternalReference::new_space_start().address(),
UNCLASSIFIED,
- 6,
+ 7,
"Heap::NewSpaceStart()");
Add(ExternalReference::heap_always_allocate_scope_depth().address(),
UNCLASSIFIED,
- 7,
+ 8,
"Heap::always_allocate_scope_depth()");
Add(ExternalReference::new_space_allocation_limit_address().address(),
UNCLASSIFIED,
- 8,
+ 9,
"Heap::NewSpaceAllocationLimitAddress()");
Add(ExternalReference::new_space_allocation_top_address().address(),
UNCLASSIFIED,
- 9,
+ 10,
"Heap::NewSpaceAllocationTopAddress()");
#ifdef ENABLE_DEBUGGER_SUPPORT
Add(ExternalReference::debug_break().address(),
UNCLASSIFIED,
- 10,
+ 11,
"Debug::Break()");
Add(ExternalReference::debug_step_in_fp_address().address(),
UNCLASSIFIED,
- 11,
+ 12,
"Debug::step_in_fp_addr()");
#endif
Add(ExternalReference::double_fp_operation(Token::ADD).address(),
UNCLASSIFIED,
- 12,
+ 13,
"add_two_doubles");
Add(ExternalReference::double_fp_operation(Token::SUB).address(),
UNCLASSIFIED,
- 13,
+ 14,
"sub_two_doubles");
Add(ExternalReference::double_fp_operation(Token::MUL).address(),
UNCLASSIFIED,
- 14,
+ 15,
"mul_two_doubles");
Add(ExternalReference::double_fp_operation(Token::DIV).address(),
UNCLASSIFIED,
- 15,
+ 16,
"div_two_doubles");
Add(ExternalReference::double_fp_operation(Token::MOD).address(),
UNCLASSIFIED,
- 16,
+ 17,
"mod_two_doubles");
Add(ExternalReference::compare_doubles().address(),
UNCLASSIFIED,
- 17,
+ 18,
"compare_doubles");
#ifdef V8_NATIVE_REGEXP
Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
UNCLASSIFIED,
- 18,
+ 19,
"NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
Add(ExternalReference::re_check_stack_guard_state().address(),
UNCLASSIFIED,
- 19,
+ 20,
"RegExpMacroAssembler*::CheckStackGuardState()");
Add(ExternalReference::re_grow_stack().address(),
UNCLASSIFIED,
- 20,
+ 21,
"NativeRegExpMacroAssembler::GrowStack()");
#endif
}
@@ -823,1053 +485,90 @@ ExternalReferenceDecoder::~ExternalReferenceDecoder() {
}
-//------------------------------------------------------------------------------
-// Implementation of Serializer
-
-
-// Helper class to write the bytes of the serialized heap.
-
-class SnapshotWriter {
- public:
- SnapshotWriter() {
- len_ = 0;
- max_ = 8 << 10; // 8K initial size
- str_ = NewArray<byte>(max_);
- }
-
- ~SnapshotWriter() {
- DeleteArray(str_);
- }
-
- void GetBytes(byte** str, int* len) {
- *str = NewArray<byte>(len_);
- memcpy(*str, str_, len_);
- *len = len_;
- }
-
- void Reserve(int bytes, int pos);
-
- void PutC(char c) {
- InsertC(c, len_);
- }
-
- void PutInt(int i) {
- InsertInt(i, len_);
- }
-
- void PutAddress(Address p) {
- PutBytes(reinterpret_cast<byte*>(&p), sizeof(p));
- }
-
- void PutBytes(const byte* a, int size) {
- InsertBytes(a, len_, size);
- }
-
- void PutString(const char* s) {
- InsertString(s, len_);
- }
-
- int InsertC(char c, int pos) {
- Reserve(1, pos);
- str_[pos] = c;
- len_++;
- return pos + 1;
- }
-
- int InsertInt(int i, int pos) {
- return InsertBytes(reinterpret_cast<byte*>(&i), pos, sizeof(i));
- }
-
- int InsertBytes(const byte* a, int pos, int size) {
- Reserve(size, pos);
- memcpy(&str_[pos], a, size);
- len_ += size;
- return pos + size;
- }
-
- int InsertString(const char* s, int pos);
-
- int length() { return len_; }
-
- Address position() { return reinterpret_cast<Address>(&str_[len_]); }
-
- private:
- byte* str_; // the snapshot
- int len_; // the current length of str_
- int max_; // the allocated size of str_
-};
-
-
-void SnapshotWriter::Reserve(int bytes, int pos) {
- CHECK(0 <= pos && pos <= len_);
- while (len_ + bytes >= max_) {
- max_ *= 2;
- byte* old = str_;
- str_ = NewArray<byte>(max_);
- memcpy(str_, old, len_);
- DeleteArray(old);
- }
- if (pos < len_) {
- byte* old = str_;
- str_ = NewArray<byte>(max_);
- memcpy(str_, old, pos);
- memcpy(str_ + pos + bytes, old + pos, len_ - pos);
- DeleteArray(old);
- }
-}
-
-int SnapshotWriter::InsertString(const char* s, int pos) {
- int size = strlen(s);
- pos = InsertC('[', pos);
- pos = InsertInt(size, pos);
- pos = InsertC(']', pos);
- return InsertBytes(reinterpret_cast<const byte*>(s), pos, size);
-}
-
-
-class ReferenceUpdater: public ObjectVisitor {
- public:
- ReferenceUpdater(HeapObject* obj, Serializer* serializer)
- : obj_address_(obj->address()),
- serializer_(serializer),
- reference_encoder_(serializer->reference_encoder_),
- offsets_(8),
- addresses_(8),
- offsets_32_bit_(0),
- data_32_bit_(0) {
- }
-
- virtual void VisitPointers(Object** start, Object** end) {
- for (Object** p = start; p < end; ++p) {
- if ((*p)->IsHeapObject()) {
- offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
- Address a = serializer_->GetSavedAddress(HeapObject::cast(*p));
- addresses_.Add(a);
- }
- }
- }
-
- virtual void VisitCodeTarget(RelocInfo* rinfo) {
- ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
- Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
- Address encoded_target = serializer_->GetSavedAddress(target);
- // All calls and jumps are to code objects that encode into 32 bits.
- offsets_32_bit_.Add(rinfo->target_address_address() - obj_address_);
- uint32_t small_target =
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(encoded_target));
- ASSERT(reinterpret_cast<uintptr_t>(encoded_target) == small_target);
- data_32_bit_.Add(small_target);
- }
-
-
- virtual void VisitExternalReferences(Address* start, Address* end) {
- for (Address* p = start; p < end; ++p) {
- uint32_t code = reference_encoder_->Encode(*p);
- CHECK(*p == NULL ? code == 0 : code != 0);
- offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
- addresses_.Add(reinterpret_cast<Address>(code));
- }
- }
-
- virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
- Address target = rinfo->target_address();
- uint32_t encoding = reference_encoder_->Encode(target);
- CHECK(target == NULL ? encoding == 0 : encoding != 0);
- offsets_.Add(rinfo->target_address_address() - obj_address_);
- addresses_.Add(reinterpret_cast<Address>(encoding));
- }
-
- void Update(Address start_address) {
- for (int i = 0; i < offsets_.length(); i++) {
- memcpy(start_address + offsets_[i], &addresses_[i], sizeof(Address));
- }
- for (int i = 0; i < offsets_32_bit_.length(); i++) {
- memcpy(start_address + offsets_32_bit_[i], &data_32_bit_[i],
- sizeof(uint32_t));
- }
- }
-
- private:
- Address obj_address_;
- Serializer* serializer_;
- ExternalReferenceEncoder* reference_encoder_;
- List<int> offsets_;
- List<Address> addresses_;
- // Some updates are 32-bit even on a 64-bit platform.
- // We keep a separate list of them on 64-bit platforms.
- List<int> offsets_32_bit_;
- List<uint32_t> data_32_bit_;
-};
-
-
-// Helper functions for a map of encoded heap object addresses.
-static uint32_t HeapObjectHash(HeapObject* key) {
- uint32_t low32bits = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key));
- return low32bits >> 2;
-}
-
-
-static bool MatchHeapObject(void* key1, void* key2) {
- return key1 == key2;
-}
-
-
-Serializer::Serializer()
- : global_handles_(4),
- saved_addresses_(MatchHeapObject) {
- root_ = true;
- roots_ = 0;
- objects_ = 0;
- reference_encoder_ = NULL;
- writer_ = new SnapshotWriter();
- for (int i = 0; i <= LAST_SPACE; i++) {
- allocator_[i] = new SimulatedHeapSpace();
- }
-}
-
-
-Serializer::~Serializer() {
- for (int i = 0; i <= LAST_SPACE; i++) {
- delete allocator_[i];
- }
- if (reference_encoder_) delete reference_encoder_;
- delete writer_;
-}
-
-
bool Serializer::serialization_enabled_ = false;
+bool Serializer::too_late_to_enable_now_ = false;
-#ifdef DEBUG
-static const int kMaxTagLength = 32;
-
-void Serializer::Synchronize(const char* tag) {
- if (FLAG_debug_serialization) {
- int length = strlen(tag);
- ASSERT(length <= kMaxTagLength);
- writer_->PutC('S');
- writer_->PutInt(length);
- writer_->PutBytes(reinterpret_cast<const byte*>(tag), length);
- }
-}
-#endif
-
-
-void Serializer::InitializeAllocators() {
- for (int i = 0; i <= LAST_SPACE; i++) {
- allocator_[i]->InitEmptyHeap(static_cast<AllocationSpace>(i));
- }
-}
-
-
-bool Serializer::IsVisited(HeapObject* obj) {
- HashMap::Entry* entry =
- saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
- return entry != NULL;
-}
-
-
-Address Serializer::GetSavedAddress(HeapObject* obj) {
- HashMap::Entry* entry =
- saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
- ASSERT(entry != NULL);
- return reinterpret_cast<Address>(entry->value);
-}
-
-
-void Serializer::SaveAddress(HeapObject* obj, Address addr) {
- HashMap::Entry* entry =
- saved_addresses_.Lookup(obj, HeapObjectHash(obj), true);
- entry->value = addr;
-}
-
-
-void Serializer::Serialize() {
- // No active threads.
- CHECK_EQ(NULL, ThreadState::FirstInUse());
- // No active or weak handles.
- CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
- CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
- // We need a counter function during serialization to resolve the
- // references to counters in the code on the heap.
- CHECK(StatsTable::HasCounterFunction());
- CHECK(enabled());
- InitializeAllocators();
- reference_encoder_ = new ExternalReferenceEncoder();
- PutHeader();
- Heap::IterateRoots(this);
- PutLog();
- PutContextStack();
- Disable();
-}
-
-
-void Serializer::Finalize(byte** str, int* len) {
- writer_->GetBytes(str, len);
-}
-
-
-// Serialize objects by writing them into the stream.
-
-void Serializer::VisitPointers(Object** start, Object** end) {
- bool root = root_;
- root_ = false;
- for (Object** p = start; p < end; ++p) {
- bool serialized;
- Address a = Encode(*p, &serialized);
- if (root) {
- roots_++;
- // If the object was not just serialized,
- // write its encoded address instead.
- if (!serialized) PutEncodedAddress(a);
- }
- }
- root_ = root;
-}
-
-
-void Serializer::VisitCodeTarget(RelocInfo* rinfo) {
- ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
- Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
- bool serialized;
- Encode(target, &serialized);
-}
-
-
-class GlobalHandlesRetriever: public ObjectVisitor {
- public:
- explicit GlobalHandlesRetriever(List<Object**>* handles)
- : global_handles_(handles) {}
-
- virtual void VisitPointers(Object** start, Object** end) {
- for (; start != end; ++start) {
- global_handles_->Add(start);
- }
- }
-
- private:
- List<Object**>* global_handles_;
-};
-
-
-void Serializer::PutFlags() {
- writer_->PutC('F');
- List<const char*>* argv = FlagList::argv();
- writer_->PutInt(argv->length());
- writer_->PutC('[');
- for (int i = 0; i < argv->length(); i++) {
- if (i > 0) writer_->PutC('|');
- writer_->PutString((*argv)[i]);
- DeleteArray((*argv)[i]);
- }
- writer_->PutC(']');
- flags_end_ = writer_->length();
- delete argv;
-}
-
-
-void Serializer::PutHeader() {
- PutFlags();
- writer_->PutC('D');
-#ifdef DEBUG
- writer_->PutC(FLAG_debug_serialization ? '1' : '0');
-#else
- writer_->PutC('0');
-#endif
-#ifdef V8_NATIVE_REGEXP
- writer_->PutC('N');
-#else // Interpreted regexp
- writer_->PutC('I');
-#endif
- // Write sizes of paged memory spaces. Allocate extra space for the old
- // and code spaces, because objects in new space will be promoted to them.
- writer_->PutC('S');
- writer_->PutC('[');
- writer_->PutInt(Heap::old_pointer_space()->Size() +
- Heap::new_space()->Size());
- writer_->PutC('|');
- writer_->PutInt(Heap::old_data_space()->Size() + Heap::new_space()->Size());
- writer_->PutC('|');
- writer_->PutInt(Heap::code_space()->Size() + Heap::new_space()->Size());
- writer_->PutC('|');
- writer_->PutInt(Heap::map_space()->Size());
- writer_->PutC('|');
- writer_->PutInt(Heap::cell_space()->Size());
- writer_->PutC(']');
- // Write global handles.
- writer_->PutC('G');
- writer_->PutC('[');
- GlobalHandlesRetriever ghr(&global_handles_);
- GlobalHandles::IterateRoots(&ghr);
- for (int i = 0; i < global_handles_.length(); i++) {
- writer_->PutC('N');
- }
- writer_->PutC(']');
-}
-
-
-void Serializer::PutLog() {
-#ifdef ENABLE_LOGGING_AND_PROFILING
- if (FLAG_log_code) {
- Logger::TearDown();
- int pos = writer_->InsertC('L', flags_end_);
- bool exists;
- Vector<const char> log = ReadFile(FLAG_logfile, &exists);
- writer_->InsertString(log.start(), pos);
- log.Dispose();
- }
-#endif
-}
-
-
-static int IndexOf(const List<Object**>& list, Object** element) {
- for (int i = 0; i < list.length(); i++) {
- if (list[i] == element) return i;
- }
- return -1;
-}
-
-
-void Serializer::PutGlobalHandleStack(const List<Handle<Object> >& stack) {
- writer_->PutC('[');
- writer_->PutInt(stack.length());
- for (int i = stack.length() - 1; i >= 0; i--) {
- writer_->PutC('|');
- int gh_index = IndexOf(global_handles_, stack[i].location());
- CHECK_GE(gh_index, 0);
- writer_->PutInt(gh_index);
- }
- writer_->PutC(']');
-}
-
-
-void Serializer::PutContextStack() {
- List<Context*> contexts(2);
- while (HandleScopeImplementer::instance()->HasSavedContexts()) {
- Context* context =
- HandleScopeImplementer::instance()->RestoreContext();
- contexts.Add(context);
- }
- for (int i = contexts.length() - 1; i >= 0; i--) {
- HandleScopeImplementer::instance()->SaveContext(contexts[i]);
- }
- writer_->PutC('C');
- writer_->PutC('[');
- writer_->PutInt(contexts.length());
- if (!contexts.is_empty()) {
- Object** start = reinterpret_cast<Object**>(&contexts.first());
- VisitPointers(start, start + contexts.length());
- }
- writer_->PutC(']');
-}
-
-void Serializer::PutEncodedAddress(Address addr) {
- writer_->PutC('P');
- writer_->PutAddress(addr);
-}
-
-
-Address Serializer::Encode(Object* o, bool* serialized) {
- *serialized = false;
- if (o->IsSmi()) {
- return reinterpret_cast<Address>(o);
- } else {
- HeapObject* obj = HeapObject::cast(o);
- if (IsVisited(obj)) {
- return GetSavedAddress(obj);
- } else {
- // First visit: serialize the object.
- *serialized = true;
- return PutObject(obj);
- }
- }
-}
-
-
-Address Serializer::PutObject(HeapObject* obj) {
- Map* map = obj->map();
- InstanceType type = map->instance_type();
- int size = obj->SizeFromMap(map);
-
- // Simulate the allocation of obj to predict where it will be
- // allocated during deserialization.
- Address addr = Allocate(obj).Encode();
-
- SaveAddress(obj, addr);
-
- if (type == CODE_TYPE) {
- LOG(CodeMoveEvent(obj->address(), addr));
- }
-
- // Write out the object prologue: type, size, and simulated address of obj.
- writer_->PutC('[');
- CHECK_EQ(0, static_cast<int>(size & kObjectAlignmentMask));
- writer_->PutInt(type);
- writer_->PutInt(size >> kObjectAlignmentBits);
- PutEncodedAddress(addr); // encodes AllocationSpace
-
- // Visit all the pointers in the object other than the map. This
- // will recursively serialize any as-yet-unvisited objects.
- obj->Iterate(this);
-
- // Mark end of recursively embedded objects, start of object body.
- writer_->PutC('|');
- // Write out the raw contents of the object. No compression, but
- // fast to deserialize.
- writer_->PutBytes(obj->address(), size);
- // Update pointers and external references in the written object.
- ReferenceUpdater updater(obj, this);
- obj->Iterate(&updater);
- updater.Update(writer_->position() - size);
-
-#ifdef DEBUG
- if (FLAG_debug_serialization) {
- // Write out the object epilogue to catch synchronization errors.
- PutEncodedAddress(addr);
- writer_->PutC(']');
- }
-#endif
-
- objects_++;
- return addr;
-}
-
-
-RelativeAddress Serializer::Allocate(HeapObject* obj) {
- // Find out which AllocationSpace 'obj' is in.
- AllocationSpace s;
- bool found = false;
- for (int i = FIRST_SPACE; !found && i <= LAST_SPACE; i++) {
- s = static_cast<AllocationSpace>(i);
- found = Heap::InSpace(obj, s);
- }
- CHECK(found);
- int size = obj->Size();
- if (s == NEW_SPACE) {
- if (size > Heap::MaxObjectSizeInPagedSpace()) {
- s = LO_SPACE;
- } else {
- OldSpace* space = Heap::TargetSpace(obj);
- ASSERT(space == Heap::old_pointer_space() ||
- space == Heap::old_data_space());
- s = (space == Heap::old_pointer_space()) ?
- OLD_POINTER_SPACE :
- OLD_DATA_SPACE;
- }
- }
- GCTreatment gc_treatment = DataObject;
- if (obj->IsFixedArray()) gc_treatment = PointerObject;
- else if (obj->IsCode()) gc_treatment = CodeObject;
- return allocator_[s]->Allocate(size, gc_treatment);
-}
-
-
-//------------------------------------------------------------------------------
-// Implementation of Deserializer
-
-
-static const int kInitArraySize = 32;
-
-
-Deserializer::Deserializer(const byte* str, int len)
- : reader_(str, len),
- map_pages_(kInitArraySize),
- cell_pages_(kInitArraySize),
- old_pointer_pages_(kInitArraySize),
- old_data_pages_(kInitArraySize),
- code_pages_(kInitArraySize),
- large_objects_(kInitArraySize),
- global_handles_(4) {
- root_ = true;
- roots_ = 0;
- objects_ = 0;
- reference_decoder_ = NULL;
-#ifdef DEBUG
- expect_debug_information_ = false;
-#endif
-}
-
-
-Deserializer::~Deserializer() {
- if (reference_decoder_) delete reference_decoder_;
-}
-
-
-void Deserializer::ExpectEncodedAddress(Address expected) {
- Address a = GetEncodedAddress();
- USE(a);
- ASSERT(a == expected);
-}
-
-
-#ifdef DEBUG
-void Deserializer::Synchronize(const char* tag) {
- if (expect_debug_information_) {
- char buf[kMaxTagLength];
- reader_.ExpectC('S');
- int length = reader_.GetInt();
- ASSERT(length <= kMaxTagLength);
- reader_.GetBytes(reinterpret_cast<Address>(buf), length);
- ASSERT_EQ(strlen(tag), length);
- ASSERT(strncmp(tag, buf, length) == 0);
- }
-}
-#endif
-
-
-class NoGlobalHandlesChecker : public ObjectVisitor {
- public:
- virtual void VisitPointers(Object** start, Object** end) {
- ASSERT(false);
- }
-};
-
-
-class GlobalHandleDestroyer : public ObjectVisitor {
- void VisitPointers(Object**start, Object**end) {
- while (start < end) {
- GlobalHandles::Destroy(start++);
- }
- }
-};
-
-
-void Deserializer::Deserialize() {
- // No global handles.
- NoGlobalHandlesChecker checker;
- GlobalHandles::IterateRoots(&checker);
- // No active threads.
- ASSERT_EQ(NULL, ThreadState::FirstInUse());
- // No active handles.
- ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
- reference_decoder_ = new ExternalReferenceDecoder();
- // By setting linear allocation only, we forbid the use of free list
- // allocation which is not predicted by SimulatedAddress.
- GetHeader();
- Heap::IterateRoots(this);
- GetContextStack();
- // Any global handles that have been set up by deserialization are leaked
- // since noone is keeping track of them. So we discard them now.
- GlobalHandleDestroyer destroyer;
- GlobalHandles::IterateRoots(&destroyer);
-}
-
-
-void Deserializer::VisitPointers(Object** start, Object** end) {
- bool root = root_;
- root_ = false;
- for (Object** p = start; p < end; ++p) {
- if (root) {
- roots_++;
- // Read the next object or pointer from the stream
- // pointer in the stream.
- int c = reader_.GetC();
- if (c == '[') {
- *p = GetObject(); // embedded object
- } else {
- ASSERT(c == 'P'); // pointer to previously serialized object
- *p = Resolve(reader_.GetAddress());
- }
- } else {
- // A pointer internal to a HeapObject that we've already
- // read: resolve it to a true address (or Smi)
- *p = Resolve(reinterpret_cast<Address>(*p));
- }
- }
- root_ = root;
-}
-
-
-void Deserializer::VisitCodeTarget(RelocInfo* rinfo) {
- ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
- // On all platforms, the encoded code object address is only 32 bits.
- Address encoded_address = reinterpret_cast<Address>(Memory::uint32_at(
- reinterpret_cast<Address>(rinfo->target_object_address())));
- Code* target_object = reinterpret_cast<Code*>(Resolve(encoded_address));
- rinfo->set_target_address(target_object->instruction_start());
-}
-
-
-void Deserializer::VisitExternalReferences(Address* start, Address* end) {
- for (Address* p = start; p < end; ++p) {
- uint32_t code = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(*p));
- *p = reference_decoder_->Decode(code);
- }
-}
-
-
-void Deserializer::VisitRuntimeEntry(RelocInfo* rinfo) {
- uint32_t* pc = reinterpret_cast<uint32_t*>(rinfo->target_address_address());
- uint32_t encoding = *pc;
- Address target = reference_decoder_->Decode(encoding);
- rinfo->set_target_address(target);
-}
-
-
-void Deserializer::GetFlags() {
- reader_.ExpectC('F');
- int argc = reader_.GetInt() + 1;
- char** argv = NewArray<char*>(argc);
- reader_.ExpectC('[');
- for (int i = 1; i < argc; i++) {
- if (i > 1) reader_.ExpectC('|');
- argv[i] = reader_.GetString();
- }
- reader_.ExpectC(']');
- has_log_ = false;
- for (int i = 1; i < argc; i++) {
- if (strcmp("--log_code", argv[i]) == 0) {
- has_log_ = true;
- } else if (strcmp("--nouse_ic", argv[i]) == 0) {
- FLAG_use_ic = false;
- } else if (strcmp("--debug_code", argv[i]) == 0) {
- FLAG_debug_code = true;
- } else if (strcmp("--nolazy", argv[i]) == 0) {
- FLAG_lazy = false;
- }
- DeleteArray(argv[i]);
- }
-
- DeleteArray(argv);
-}
-
-
-void Deserializer::GetLog() {
- if (has_log_) {
- reader_.ExpectC('L');
- char* snapshot_log = reader_.GetString();
-#ifdef ENABLE_LOGGING_AND_PROFILING
- if (FLAG_log_code) {
- LOG(Preamble(snapshot_log));
- }
-#endif
- DeleteArray(snapshot_log);
- }
-}
-
-
-static void InitPagedSpace(PagedSpace* space,
- int capacity,
- List<Page*>* page_list) {
- if (!space->EnsureCapacity(capacity)) {
- V8::FatalProcessOutOfMemory("InitPagedSpace");
- }
- PageIterator it(space, PageIterator::ALL_PAGES);
- while (it.has_next()) page_list->Add(it.next());
-}
-
-
-void Deserializer::GetHeader() {
- reader_.ExpectC('D');
-#ifdef DEBUG
- expect_debug_information_ = reader_.GetC() == '1';
-#else
- // In release mode, don't attempt to read a snapshot containing
- // synchronization tags.
- if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags.");
-#endif
-#ifdef V8_NATIVE_REGEXP
- reader_.ExpectC('N');
-#else // Interpreted regexp.
- reader_.ExpectC('I');
-#endif
- // Ensure sufficient capacity in paged memory spaces to avoid growth
- // during deserialization.
- reader_.ExpectC('S');
- reader_.ExpectC('[');
- InitPagedSpace(Heap::old_pointer_space(),
- reader_.GetInt(),
- &old_pointer_pages_);
- reader_.ExpectC('|');
- InitPagedSpace(Heap::old_data_space(), reader_.GetInt(), &old_data_pages_);
- reader_.ExpectC('|');
- InitPagedSpace(Heap::code_space(), reader_.GetInt(), &code_pages_);
- reader_.ExpectC('|');
- InitPagedSpace(Heap::map_space(), reader_.GetInt(), &map_pages_);
- reader_.ExpectC('|');
- InitPagedSpace(Heap::cell_space(), reader_.GetInt(), &cell_pages_);
- reader_.ExpectC(']');
- // Create placeholders for global handles later to be fill during
- // IterateRoots.
- reader_.ExpectC('G');
- reader_.ExpectC('[');
- int c = reader_.GetC();
- while (c != ']') {
- ASSERT(c == 'N');
- global_handles_.Add(GlobalHandles::Create(NULL).location());
- c = reader_.GetC();
- }
-}
-
-
-void Deserializer::GetGlobalHandleStack(List<Handle<Object> >* stack) {
- reader_.ExpectC('[');
- int length = reader_.GetInt();
- for (int i = 0; i < length; i++) {
- reader_.ExpectC('|');
- int gh_index = reader_.GetInt();
- stack->Add(global_handles_[gh_index]);
- }
- reader_.ExpectC(']');
-}
-
-
-void Deserializer::GetContextStack() {
- reader_.ExpectC('C');
- CHECK_EQ(reader_.GetC(), '[');
- int count = reader_.GetInt();
- List<Context*> entered_contexts(count);
- if (count > 0) {
- Object** start = reinterpret_cast<Object**>(&entered_contexts.first());
- VisitPointers(start, start + count);
- }
- reader_.ExpectC(']');
- for (int i = 0; i < count; i++) {
- HandleScopeImplementer::instance()->SaveContext(entered_contexts[i]);
- }
-}
-
-
-Address Deserializer::GetEncodedAddress() {
- reader_.ExpectC('P');
- return reader_.GetAddress();
-}
-
-
-Object* Deserializer::GetObject() {
- // Read the prologue: type, size and encoded address.
- InstanceType type = static_cast<InstanceType>(reader_.GetInt());
- int size = reader_.GetInt() << kObjectAlignmentBits;
- Address a = GetEncodedAddress();
-
- // Get a raw object of the right size in the right space.
- AllocationSpace space = GetSpace(a);
- Object* o;
- if (IsLargeExecutableObject(a)) {
- o = Heap::lo_space()->AllocateRawCode(size);
- } else if (IsLargeFixedArray(a)) {
- o = Heap::lo_space()->AllocateRawFixedArray(size);
- } else {
- AllocationSpace retry_space = (space == NEW_SPACE)
- ? Heap::TargetSpaceId(type)
- : space;
- o = Heap::AllocateRaw(size, space, retry_space);
- }
- ASSERT(!o->IsFailure());
- // Check that the simulation of heap allocation was correct.
- ASSERT(o == Resolve(a));
-
- // Read any recursively embedded objects.
- int c = reader_.GetC();
- while (c == '[') {
- GetObject();
- c = reader_.GetC();
- }
- ASSERT(c == '|');
-
- HeapObject* obj = reinterpret_cast<HeapObject*>(o);
- // Read the uninterpreted contents of the object after the map
- reader_.GetBytes(obj->address(), size);
-#ifdef DEBUG
- if (expect_debug_information_) {
- // Read in the epilogue to check that we're still synchronized
- ExpectEncodedAddress(a);
- reader_.ExpectC(']');
- }
-#endif
-
- // Resolve the encoded pointers we just read in.
- // Same as obj->Iterate(this), but doesn't rely on the map pointer being set.
- VisitPointer(reinterpret_cast<Object**>(obj->address()));
- obj->IterateBody(type, size, this);
-
- if (type == CODE_TYPE) {
- LOG(CodeMoveEvent(a, obj->address()));
- }
- objects_++;
- return o;
-}
-
-
-static inline Object* ResolvePaged(int page_index,
- int page_offset,
- PagedSpace* space,
- List<Page*>* page_list) {
- ASSERT(page_index < page_list->length());
- Address address = (*page_list)[page_index]->OffsetToAddress(page_offset);
- return HeapObject::FromAddress(address);
-}
-
-
-template<typename T>
-void ConcatReversed(List<T>* target, const List<T>& source) {
- for (int i = source.length() - 1; i >= 0; i--) {
- target->Add(source[i]);
- }
-}
-
-
-Object* Deserializer::Resolve(Address encoded) {
- Object* o = reinterpret_cast<Object*>(encoded);
- if (o->IsSmi()) return o;
-
- // Encoded addresses of HeapObjects always have 'HeapObject' tags.
- ASSERT(o->IsHeapObject());
- switch (GetSpace(encoded)) {
- // For Map space and Old space, we cache the known Pages in map_pages,
- // old_pointer_pages and old_data_pages. Even though MapSpace keeps a list
- // of page addresses, we don't rely on it since GetObject uses AllocateRaw,
- // and that appears not to update the page list.
- case MAP_SPACE:
- return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
- Heap::map_space(), &map_pages_);
- case CELL_SPACE:
- return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
- Heap::cell_space(), &cell_pages_);
- case OLD_POINTER_SPACE:
- return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
- Heap::old_pointer_space(), &old_pointer_pages_);
- case OLD_DATA_SPACE:
- return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
- Heap::old_data_space(), &old_data_pages_);
- case CODE_SPACE:
- return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
- Heap::code_space(), &code_pages_);
- case NEW_SPACE:
- return HeapObject::FromAddress(Heap::NewSpaceStart() +
- NewSpaceOffset(encoded));
- case LO_SPACE:
- // Cache the known large_objects, allocated one per 'page'
- int index = LargeObjectIndex(encoded);
- if (index >= large_objects_.length()) {
- int new_object_count =
- Heap::lo_space()->PageCount() - large_objects_.length();
- List<Object*> new_objects(new_object_count);
- LargeObjectIterator it(Heap::lo_space());
- for (int i = 0; i < new_object_count; i++) {
- new_objects.Add(it.next());
- }
-#ifdef DEBUG
- for (int i = large_objects_.length() - 1; i >= 0; i--) {
- ASSERT(it.next() == large_objects_[i]);
- }
-#endif
- ConcatReversed(&large_objects_, new_objects);
- ASSERT(index < large_objects_.length());
- }
- return large_objects_[index]; // s.page_offset() is ignored.
- }
- UNREACHABLE();
- return NULL;
-}
-
-
-Deserializer2::Deserializer2(SnapshotByteSource* source)
+Deserializer::Deserializer(SnapshotByteSource* source)
: source_(source),
external_reference_decoder_(NULL) {
- for (int i = 0; i <= LAST_SPACE; i++) {
- fullness_[i] = 0;
- }
}
// This routine both allocates a new object, and also keeps
// track of where objects have been allocated so that we can
// fix back references when deserializing.
-Address Deserializer2::Allocate(int space_index, int size) {
- HeapObject* new_object;
- int old_fullness = CurrentAllocationAddress(space_index);
- // When we start a new page we need to record its location.
- bool record_page = (old_fullness == 0);
- if (SpaceIsPaged(space_index)) {
- PagedSpace* space;
- switch (space_index) {
- case OLD_DATA_SPACE: space = Heap::old_data_space(); break;
- case OLD_POINTER_SPACE: space = Heap::old_pointer_space(); break;
- case MAP_SPACE: space = Heap::map_space(); break;
- case CODE_SPACE: space = Heap::code_space(); break;
- case CELL_SPACE: space = Heap::cell_space(); break;
- default: UNREACHABLE(); space = NULL; break;
- }
- ASSERT(size <= Page::kPageSize - Page::kObjectStartOffset);
- int current_page = old_fullness >> Page::kPageSizeBits;
- int new_fullness = old_fullness + size;
- int new_page = new_fullness >> Page::kPageSizeBits;
- // What is our new position within the current page.
- int intra_page_offset = new_fullness - current_page * Page::kPageSize;
- if (intra_page_offset > Page::kPageSize - Page::kObjectStartOffset) {
- // This object will not fit in a page and we have to move to the next.
- new_page = current_page + 1;
- old_fullness = new_page << Page::kPageSizeBits;
- new_fullness = old_fullness + size;
- record_page = true;
+Address Deserializer::Allocate(int space_index, Space* space, int size) {
+ Address address;
+ if (!SpaceIsLarge(space_index)) {
+ ASSERT(!SpaceIsPaged(space_index) ||
+ size <= Page::kPageSize - Page::kObjectStartOffset);
+ Object* new_allocation;
+ if (space_index == NEW_SPACE) {
+ new_allocation = reinterpret_cast<NewSpace*>(space)->AllocateRaw(size);
+ } else {
+ new_allocation = reinterpret_cast<PagedSpace*>(space)->AllocateRaw(size);
}
- fullness_[space_index] = new_fullness;
- Object* new_allocation = space->AllocateRaw(size);
- new_object = HeapObject::cast(new_allocation);
+ HeapObject* new_object = HeapObject::cast(new_allocation);
ASSERT(!new_object->IsFailure());
- ASSERT((reinterpret_cast<intptr_t>(new_object->address()) &
- Page::kPageAlignmentMask) ==
- (old_fullness & Page::kPageAlignmentMask) +
- Page::kObjectStartOffset);
- } else if (SpaceIsLarge(space_index)) {
+ address = new_object->address();
+ high_water_[space_index] = address + size;
+ } else {
+ ASSERT(SpaceIsLarge(space_index));
ASSERT(size > Page::kPageSize - Page::kObjectStartOffset);
- fullness_[LO_SPACE]++;
- LargeObjectSpace* lo_space = Heap::lo_space();
+ LargeObjectSpace* lo_space = reinterpret_cast<LargeObjectSpace*>(space);
Object* new_allocation;
if (space_index == kLargeData) {
new_allocation = lo_space->AllocateRaw(size);
} else if (space_index == kLargeFixedArray) {
new_allocation = lo_space->AllocateRawFixedArray(size);
} else {
- ASSERT(space_index == kLargeCode);
+ ASSERT_EQ(kLargeCode, space_index);
new_allocation = lo_space->AllocateRawCode(size);
}
ASSERT(!new_allocation->IsFailure());
- new_object = HeapObject::cast(new_allocation);
- record_page = true;
- // The page recording below records all large objects in the same space.
- space_index = LO_SPACE;
- } else {
- ASSERT(space_index == NEW_SPACE);
- Object* new_allocation = Heap::new_space()->AllocateRaw(size);
- fullness_[space_index] += size;
- ASSERT(!new_allocation->IsFailure());
- new_object = HeapObject::cast(new_allocation);
- }
- Address address = new_object->address();
- if (record_page) {
- pages_[space_index].Add(address);
+ HeapObject* new_object = HeapObject::cast(new_allocation);
+ // Record all large objects in the same space.
+ address = new_object->address();
+ high_water_[LO_SPACE] = address + size;
}
+ last_object_address_ = address;
return address;
}
// This returns the address of an object that has been described in the
// snapshot as being offset bytes back in a particular space.
-HeapObject* Deserializer2::GetAddress(int space) {
+HeapObject* Deserializer::GetAddressFromEnd(int space) {
+ int offset = source_->GetInt();
+ ASSERT(!SpaceIsLarge(space));
+ offset <<= kObjectAlignmentBits;
+ return HeapObject::FromAddress(high_water_[space] - offset);
+}
+
+
+// This returns the address of an object that has been described in the
+// snapshot as being offset bytes into a particular space.
+HeapObject* Deserializer::GetAddressFromStart(int space) {
int offset = source_->GetInt();
if (SpaceIsLarge(space)) {
// Large spaces have one object per 'page'.
- return HeapObject::FromAddress(
- pages_[LO_SPACE][fullness_[LO_SPACE] - offset]);
+ return HeapObject::FromAddress(pages_[LO_SPACE][offset]);
}
offset <<= kObjectAlignmentBits;
if (space == NEW_SPACE) {
// New space has only one space - numbered 0.
- return HeapObject::FromAddress(
- pages_[space][0] + fullness_[space] - offset);
+ return HeapObject::FromAddress(pages_[space][0] + offset);
}
ASSERT(SpaceIsPaged(space));
- int virtual_address = fullness_[space] - offset;
- int page_of_pointee = (virtual_address) >> Page::kPageSizeBits;
+ int page_of_pointee = offset >> Page::kPageSizeBits;
Address object_address = pages_[space][page_of_pointee] +
- (virtual_address & Page::kPageAlignmentMask);
+ (offset & Page::kPageAlignmentMask);
return HeapObject::FromAddress(object_address);
}
-void Deserializer2::Deserialize() {
+void Deserializer::Deserialize() {
// Don't GC while deserializing - just expand the heap.
AlwaysAllocateScope always_allocate;
// Don't use the free lists while deserializing.
@@ -1878,9 +577,9 @@ void Deserializer2::Deserialize() {
ASSERT_EQ(NULL, ThreadState::FirstInUse());
// No active handles.
ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
- ASSERT(external_reference_decoder_ == NULL);
+ ASSERT_EQ(NULL, external_reference_decoder_);
external_reference_decoder_ = new ExternalReferenceDecoder();
- Heap::IterateRoots(this);
+ Heap::IterateRoots(this, VISIT_ONLY_STRONG);
ASSERT(source_->AtEOF());
delete external_reference_decoder_;
external_reference_decoder_ = NULL;
@@ -1888,20 +587,11 @@ void Deserializer2::Deserialize() {
// This is called on the roots. It is the driver of the deserialization
-// process.
-void Deserializer2::VisitPointers(Object** start, Object** end) {
- for (Object** current = start; current < end; current++) {
- DataType data = static_cast<DataType>(source_->Get());
- if (data == SMI_SERIALIZATION) {
- *current = Smi::FromInt(source_->GetInt() - kSmiBias);
- } else if (data == BACKREF_SERIALIZATION) {
- int space = source_->Get();
- *current = GetAddress(space);
- } else {
- ASSERT(data == OBJECT_SERIALIZATION);
- ReadObject(current);
- }
- }
+// process. It is also called on the body of each function.
+void Deserializer::VisitPointers(Object** start, Object** end) {
+ // The space must be new space. Any other space would cause ReadChunk to try
+ // to update the remembered using NULL as the address.
+ ReadChunk(start, end, NEW_SPACE, NULL);
}
@@ -1911,42 +601,106 @@ void Deserializer2::VisitPointers(Object** start, Object** end) {
// written very late, which means the ByteArray map is not set up by the
// time we need to use it to mark the space at the end of a page free (by
// making it into a byte array).
-bool Deserializer2::ReadObject(Object** write_back) {
- int space = source_->Get();
+void Deserializer::ReadObject(int space_number,
+ Space* space,
+ Object** write_back) {
int size = source_->GetInt() << kObjectAlignmentBits;
- Address address = Allocate(space, size);
+ Address address = Allocate(space_number, space, size);
*write_back = HeapObject::FromAddress(address);
Object** current = reinterpret_cast<Object**>(address);
Object** limit = current + (size >> kPointerSizeLog2);
+ ReadChunk(current, limit, space_number, address);
+}
+
+
+#define ONE_CASE_PER_SPACE(base_tag) \
+ case (base_tag) + NEW_SPACE: /* NOLINT */ \
+ case (base_tag) + OLD_POINTER_SPACE: /* NOLINT */ \
+ case (base_tag) + OLD_DATA_SPACE: /* NOLINT */ \
+ case (base_tag) + CODE_SPACE: /* NOLINT */ \
+ case (base_tag) + MAP_SPACE: /* NOLINT */ \
+ case (base_tag) + CELL_SPACE: /* NOLINT */ \
+ case (base_tag) + kLargeData: /* NOLINT */ \
+ case (base_tag) + kLargeCode: /* NOLINT */ \
+ case (base_tag) + kLargeFixedArray: /* NOLINT */
+
+
+void Deserializer::ReadChunk(Object** current,
+ Object** limit,
+ int space,
+ Address address) {
while (current < limit) {
- DataType data = static_cast<DataType>(source_->Get());
+ int data = source_->Get();
switch (data) {
- case SMI_SERIALIZATION:
- *current++ = Smi::FromInt(source_->GetInt() - kSmiBias);
- break;
+#define RAW_CASE(index, size) \
+ case RAW_DATA_SERIALIZATION + index: { \
+ byte* raw_data_out = reinterpret_cast<byte*>(current); \
+ source_->CopyRaw(raw_data_out, size); \
+ current = reinterpret_cast<Object**>(raw_data_out + size); \
+ break; \
+ }
+ COMMON_RAW_LENGTHS(RAW_CASE)
+#undef RAW_CASE
case RAW_DATA_SERIALIZATION: {
int size = source_->GetInt();
byte* raw_data_out = reinterpret_cast<byte*>(current);
- for (int j = 0; j < size; j++) {
- *raw_data_out++ = source_->Get();
- }
- current = reinterpret_cast<Object**>(raw_data_out);
+ source_->CopyRaw(raw_data_out, size);
+ current = reinterpret_cast<Object**>(raw_data_out + size);
break;
}
- case OBJECT_SERIALIZATION: {
- // Recurse to unpack an object that is forward-referenced from here.
- bool in_new_space = ReadObject(current);
- if (in_new_space && space != NEW_SPACE) {
- Heap::RecordWrite(address,
- reinterpret_cast<Address>(current) - address);
+ case OBJECT_SERIALIZATION + NEW_SPACE: {
+ ReadObject(NEW_SPACE, Heap::new_space(), current);
+ if (space != NEW_SPACE) {
+ Heap::RecordWrite(address, static_cast<int>(
+ reinterpret_cast<Address>(current) - address));
}
current++;
break;
}
- case CODE_OBJECT_SERIALIZATION: {
+ case OBJECT_SERIALIZATION + OLD_DATA_SPACE:
+ ReadObject(OLD_DATA_SPACE, Heap::old_data_space(), current++);
+ break;
+ case OBJECT_SERIALIZATION + OLD_POINTER_SPACE:
+ ReadObject(OLD_POINTER_SPACE, Heap::old_pointer_space(), current++);
+ break;
+ case OBJECT_SERIALIZATION + MAP_SPACE:
+ ReadObject(MAP_SPACE, Heap::map_space(), current++);
+ break;
+ case OBJECT_SERIALIZATION + CODE_SPACE:
+ ReadObject(CODE_SPACE, Heap::code_space(), current++);
+ Logger::LogCodeObject(current[-1]);
+ break;
+ case OBJECT_SERIALIZATION + CELL_SPACE:
+ ReadObject(CELL_SPACE, Heap::cell_space(), current++);
+ break;
+ case OBJECT_SERIALIZATION + kLargeData:
+ ReadObject(kLargeData, Heap::lo_space(), current++);
+ break;
+ case OBJECT_SERIALIZATION + kLargeCode:
+ ReadObject(kLargeCode, Heap::lo_space(), current++);
+ Logger::LogCodeObject(current[-1]);
+ break;
+ case OBJECT_SERIALIZATION + kLargeFixedArray:
+ ReadObject(kLargeFixedArray, Heap::lo_space(), current++);
+ break;
+ case CODE_OBJECT_SERIALIZATION + kLargeCode: {
+ Object* new_code_object = NULL;
+ ReadObject(kLargeCode, Heap::lo_space(), &new_code_object);
+ Code* code_object = reinterpret_cast<Code*>(new_code_object);
+ Logger::LogCodeObject(code_object);
+ // Setting a branch/call to another code object from code.
+ Address location_of_branch_data = reinterpret_cast<Address>(current);
+ Assembler::set_target_at(location_of_branch_data,
+ code_object->instruction_start());
+ location_of_branch_data += Assembler::kCallTargetSize;
+ current = reinterpret_cast<Object**>(location_of_branch_data);
+ break;
+ }
+ case CODE_OBJECT_SERIALIZATION + CODE_SPACE: {
Object* new_code_object = NULL;
- ReadObject(&new_code_object);
+ ReadObject(CODE_SPACE, Heap::code_space(), &new_code_object);
Code* code_object = reinterpret_cast<Code*>(new_code_object);
+ Logger::LogCodeObject(code_object);
// Setting a branch/call to another code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
Assembler::set_target_at(location_of_branch_data,
@@ -1955,21 +709,42 @@ bool Deserializer2::ReadObject(Object** write_back) {
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
}
- case BACKREF_SERIALIZATION: {
+ ONE_CASE_PER_SPACE(BACKREF_SERIALIZATION) {
// Write a backreference to an object we unpacked earlier.
- int backref_space = source_->Get();
+ int backref_space = (data & kSpaceMask);
if (backref_space == NEW_SPACE && space != NEW_SPACE) {
- Heap::RecordWrite(address,
- reinterpret_cast<Address>(current) - address);
+ Heap::RecordWrite(address, static_cast<int>(
+ reinterpret_cast<Address>(current) - address));
+ }
+ *current++ = GetAddressFromEnd(backref_space);
+ break;
+ }
+ ONE_CASE_PER_SPACE(REFERENCE_SERIALIZATION) {
+ // Write a reference to an object we unpacked earlier.
+ int reference_space = (data & kSpaceMask);
+ if (reference_space == NEW_SPACE && space != NEW_SPACE) {
+ Heap::RecordWrite(address, static_cast<int>(
+ reinterpret_cast<Address>(current) - address));
}
- *current++ = GetAddress(backref_space);
+ *current++ = GetAddressFromStart(reference_space);
break;
}
- case CODE_BACKREF_SERIALIZATION: {
- int backref_space = source_->Get();
+#define COMMON_REFS_CASE(index, reference_space, address) \
+ case REFERENCE_SERIALIZATION + index: { \
+ ASSERT(SpaceIsPaged(reference_space)); \
+ Address object_address = \
+ pages_[reference_space][0] + (address << kObjectAlignmentBits); \
+ *current++ = HeapObject::FromAddress(object_address); \
+ break; \
+ }
+ COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
+#undef COMMON_REFS_CASE
+ ONE_CASE_PER_SPACE(CODE_BACKREF_SERIALIZATION) {
+ int backref_space = (data & kSpaceMask);
// Can't use Code::cast because heap is not set up yet and assertions
// will fail.
- Code* code_object = reinterpret_cast<Code*>(GetAddress(backref_space));
+ Code* code_object =
+ reinterpret_cast<Code*>(GetAddressFromEnd(backref_space));
// Setting a branch/call to previously decoded code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
Assembler::set_target_at(location_of_branch_data,
@@ -1977,39 +752,74 @@ bool Deserializer2::ReadObject(Object** write_back) {
location_of_branch_data += Assembler::kCallTargetSize;
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
- }
+ }
+ ONE_CASE_PER_SPACE(CODE_REFERENCE_SERIALIZATION) {
+ int backref_space = (data & kSpaceMask);
+ // Can't use Code::cast because heap is not set up yet and assertions
+ // will fail.
+ Code* code_object =
+ reinterpret_cast<Code*>(GetAddressFromStart(backref_space));
+ // Setting a branch/call to previously decoded code object from code.
+ Address location_of_branch_data = reinterpret_cast<Address>(current);
+ Assembler::set_target_at(location_of_branch_data,
+ code_object->instruction_start());
+ location_of_branch_data += Assembler::kCallTargetSize;
+ current = reinterpret_cast<Object**>(location_of_branch_data);
+ break;
+ }
case EXTERNAL_REFERENCE_SERIALIZATION: {
int reference_id = source_->GetInt();
Address address = external_reference_decoder_->Decode(reference_id);
*current++ = reinterpret_cast<Object*>(address);
break;
}
+ case EXTERNAL_BRANCH_TARGET_SERIALIZATION: {
+ int reference_id = source_->GetInt();
+ Address address = external_reference_decoder_->Decode(reference_id);
+ Address location_of_branch_data = reinterpret_cast<Address>(current);
+ Assembler::set_external_target_at(location_of_branch_data, address);
+ location_of_branch_data += Assembler::kExternalTargetSize;
+ current = reinterpret_cast<Object**>(location_of_branch_data);
+ break;
+ }
+ case START_NEW_PAGE_SERIALIZATION: {
+ int space = source_->Get();
+ pages_[space].Add(last_object_address_);
+ break;
+ }
+ case NATIVES_STRING_RESOURCE: {
+ int index = source_->Get();
+ Vector<const char> source_vector = Natives::GetScriptSource(index);
+ NativesExternalStringResource* resource =
+ new NativesExternalStringResource(source_vector.start());
+ *current++ = reinterpret_cast<Object*>(resource);
+ break;
+ }
default:
UNREACHABLE();
}
}
- ASSERT(current == limit);
- return space == NEW_SPACE;
+ ASSERT_EQ(current, limit);
}
void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
for (int shift = max_shift; shift > 0; shift -= 7) {
- if (integer >= 1u << shift) {
- Put(((integer >> shift) & 0x7f) | 0x80, "intpart");
+ if (integer >= static_cast<uintptr_t>(1u) << shift) {
+ Put(((integer >> shift) & 0x7f) | 0x80, "IntPart");
}
}
- Put(integer & 0x7f, "intlastpart");
+ PutSection(integer & 0x7f, "IntLastPart");
}
#ifdef DEBUG
-void Deserializer2::Synchronize(const char* tag) {
+void Deserializer::Synchronize(const char* tag) {
int data = source_->Get();
// If this assert fails then that indicates that you have a mismatch between
// the number of GC roots when serializing and deserializing.
- ASSERT(data == SYNCHRONIZE);
+ ASSERT_EQ(SYNCHRONIZE, data);
do {
int character = source_->Get();
if (character == 0) break;
@@ -2023,18 +833,18 @@ void Deserializer2::Synchronize(const char* tag) {
}
-void Serializer2::Synchronize(const char* tag) {
+void Serializer::Synchronize(const char* tag) {
sink_->Put(SYNCHRONIZE, tag);
int character;
do {
character = *tag++;
- sink_->Put(character, "tagcharacter");
+ sink_->PutSection(character, "TagCharacter");
} while (character != 0);
}
#endif
-Serializer2::Serializer2(SnapshotByteSink* sink)
+Serializer::Serializer(SnapshotByteSink* sink)
: sink_(sink),
current_root_index_(0),
external_reference_encoder_(NULL) {
@@ -2044,123 +854,183 @@ Serializer2::Serializer2(SnapshotByteSink* sink)
}
-void Serializer2::Serialize() {
+void Serializer::Serialize() {
// No active threads.
CHECK_EQ(NULL, ThreadState::FirstInUse());
// No active or weak handles.
CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
- ASSERT(external_reference_encoder_ == NULL);
+ CHECK_EQ(NULL, external_reference_encoder_);
+ // We don't support serializing installed extensions.
+ for (RegisteredExtension* ext = RegisteredExtension::first_extension();
+ ext != NULL;
+ ext = ext->next()) {
+ CHECK_NE(v8::INSTALLED, ext->state());
+ }
external_reference_encoder_ = new ExternalReferenceEncoder();
- Heap::IterateRoots(this);
+ Heap::IterateRoots(this, VISIT_ONLY_STRONG);
delete external_reference_encoder_;
external_reference_encoder_ = NULL;
}
-void Serializer2::VisitPointers(Object** start, Object** end) {
+void Serializer::VisitPointers(Object** start, Object** end) {
for (Object** current = start; current < end; current++) {
- SerializeObject(*current, TAGGED_REPRESENTATION);
+ if ((*current)->IsSmi()) {
+ sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
+ sink_->PutInt(kPointerSize, "length");
+ for (int i = 0; i < kPointerSize; i++) {
+ sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
+ }
+ } else {
+ SerializeObject(*current, TAGGED_REPRESENTATION);
+ }
}
}
-void Serializer2::SerializeObject(
+void Serializer::SerializeObject(
Object* o,
ReferenceRepresentation reference_representation) {
- if (o->IsHeapObject()) {
- HeapObject* heap_object = HeapObject::cast(o);
- MapWord map_word = heap_object->map_word();
- if (map_word.IsSerializationAddress()) {
- int space = SpaceOfAlreadySerializedObject(heap_object);
- int offset =
- CurrentAllocationAddress(space) - map_word.ToSerializationAddress();
- // If we are actually dealing with real offsets (and not a numbering of
- // all objects) then we should shift out the bits that are always 0.
- if (!SpaceIsLarge(space)) offset >>= kObjectAlignmentBits;
- if (reference_representation == CODE_TARGET_REPRESENTATION) {
- sink_->Put(CODE_BACKREF_SERIALIZATION, "BackRefCodeSerialization");
+ CHECK(o->IsHeapObject());
+ HeapObject* heap_object = HeapObject::cast(o);
+ MapWord map_word = heap_object->map_word();
+ if (map_word.IsSerializationAddress()) {
+ int space = SpaceOfAlreadySerializedObject(heap_object);
+ int address = map_word.ToSerializationAddress();
+ int offset = CurrentAllocationAddress(space) - address;
+ bool from_start = true;
+ if (SpaceIsPaged(space)) {
+ if ((CurrentAllocationAddress(space) >> Page::kPageSizeBits) ==
+ (address >> Page::kPageSizeBits)) {
+ from_start = false;
+ address = offset;
+ }
+ } else if (space == NEW_SPACE) {
+ if (offset < address) {
+ from_start = false;
+ address = offset;
+ }
+ }
+ // If we are actually dealing with real offsets (and not a numbering of
+ // all objects) then we should shift out the bits that are always 0.
+ if (!SpaceIsLarge(space)) address >>= kObjectAlignmentBits;
+ if (reference_representation == CODE_TARGET_REPRESENTATION) {
+ if (from_start) {
+ sink_->Put(CODE_REFERENCE_SERIALIZATION + space, "RefCodeSer");
+ sink_->PutInt(address, "address");
} else {
- ASSERT(reference_representation == TAGGED_REPRESENTATION);
- sink_->Put(BACKREF_SERIALIZATION, "BackRefSerialization");
+ sink_->Put(CODE_BACKREF_SERIALIZATION + space, "BackRefCodeSer");
+ sink_->PutInt(address, "address");
}
- sink_->Put(space, "space");
- sink_->PutInt(offset, "offset");
} else {
- // Object has not yet been serialized. Serialize it here.
- ObjectSerializer serializer(this,
- heap_object,
- sink_,
- reference_representation);
- serializer.Serialize();
+ CHECK_EQ(TAGGED_REPRESENTATION, reference_representation);
+ if (from_start) {
+#define COMMON_REFS_CASE(tag, common_space, common_offset) \
+ if (space == common_space && address == common_offset) { \
+ sink_->PutSection(tag + REFERENCE_SERIALIZATION, "RefSer"); \
+ } else /* NOLINT */
+ COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
+#undef COMMON_REFS_CASE
+ { /* NOLINT */
+ sink_->Put(REFERENCE_SERIALIZATION + space, "RefSer");
+ sink_->PutInt(address, "address");
+ }
+ } else {
+ sink_->Put(BACKREF_SERIALIZATION + space, "BackRefSer");
+ sink_->PutInt(address, "address");
+ }
}
} else {
- // Serialize a Smi.
- unsigned int value = Smi::cast(o)->value() + kSmiBias;
- sink_->Put(SMI_SERIALIZATION, "SmiSerialization");
- sink_->PutInt(value, "smi");
+ // Object has not yet been serialized. Serialize it here.
+ ObjectSerializer serializer(this,
+ heap_object,
+ sink_,
+ reference_representation);
+ serializer.Serialize();
}
}
-void Serializer2::ObjectSerializer::Serialize() {
- int space = Serializer2::SpaceOfObject(object_);
+
+void Serializer::ObjectSerializer::Serialize() {
+ int space = Serializer::SpaceOfObject(object_);
int size = object_->Size();
if (reference_representation_ == TAGGED_REPRESENTATION) {
- sink_->Put(OBJECT_SERIALIZATION, "ObjectSerialization");
+ sink_->Put(OBJECT_SERIALIZATION + space, "ObjectSerialization");
} else {
- ASSERT(reference_representation_ == CODE_TARGET_REPRESENTATION);
- sink_->Put(CODE_OBJECT_SERIALIZATION, "ObjectSerialization");
+ CHECK_EQ(CODE_TARGET_REPRESENTATION, reference_representation_);
+ sink_->Put(CODE_OBJECT_SERIALIZATION + space, "ObjectSerialization");
}
- sink_->Put(space, "space");
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
// Get the map before overwriting it.
Map* map = object_->map();
// Mark this object as already serialized.
- object_->set_map_word(
- MapWord::FromSerializationAddress(serializer_->Allocate(space, size)));
+ bool start_new_page;
+ object_->set_map_word(MapWord::FromSerializationAddress(
+ serializer_->Allocate(space, size, &start_new_page)));
+ if (start_new_page) {
+ sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
+ sink_->PutSection(space, "NewPageSpace");
+ }
// Serialize the map (first word of the object).
serializer_->SerializeObject(map, TAGGED_REPRESENTATION);
// Serialize the rest of the object.
- ASSERT(bytes_processed_so_far_ == 0);
+ CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
object_->IterateBody(map->instance_type(), size, this);
OutputRawData(object_->address() + size);
}
-void Serializer2::ObjectSerializer::VisitPointers(Object** start,
- Object** end) {
- Address pointers_start = reinterpret_cast<Address>(start);
- OutputRawData(pointers_start);
+void Serializer::ObjectSerializer::VisitPointers(Object** start,
+ Object** end) {
+ Object** current = start;
+ while (current < end) {
+ while (current < end && (*current)->IsSmi()) current++;
+ if (current < end) OutputRawData(reinterpret_cast<Address>(current));
- for (Object** current = start; current < end; current++) {
- serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
+ while (current < end && !(*current)->IsSmi()) {
+ serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
+ bytes_processed_so_far_ += kPointerSize;
+ current++;
+ }
}
- bytes_processed_so_far_ += (end - start) * kPointerSize;
}
-void Serializer2::ObjectSerializer::VisitExternalReferences(Address* start,
- Address* end) {
+void Serializer::ObjectSerializer::VisitExternalReferences(Address* start,
+ Address* end) {
Address references_start = reinterpret_cast<Address>(start);
OutputRawData(references_start);
for (Address* current = start; current < end; current++) {
- sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "External reference");
+ sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "ExternalReference");
int reference_id = serializer_->EncodeExternalReference(*current);
sink_->PutInt(reference_id, "reference id");
}
- bytes_processed_so_far_ += (end - start) * kPointerSize;
+ bytes_processed_so_far_ += static_cast<int>((end - start) * kPointerSize);
}
-void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
- ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) {
+ Address target_start = rinfo->target_address_address();
+ OutputRawData(target_start);
+ Address target = rinfo->target_address();
+ uint32_t encoding = serializer_->EncodeExternalReference(target);
+ CHECK(target == NULL ? encoding == 0 : encoding != 0);
+ sink_->Put(EXTERNAL_BRANCH_TARGET_SERIALIZATION, "ExternalReference");
+ sink_->PutInt(encoding, "reference id");
+ bytes_processed_so_far_ += Assembler::kExternalTargetSize;
+}
+
+
+void Serializer::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
+ CHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
Address target_start = rinfo->target_address_address();
OutputRawData(target_start);
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
@@ -2169,26 +1039,62 @@ void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
}
-void Serializer2::ObjectSerializer::OutputRawData(Address up_to) {
+void Serializer::ObjectSerializer::VisitExternalAsciiString(
+ v8::String::ExternalAsciiStringResource** resource_pointer) {
+ Address references_start = reinterpret_cast<Address>(resource_pointer);
+ OutputRawData(references_start);
+ for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
+ // Use raw_unchecked when maps are munged.
+ Object* source = Heap::raw_unchecked_natives_source_cache()->get(i);
+ if (!source->IsUndefined()) {
+ // Don't use cast when maps are munged.
+ ExternalAsciiString* string =
+ reinterpret_cast<ExternalAsciiString*>(source);
+ typedef v8::String::ExternalAsciiStringResource Resource;
+ Resource* resource = string->resource();
+ if (resource == *resource_pointer) {
+ sink_->Put(NATIVES_STRING_RESOURCE, "NativesStringResource");
+ sink_->PutSection(i, "NativesStringResourceEnd");
+ bytes_processed_so_far_ += sizeof(resource);
+ return;
+ }
+ }
+ }
+ // One of the strings in the natives cache should match the resource. We
+ // can't serialize any other kinds of external strings.
+ UNREACHABLE();
+}
+
+
+void Serializer::ObjectSerializer::OutputRawData(Address up_to) {
Address object_start = object_->address();
- int up_to_offset = up_to - object_start;
+ int up_to_offset = static_cast<int>(up_to - object_start);
int skipped = up_to_offset - bytes_processed_so_far_;
// This assert will fail if the reloc info gives us the target_address_address
// locations in a non-ascending order. Luckily that doesn't happen.
ASSERT(skipped >= 0);
if (skipped != 0) {
- sink_->Put(RAW_DATA_SERIALIZATION, "raw data");
- sink_->PutInt(skipped, "length");
+ Address base = object_start + bytes_processed_so_far_;
+#define RAW_CASE(index, length) \
+ if (skipped == length) { \
+ sink_->PutSection(RAW_DATA_SERIALIZATION + index, "RawDataFixed"); \
+ } else /* NOLINT */
+ COMMON_RAW_LENGTHS(RAW_CASE)
+#undef RAW_CASE
+ { /* NOLINT */
+ sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
+ sink_->PutInt(skipped, "length");
+ }
for (int i = 0; i < skipped; i++) {
- unsigned int data = object_start[bytes_processed_so_far_ + i];
- sink_->Put(data, "byte");
+ unsigned int data = base[i];
+ sink_->PutSection(data, "Byte");
}
+ bytes_processed_so_far_ += skipped;
}
- bytes_processed_so_far_ += skipped;
}
-int Serializer2::SpaceOfObject(HeapObject* object) {
+int Serializer::SpaceOfObject(HeapObject* object) {
for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
AllocationSpace s = static_cast<AllocationSpace>(i);
if (Heap::InSpace(object, s)) {
@@ -2209,7 +1115,7 @@ int Serializer2::SpaceOfObject(HeapObject* object) {
}
-int Serializer2::SpaceOfAlreadySerializedObject(HeapObject* object) {
+int Serializer::SpaceOfAlreadySerializedObject(HeapObject* object) {
for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
AllocationSpace s = static_cast<AllocationSpace>(i);
if (Heap::InSpace(object, s)) {
@@ -2221,13 +1127,18 @@ int Serializer2::SpaceOfAlreadySerializedObject(HeapObject* object) {
}
-int Serializer2::Allocate(int space, int size) {
- ASSERT(space >= 0 && space < kNumberOfSpaces);
+int Serializer::Allocate(int space, int size, bool* new_page) {
+ CHECK(space >= 0 && space < kNumberOfSpaces);
if (SpaceIsLarge(space)) {
// In large object space we merely number the objects instead of trying to
// determine some sort of address.
+ *new_page = true;
return fullness_[LO_SPACE]++;
}
+ *new_page = false;
+ if (fullness_[space] == 0) {
+ *new_page = true;
+ }
if (SpaceIsPaged(space)) {
// Paged spaces are a little special. We encode their addresses as if the
// pages were all contiguous and each page were filled up in the range
@@ -2235,10 +1146,11 @@ int Serializer2::Allocate(int space, int size) {
// and allocation does not start at offset 0 in the page, but this scheme
// means the deserializer can get the page number quickly by shifting the
// serialized address.
- ASSERT(IsPowerOf2(Page::kPageSize));
+ CHECK(IsPowerOf2(Page::kPageSize));
int used_in_this_page = (fullness_[space] & (Page::kPageSize - 1));
- ASSERT(size <= Page::kObjectAreaSize);
+ CHECK(size <= Page::kObjectAreaSize);
if (used_in_this_page + size > Page::kObjectAreaSize) {
+ *new_page = true;
fullness_[space] = RoundUp(fullness_[space], Page::kPageSize);
}
}