From 64941f1cf95fc8a13e125ed8159ab0166e89fa32 Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Mon, 16 Nov 2009 12:08:40 +0000 Subject: [PATCH] * Remove old snapshot implementation Review URL: http://codereview.chromium.org/394007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3307 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/api.cc | 6 +- src/assembler.h | 8 +- src/checks.cc | 2 + src/globals.h | 1 - src/mksnapshot.cc | 98 +-- src/serialize.cc | 1386 ++------------------------------- src/serialize.h | 301 +------ src/snapshot-common.cc | 46 +- src/snapshot.h | 3 - src/v8.cc | 3 +- src/v8.h | 4 +- test/cctest/cctest.status | 6 - test/cctest/test-serialize.cc | 105 +-- 13 files changed, 112 insertions(+), 1857 deletions(-) diff --git a/src/api.cc b/src/api.cc index 00b590f3eb..f631bfde32 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2636,11 +2636,7 @@ bool v8::V8::Initialize() { if (i::V8::IsRunning()) return true; ENTER_V8; HandleScope scope; - if (i::FLAG_new_snapshot) { - if (i::Snapshot::Initialize2()) return true; - } else { - if (i::Snapshot::Initialize()) return true; - } + if (i::Snapshot::Initialize()) return true; return i::V8::Initialize(NULL); } diff --git a/src/assembler.h b/src/assembler.h index 434e3bccde..aecd4cd63a 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -471,12 +471,16 @@ class ExternalReference BASE_EMBEDDED { static void* Redirect(void* address, bool fp_return = false) { if (redirector_ == NULL) return address; - return (*redirector_)(address, fp_return); + void* answer = (*redirector_)(address, fp_return); + return answer; } static void* Redirect(Address address_arg, bool fp_return = false) { void* address = reinterpret_cast(address_arg); - return redirector_ == NULL ? address : (*redirector_)(address, fp_return); + void* answer = (redirector_ == NULL) ? + address : + (*redirector_)(address, fp_return); + return answer; } void* address_; diff --git a/src/checks.cc b/src/checks.cc index f8a2f24f64..b5df316d0f 100644 --- a/src/checks.cc +++ b/src/checks.cc @@ -36,6 +36,8 @@ static int fatal_error_handler_nesting_depth = 0; // Contains protection against recursive calls (faults while handling faults). extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) { + fflush(stdout); + fflush(stderr); fatal_error_handler_nesting_depth++; // First time we try to print an error message if (fatal_error_handler_nesting_depth < 2) { diff --git a/src/globals.h b/src/globals.h index a1974fc4ec..ad0539f460 100644 --- a/src/globals.h +++ b/src/globals.h @@ -252,7 +252,6 @@ class Variable; class VariableProxy; class RelocInfo; class Deserializer; -class GenericDeserializer; // TODO(erikcorry): Get rid of this. class MessageLocation; class ObjectGroup; class TickSample; diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc index f9dbd5c9fa..eb743f81f8 100644 --- a/src/mksnapshot.cc +++ b/src/mksnapshot.cc @@ -87,27 +87,12 @@ class CounterCollection { // We statically allocate a set of local counters to be used if we // don't want to store the stats in a memory-mapped file static CounterCollection local_counters; -static CounterCollection* counters = &local_counters; typedef std::map CounterMap; typedef std::map::iterator CounterMapIterator; static CounterMap counter_table_; -// Callback receiver when v8 has a counter to track. -static int* counter_callback(const char* name) { - std::string counter = name; - // See if this counter name is already known. - if (counter_table_.find(counter) != counter_table_.end()) - return counter_table_[counter]; - - Counter* ctr = counters->GetNextCounter(); - if (ctr == NULL) return NULL; - int* ptr = ctr->Bind(name); - counter_table_[counter] = ptr; - return ptr; -} - class CppByteSink : public i::SnapshotByteSink { public: @@ -151,57 +136,6 @@ class CppByteSink : public i::SnapshotByteSink { }; -// Write C++ code that defines Snapshot::snapshot_ to contain the snapshot -// to the file given by filename. Only the first size chars are written. -static int WriteInternalSnapshotToFile(const char* filename, - const v8::internal::byte* bytes, - int size) { - FILE* f = i::OS::FOpen(filename, "wb"); - if (f == NULL) { - i::OS::PrintError("Cannot open file %s for writing.\n", filename); - return 0; - } - fprintf(f, "// Autogenerated snapshot file. Do not edit.\n\n"); - fprintf(f, "#include \"v8.h\"\n"); - fprintf(f, "#include \"platform.h\"\n\n"); - fprintf(f, "#include \"snapshot.h\"\n\n"); - fprintf(f, "namespace v8 {\nnamespace internal {\n\n"); - fprintf(f, "const byte Snapshot::data_[] = {"); - int written = 0; - written += fprintf(f, "0x%x", bytes[0]); - for (int i = 1; i < size; ++i) { - written += fprintf(f, ",0x%x", bytes[i]); - // The following is needed to keep the line length low on Visual C++: - if (i % 512 == 0) fprintf(f, "\n"); - } - fprintf(f, "};\n\n"); - fprintf(f, "int Snapshot::size_ = %d;\n\n", size); - fprintf(f, "} } // namespace v8::internal\n"); - fclose(f); - return written; -} - - -int main2(int argc, char** argv) { - i::Serializer::Enable(); - Persistent context = v8::Context::New(); - // Make sure all builtin scripts are cached. - { HandleScope scope; - for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) { - i::Bootstrapper::NativesSourceLookup(i); - } - } - context.Dispose(); - CppByteSink sink(argv[1]); - i::Serializer2 ser(&sink); - // This results in a somewhat smaller snapshot, probably because it gets rid - // of some things that are cached between garbage collections. - i::Heap::CollectAllGarbage(true); - ser.Serialize(); - return 0; -} - - int main(int argc, char** argv) { #ifdef ENABLE_LOGGING_AND_PROFILING // By default, log code create information in the snapshot. @@ -215,38 +149,20 @@ int main(int argc, char** argv) { i::FlagList::PrintHelp(); return !i::FLAG_help; } - - if (i::FLAG_new_snapshot) { - return main2(argc, argv); - } - - v8::V8::SetCounterFunction(counter_callback); - v8::HandleScope scope; - - const int kExtensionCount = 1; - const char* extension_list[kExtensionCount] = { "v8/gc" }; - v8::ExtensionConfiguration extensions(kExtensionCount, extension_list); - i::Serializer::Enable(); - v8::Context::New(&extensions); - + Persistent context = v8::Context::New(); // Make sure all builtin scripts are cached. { HandleScope scope; for (int i = 0; i < i::Natives::GetBuiltinsCount(); i++) { i::Bootstrapper::NativesSourceLookup(i); } } - // Get rid of unreferenced scripts with a global GC. - i::Heap::CollectAllGarbage(false); - i::Serializer ser; + context.Dispose(); + CppByteSink sink(argv[1]); + i::Serializer ser(&sink); + // This results in a somewhat smaller snapshot, probably because it gets rid + // of some things that are cached between garbage collections. + i::Heap::CollectAllGarbage(true); ser.Serialize(); - v8::internal::byte* bytes; - int len; - ser.Finalize(&bytes, &len); - - WriteInternalSnapshotToFile(argv[1], bytes, len); - - i::DeleteArray(bytes); - return 0; } diff --git a/src/serialize.cc b/src/serialize.cc index 858f4c0d50..de87022e00 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -44,350 +44,6 @@ 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(addr); - int space_number = (static_cast(encoded >> kSpaceShift) & kSpaceMask); - if (space_number > LAST_SPACE) space_number = LO_SPACE; - return static_cast(space_number); -} - - -static inline bool IsLargeExecutableObject(Address addr) { - const intptr_t encoded = reinterpret_cast(addr); - const int space_number = - (static_cast(encoded >> kSpaceShift) & kSpaceMask); - return (space_number == kLargeCode); -} - - -static inline bool IsLargeFixedArray(Address addr) { - const intptr_t encoded = reinterpret_cast(addr); - const int space_number = - (static_cast(encoded >> kSpaceShift) & kSpaceMask); - return (space_number == kLargeFixedArray); -} - - -static inline int PageIndex(Address addr) { - const intptr_t encoded = reinterpret_cast(addr); - return static_cast(encoded >> kPageShift) & kPageMask; -} - - -static inline int PageOffset(Address addr) { - const intptr_t encoded = reinterpret_cast(addr); - const int offset = static_cast(encoded >> kOffsetShift) & kOffsetMask; - return offset << kObjectAlignmentBits; -} - - -static inline int NewSpaceOffset(Address addr) { - const intptr_t encoded = reinterpret_cast(addr); - const int page_offset = - static_cast(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask; - return page_offset << kObjectAlignmentBits; -} - - -static inline int LargeObjectIndex(Address addr) { - const intptr_t encoded = reinterpret_cast(addr); - return static_cast(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(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
(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, - static_cast(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. @@ -491,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; } @@ -829,953 +485,11 @@ 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(max_); - } - - ~SnapshotWriter() { - DeleteArray(str_); - } - - void GetBytes(byte** str, int* len) { - *str = NewArray(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(&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(&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
(&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(max_); - memcpy(str_, old, len_); - DeleteArray(old); - } - if (pos < len_) { - byte* old = str_; - str_ = NewArray(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 = StrLength(s); - pos = InsertC('[', pos); - pos = InsertInt(size, pos); - pos = InsertC(']', pos); - return InsertBytes(reinterpret_cast(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( - static_cast(reinterpret_cast
(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( - static_cast(rinfo->target_address_address() - obj_address_)); - uint32_t small_target = - static_cast(reinterpret_cast(encoded_target)); - ASSERT(reinterpret_cast(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( - static_cast(reinterpret_cast
(p) - obj_address_)); - addresses_.Add(reinterpret_cast
(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( - static_cast(rinfo->target_address_address() - obj_address_)); - addresses_.Add(reinterpret_cast
(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 offsets_; - List
addresses_; - // Some updates are 32-bit even on a 64-bit platform. - // We keep a separate list of them on 64-bit platforms. - List offsets_32_bit_; - List data_32_bit_; -}; - - -// Helper functions for a map of encoded heap object addresses. -static uint32_t HeapObjectHash(HeapObject* key) { - uint32_t low32bits = static_cast(reinterpret_cast(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 = StrLength(tag); - ASSERT(length <= kMaxTagLength); - writer_->PutC('S'); - writer_->PutInt(length); - writer_->PutBytes(reinterpret_cast(tag), length); - } -} -#endif - - -void Serializer::InitializeAllocators() { - for (int i = 0; i <= LAST_SPACE; i++) { - allocator_[i]->InitEmptyHeap(static_cast(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
(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, VISIT_ONLY_STRONG); - 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* handles) - : global_handles_(handles) {} - - virtual void VisitPointers(Object** start, Object** end) { - for (; start != end; ++start) { - global_handles_->Add(start); - } - } - - private: - List* global_handles_; -}; - - -void Serializer::PutFlags() { - writer_->PutC('F'); - List* 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::IterateStrongRoots(&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 log = ReadFile(FLAG_logfile, &exists); - writer_->InsertString(log.start(), pos); - log.Dispose(); - } -#endif -} - - -static int IndexOf(const List& list, Object** element) { - for (int i = 0; i < list.length(); i++) { - if (list[i] == element) return i; - } - return -1; -} - - -void Serializer::PutGlobalHandleStack(const List >& 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 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(&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
(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(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(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
(buf), length); - ASSERT_EQ(StrLength(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::IterateStrongRoots(&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, VISIT_ONLY_STRONG); - 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::IterateStrongRoots(&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
(*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
(Memory::uint32_at( - reinterpret_cast
(rinfo->target_object_address()))); - Code* target_object = reinterpret_cast(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(reinterpret_cast(*p)); - *p = reference_decoder_->Decode(code); - } -} - - -void Deserializer::VisitRuntimeEntry(RelocInfo* rinfo) { - uint32_t* pc = reinterpret_cast(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(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_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 >* 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 entered_contexts(count); - if (count > 0) { - Object** start = reinterpret_cast(&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(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(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(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_list) { - ASSERT(page_index < page_list->length()); - Address address = (*page_list)[page_index]->OffsetToAddress(page_offset); - return HeapObject::FromAddress(address); -} - - -template -void ConcatReversed(List* target, const List& source) { - for (int i = source.length() - 1; i >= 0; i--) { - target->Add(source[i]); - } -} - - -Object* Deserializer::Resolve(Address encoded) { - Object* o = reinterpret_cast(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 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) { } @@ -1784,7 +498,7 @@ Deserializer2::Deserializer2(SnapshotByteSource* source) // 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, Space* space, int size) { +Address Deserializer::Allocate(int space_index, Space* space, int size) { Address address; if (!SpaceIsLarge(space_index)) { ASSERT(!SpaceIsPaged(space_index) || @@ -1809,7 +523,7 @@ Address Deserializer2::Allocate(int space_index, Space* space, int 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()); @@ -1825,7 +539,7 @@ Address Deserializer2::Allocate(int space_index, Space* space, int size) { // 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::GetAddressFromEnd(int space) { +HeapObject* Deserializer::GetAddressFromEnd(int space) { int offset = source_->GetInt(); ASSERT(!SpaceIsLarge(space)); offset <<= kObjectAlignmentBits; @@ -1835,7 +549,7 @@ HeapObject* Deserializer2::GetAddressFromEnd(int space) { // This returns the address of an object that has been described in the // snapshot as being offset bytes into a particular space. -HeapObject* Deserializer2::GetAddressFromStart(int space) { +HeapObject* Deserializer::GetAddressFromStart(int space) { int offset = source_->GetInt(); if (SpaceIsLarge(space)) { // Large spaces have one object per 'page'. @@ -1854,7 +568,7 @@ HeapObject* Deserializer2::GetAddressFromStart(int space) { } -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. @@ -1863,7 +577,7 @@ 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, VISIT_ONLY_STRONG); ASSERT(source_->AtEOF()); @@ -1874,7 +588,7 @@ void Deserializer2::Deserialize() { // This is called on the roots. It is the driver of the deserialization // process. It is also called on the body of each function. -void Deserializer2::VisitPointers(Object** start, Object** end) { +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); @@ -1887,9 +601,9 @@ 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). -void Deserializer2::ReadObject(int space_number, - Space* space, - Object** write_back) { +void Deserializer::ReadObject(int space_number, + Space* space, + Object** write_back) { int size = source_->GetInt() << kObjectAlignmentBits; Address address = Allocate(space_number, space, size); *write_back = HeapObject::FromAddress(address); @@ -1911,10 +625,10 @@ void Deserializer2::ReadObject(int space_number, case (base_tag) + kLargeFixedArray: /* NOLINT */ -void Deserializer2::ReadChunk(Object** current, - Object** limit, - int space, - Address address) { +void Deserializer::ReadChunk(Object** current, + Object** limit, + int space, + Address address) { while (current < limit) { int data = source_->Get(); switch (data) { @@ -2085,7 +799,7 @@ void Deserializer2::ReadChunk(Object** current, UNREACHABLE(); } } - ASSERT(current == limit); + ASSERT_EQ(current, limit); } @@ -2101,11 +815,11 @@ void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) { #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; @@ -2119,7 +833,7 @@ 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 { @@ -2130,7 +844,7 @@ void Serializer2::Synchronize(const char* tag) { #endif -Serializer2::Serializer2(SnapshotByteSink* sink) +Serializer::Serializer(SnapshotByteSink* sink) : sink_(sink), current_root_index_(0), external_reference_encoder_(NULL) { @@ -2140,13 +854,19 @@ 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, VISIT_ONLY_STRONG); delete external_reference_encoder_; @@ -2154,7 +874,7 @@ void Serializer2::Serialize() { } -void Serializer2::VisitPointers(Object** start, Object** end) { +void Serializer::VisitPointers(Object** start, Object** end) { for (Object** current = start; current < end; current++) { if ((*current)->IsSmi()) { sink_->Put(RAW_DATA_SERIALIZATION, "RawData"); @@ -2169,10 +889,10 @@ void Serializer2::VisitPointers(Object** start, Object** end) { } -void Serializer2::SerializeObject( +void Serializer::SerializeObject( Object* o, ReferenceRepresentation reference_representation) { - ASSERT(o->IsHeapObject()); + CHECK(o->IsHeapObject()); HeapObject* heap_object = HeapObject::cast(o); MapWord map_word = heap_object->map_word(); if (map_word.IsSerializationAddress()) { @@ -2204,7 +924,7 @@ void Serializer2::SerializeObject( sink_->PutInt(address, "address"); } } else { - ASSERT(reference_representation == TAGGED_REPRESENTATION); + 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) { \ @@ -2233,14 +953,14 @@ void Serializer2::SerializeObject( -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 + space, "ObjectSerialization"); } else { - ASSERT(reference_representation_ == CODE_TARGET_REPRESENTATION); + CHECK_EQ(CODE_TARGET_REPRESENTATION, reference_representation_); sink_->Put(CODE_OBJECT_SERIALIZATION + space, "ObjectSerialization"); } sink_->PutInt(size >> kObjectAlignmentBits, "Size in words"); @@ -2260,15 +980,15 @@ void Serializer2::ObjectSerializer::Serialize() { 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) { +void Serializer::ObjectSerializer::VisitPointers(Object** start, + Object** end) { Object** current = start; while (current < end) { while (current < end && (*current)->IsSmi()) current++; @@ -2283,8 +1003,8 @@ void Serializer2::ObjectSerializer::VisitPointers(Object** start, } -void Serializer2::ObjectSerializer::VisitExternalReferences(Address* start, - Address* end) { +void Serializer::ObjectSerializer::VisitExternalReferences(Address* start, + Address* end) { Address references_start = reinterpret_cast
(start); OutputRawData(references_start); @@ -2297,7 +1017,7 @@ void Serializer2::ObjectSerializer::VisitExternalReferences(Address* start, } -void Serializer2::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { +void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { Address target_start = rinfo->target_address_address(); OutputRawData(target_start); Address target = rinfo->target_address(); @@ -2309,8 +1029,8 @@ void Serializer2::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { } -void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) { - ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); +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()); @@ -2319,7 +1039,7 @@ void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) { } -void Serializer2::ObjectSerializer::VisitExternalAsciiString( +void Serializer::ObjectSerializer::VisitExternalAsciiString( v8::String::ExternalAsciiStringResource** resource_pointer) { Address references_start = reinterpret_cast
(resource_pointer); OutputRawData(references_start); @@ -2346,7 +1066,7 @@ void Serializer2::ObjectSerializer::VisitExternalAsciiString( } -void Serializer2::ObjectSerializer::OutputRawData(Address up_to) { +void Serializer::ObjectSerializer::OutputRawData(Address up_to) { Address object_start = object_->address(); int up_to_offset = static_cast(up_to - object_start); int skipped = up_to_offset - bytes_processed_so_far_; @@ -2374,7 +1094,7 @@ void Serializer2::ObjectSerializer::OutputRawData(Address up_to) { } -int Serializer2::SpaceOfObject(HeapObject* object) { +int Serializer::SpaceOfObject(HeapObject* object) { for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) { AllocationSpace s = static_cast(i); if (Heap::InSpace(object, s)) { @@ -2395,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(i); if (Heap::InSpace(object, s)) { @@ -2407,8 +1127,8 @@ int Serializer2::SpaceOfAlreadySerializedObject(HeapObject* object) { } -int Serializer2::Allocate(int space, int size, bool* new_page) { - 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. @@ -2426,9 +1146,9 @@ int Serializer2::Allocate(int space, int size, bool* new_page) { // 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); diff --git a/src/serialize.h b/src/serialize.h index 1205561f03..96bd751da9 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2006-2009 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -108,260 +108,6 @@ class ExternalReferenceDecoder { }; -// A Serializer recursively visits objects to construct a serialized -// representation of the Heap stored in a string. Serialization is -// destructive. We use a similar mechanism to the GC to ensure that -// each object is visited once, namely, we modify the map pointer of -// each visited object to contain the relative address in the -// appropriate space where that object will be allocated when the heap -// is deserialized. - - -// Helper classes defined in serialize.cc. -class RelativeAddress; -class SimulatedHeapSpace; -class SnapshotWriter; -class ReferenceUpdater; - - -class Serializer: public ObjectVisitor { - public: - Serializer(); - - virtual ~Serializer(); - - // Serialize the current state of the heap. This operation destroys the - // heap contents and the contents of the roots into the heap. - void Serialize(); - - // Returns the serialized buffer. Ownership is transferred to the - // caller. Only the destructor and getters may be called after this call. - void Finalize(byte** str, int* len); - - int roots() { return roots_; } - int objects() { return objects_; } - -#ifdef DEBUG - // insert "tag" into the serialized stream - virtual void Synchronize(const char* tag); -#endif - - static bool enabled() { return serialization_enabled_; } - - static void Enable() { - if (!serialization_enabled_) { - ASSERT(!too_late_to_enable_now_); - } - serialization_enabled_ = true; - } - - static void Disable() { serialization_enabled_ = false; } - // Call this when you have made use of the fact that there is no serialization - // going on. - static void TooLateToEnableNow() { too_late_to_enable_now_ = true; } - - private: - friend class ReferenceUpdater; - - virtual void VisitPointers(Object** start, Object** end); - virtual void VisitCodeTarget(RelocInfo* rinfo); - bool IsVisited(HeapObject* obj); - - Address GetSavedAddress(HeapObject* obj); - - void SaveAddress(HeapObject* obj, Address addr); - - void PutEncodedAddress(Address addr); - // Write the global flags into the file. - void PutFlags(); - // Write global information into the header of the file. - void PutHeader(); - // Write the contents of the log into the file. - void PutLog(); - // Serialize 'obj', and return its encoded RelativeAddress. - Address PutObject(HeapObject* obj); - // Write a stack of handles to the file bottom first. - void PutGlobalHandleStack(const List >& stack); - // Write the context stack into the file. - void PutContextStack(); - - // Return the encoded RelativeAddress where this object will be - // allocated on deserialization. On the first visit of 'o', - // serialize its contents. On return, *serialized will be true iff - // 'o' has just been serialized. - Address Encode(Object* o, bool* serialized); - - // Simulate the allocation of 'obj', returning the address where it will - // be allocated on deserialization - RelativeAddress Allocate(HeapObject* obj); - - void InitializeAllocators(); - - SnapshotWriter* writer_; - bool root_; // serializing a root? - int roots_; // number of roots visited - int objects_; // number of objects serialized - - static bool serialization_enabled_; - // Did we already make use of the fact that serialization was not enabled? - static bool too_late_to_enable_now_; - - int flags_end_; // The position right after the flags. - - // An array of per-space SimulatedHeapSpaces used as memory allocators. - SimulatedHeapSpace* allocator_[LAST_SPACE+1]; - // A list of global handles at serialization time. - List global_handles_; - - ExternalReferenceEncoder* reference_encoder_; - - HashMap saved_addresses_; - - DISALLOW_COPY_AND_ASSIGN(Serializer); -}; - -// Helper class to read the bytes of the serialized heap. - -class SnapshotReader { - public: - SnapshotReader(const byte* str, int len): str_(str), end_(str + len) {} - - void ExpectC(char expected) { - int c = GetC(); - USE(c); - ASSERT(c == expected); - } - - int GetC() { - if (str_ >= end_) return EOF; - return *str_++; - } - - int GetInt() { - int result; - GetBytes(reinterpret_cast
(&result), sizeof(result)); - return result; - } - - Address GetAddress() { - Address result; - GetBytes(reinterpret_cast
(&result), sizeof(result)); - return result; - } - - void GetBytes(Address a, int size) { - ASSERT(str_ + size <= end_); - memcpy(a, str_, size); - str_ += size; - } - - char* GetString() { - ExpectC('['); - int size = GetInt(); - ExpectC(']'); - char* s = NewArray(size + 1); - GetBytes(reinterpret_cast
(s), size); - s[size] = 0; - return s; - } - - private: - const byte* str_; - const byte* end_; -}; - - -// A Deserializer reads a snapshot and reconstructs the Object graph it defines. - - -// TODO(erikcorry): Get rid of this superclass when we are using the new -// snapshot code exclusively. -class GenericDeserializer: public ObjectVisitor { - public: - virtual void GetLog() = 0; - virtual void Deserialize() = 0; -}; - - -// TODO(erikcorry): Get rid of this class. -class Deserializer: public GenericDeserializer { - public: - // Create a deserializer. The snapshot is held in str and has size len. - Deserializer(const byte* str, int len); - - virtual ~Deserializer(); - - // Read the flags from the header of the file, and set those that - // should be inherited from the snapshot. - void GetFlags(); - - // Read saved profiling information from the file and log it if required. - void GetLog(); - - // Deserialize the snapshot into an empty heap. - void Deserialize(); - - int roots() { return roots_; } - int objects() { return objects_; } - -#ifdef DEBUG - // Check for the presence of "tag" in the serialized stream - virtual void Synchronize(const char* tag); -#endif - - private: - virtual void VisitPointers(Object** start, Object** end); - virtual void VisitCodeTarget(RelocInfo* rinfo); - virtual void VisitExternalReferences(Address* start, Address* end); - virtual void VisitRuntimeEntry(RelocInfo* rinfo); - - Address GetEncodedAddress(); - - // Read other global information (except flags) from the header of the file. - void GetHeader(); - // Read a stack of handles from the file bottom first. - void GetGlobalHandleStack(List >* stack); - // Read the context stack from the file. - void GetContextStack(); - - Object* GetObject(); - - // Get the encoded address. In debug mode we make sure - // it matches the given expectations. - void ExpectEncodedAddress(Address expected); - - // Given an encoded address (the result of - // RelativeAddress::Encode), return the object to which it points, - // which will be either an Smi or a HeapObject in the current heap. - Object* Resolve(Address encoded_address); - - SnapshotReader reader_; - bool root_; // Deserializing a root? - int roots_; // number of roots visited - int objects_; // number of objects serialized - - bool has_log_; // The file has log information. - - // Resolve caches the following: - List map_pages_; // All pages in the map space. - List cell_pages_; // All pages in the cell space. - List old_pointer_pages_; // All pages in the old pointer space. - List old_data_pages_; // All pages in the old data space. - List code_pages_; // All pages in the code space. - List large_objects_; // All known large objects. - // A list of global handles at deserialization time. - List global_handles_; - - ExternalReferenceDecoder* reference_decoder_; - -#ifdef DEBUG - bool expect_debug_information_; -#endif - - DISALLOW_COPY_AND_ASSIGN(Deserializer); -}; - - class SnapshotByteSource { public: SnapshotByteSource(const byte* array, int length) @@ -407,6 +153,7 @@ class SnapshotByteSource { int position_; }; + // It is very common to have a reference to the object at word 10 in space 2, // the object at word 5 in space 2 and the object at word 28 in space 4. This // only works for objects in the first page of a space. @@ -436,10 +183,9 @@ class SnapshotByteSource { f(14, 32) \ f(15, 36) -// The SerDes class is a common superclass for Serializer2 and Deserializer2 +// The SerDes class is a common superclass for Serializer and Deserializer // which is used to store common constants and methods used by both. -// TODO(erikcorry): This should inherit from ObjectVisitor. -class SerDes: public GenericDeserializer { +class SerDes: public ObjectVisitor { protected: enum DataType { RAW_DATA_SERIALIZATION = 0, @@ -483,16 +229,15 @@ class SerDes: public GenericDeserializer { // A Deserializer reads a snapshot and reconstructs the Object graph it defines. -class Deserializer2: public SerDes { +class Deserializer: public SerDes { public: // Create a deserializer from a snapshot byte source. - explicit Deserializer2(SnapshotByteSource* source); + explicit Deserializer(SnapshotByteSource* source); - virtual ~Deserializer2() { } + virtual ~Deserializer() { } // Deserialize the snapshot into an empty heap. void Deserialize(); - void GetLog() { } // TODO(erikcorry): Get rid of this. #ifdef DEBUG virtual void Synchronize(const char* tag); #endif @@ -530,7 +275,7 @@ class Deserializer2: public SerDes { // START_NEW_PAGE_SERIALIZATION tag. Address last_object_address_; - DISALLOW_COPY_AND_ASSIGN(Deserializer2); + DISALLOW_COPY_AND_ASSIGN(Deserializer); }; @@ -545,15 +290,26 @@ class SnapshotByteSink { }; -class Serializer2 : public SerDes { +class Serializer : public SerDes { public: - explicit Serializer2(SnapshotByteSink* sink); + explicit Serializer(SnapshotByteSink* sink); // Serialize the current state of the heap. This operation destroys the // heap contents. void Serialize(); void VisitPointers(Object** start, Object** end); - void GetLog() { } // TODO(erikcorry): Get rid of this. - void Deserialize() { } // TODO(erikcorry): Get rid of this. + + static void Enable() { + if (!serialization_enabled_) { + ASSERT(!too_late_to_enable_now_); + } + serialization_enabled_ = true; + } + + static void Disable() { serialization_enabled_ = false; } + // Call this when you have made use of the fact that there is no serialization + // going on. + static void TooLateToEnableNow() { too_late_to_enable_now_ = true; } + static bool enabled() { return serialization_enabled_; } #ifdef DEBUG virtual void Synchronize(const char* tag); #endif @@ -565,7 +321,7 @@ class Serializer2 : public SerDes { }; class ObjectSerializer : public ObjectVisitor { public: - ObjectSerializer(Serializer2* serializer, + ObjectSerializer(Serializer* serializer, Object* o, SnapshotByteSink* sink, ReferenceRepresentation representation) @@ -591,7 +347,7 @@ class Serializer2 : public SerDes { private: void OutputRawData(Address up_to); - Serializer2* serializer_; + Serializer* serializer_; HeapObject* object_; SnapshotByteSink* sink_; ReferenceRepresentation reference_representation_; @@ -626,11 +382,14 @@ class Serializer2 : public SerDes { SnapshotByteSink* sink_; int current_root_index_; ExternalReferenceEncoder* external_reference_encoder_; + static bool serialization_enabled_; + // Did we already make use of the fact that serialization was not enabled? + static bool too_late_to_enable_now_; friend class ObjectSerializer; - friend class Deserializer2; + friend class Deserializer; - DISALLOW_COPY_AND_ASSIGN(Serializer2); + DISALLOW_COPY_AND_ASSIGN(Serializer); }; } } // namespace v8::internal diff --git a/src/snapshot-common.cc b/src/snapshot-common.cc index 875cc9667d..c01baad79a 100644 --- a/src/snapshot-common.cc +++ b/src/snapshot-common.cc @@ -38,15 +38,8 @@ namespace v8 { namespace internal { bool Snapshot::Deserialize(const byte* content, int len) { - Deserializer des(content, len); - des.GetFlags(); - return V8::Initialize(&des); -} - - -bool Snapshot::Deserialize2(const byte* content, int len) { SnapshotByteSource source(content, len); - Deserializer2 deserializer(&source); + Deserializer deserializer(&source); return V8::Initialize(&deserializer); } @@ -56,46 +49,17 @@ bool Snapshot::Initialize(const char* snapshot_file) { int len; byte* str = ReadBytes(snapshot_file, &len); if (!str) return false; - bool result = Deserialize(str, len); - DeleteArray(str); - return result; - } else if (size_ > 0) { - return Deserialize(data_, size_); - } - return false; -} - - -bool Snapshot::Initialize2(const char* snapshot_file) { - if (snapshot_file) { - int len; - byte* str = ReadBytes(snapshot_file, &len); - if (!str) return false; - Deserialize2(str, len); + Deserialize(str, len); DeleteArray(str); return true; } else if (size_ > 0) { - Deserialize2(data_, size_); + Deserialize(data_, size_); return true; } return false; } -bool Snapshot::WriteToFile(const char* snapshot_file) { - Serializer ser; - ser.Serialize(); - byte* str; - int len; - ser.Finalize(&str, &len); - - int written = WriteBytes(snapshot_file, str, len); - - DeleteArray(str); - return written == len; -} - - class FileByteSink : public SnapshotByteSink { public: explicit FileByteSink(const char* snapshot_file) { @@ -121,9 +85,9 @@ class FileByteSink : public SnapshotByteSink { }; -bool Snapshot::WriteToFile2(const char* snapshot_file) { +bool Snapshot::WriteToFile(const char* snapshot_file) { FileByteSink file(snapshot_file); - Serializer2 ser(&file); + Serializer ser(&file); ser.Serialize(); return true; } diff --git a/src/snapshot.h b/src/snapshot.h index a3a3867d05..88ba8db30e 100644 --- a/src/snapshot.h +++ b/src/snapshot.h @@ -37,7 +37,6 @@ class Snapshot { // NULL, use the internal snapshot instead. Returns false if no snapshot // could be found. static bool Initialize(const char* snapshot_file = NULL); - static bool Initialize2(const char* snapshot_file = NULL); // Returns whether or not the snapshot is enabled. static bool IsEnabled() { return size_ != 0; } @@ -45,14 +44,12 @@ class Snapshot { // Write snapshot to the given file. Returns true if snapshot was written // successfully. static bool WriteToFile(const char* snapshot_file); - static bool WriteToFile2(const char* snapshot_file); private: static const byte data_[]; static int size_; static bool Deserialize(const byte* content, int len); - static bool Deserialize2(const byte* content, int len); DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot); }; diff --git a/src/v8.cc b/src/v8.cc index 93a116def6..d172742531 100644 --- a/src/v8.cc +++ b/src/v8.cc @@ -43,7 +43,7 @@ bool V8::has_been_setup_ = false; bool V8::has_been_disposed_ = false; bool V8::has_fatal_error_ = false; -bool V8::Initialize(GenericDeserializer *des) { +bool V8::Initialize(Deserializer *des) { bool create_heap_objects = des == NULL; if (has_been_disposed_ || has_fatal_error_) return false; if (IsRunning()) return true; @@ -59,7 +59,6 @@ bool V8::Initialize(GenericDeserializer *des) { // Enable logging before setting up the heap Logger::Setup(); - if (des) des->GetLog(); // Setup the platform OS support. OS::Setup(); diff --git a/src/v8.h b/src/v8.h index 6c5546c631..b3624c5d54 100644 --- a/src/v8.h +++ b/src/v8.h @@ -72,6 +72,8 @@ namespace v8 { namespace internal { +class Deserializer; + class V8 : public AllStatic { public: // Global actions. @@ -80,7 +82,7 @@ class V8 : public AllStatic { // created from scratch. If a non-null Deserializer is given, the // initial state is created by reading the deserialized data into an // empty heap. - static bool Initialize(GenericDeserializer* des); + static bool Initialize(Deserializer* des); static void TearDown(); static bool IsRunning() { return is_running_; } // To be dead you have to have lived diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 35361b4049..a143cbdab2 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -33,12 +33,6 @@ test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux # BUG(382): Weird test. Can't guarantee that it never times out. test-api/ApplyInterruption: PASS || TIMEOUT -# This is about to go away anyway since new snapshot code is on the way. -test-serialize/Deserialize: FAIL -test-serialize/DeserializeAndRunScript: FAIL || CRASH -test-serialize/DeserializeNatives: FAIL || CRASH -test-serialize/DeserializeExtensions: FAIL || CRASH - # These tests always fail. They are here to test test.py. If # they don't fail then test.py has failed. test-serialize/TestThatAlwaysFails: FAIL diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc index ee8ef51d4f..9ed487450d 100644 --- a/test/cctest/test-serialize.cc +++ b/test/cctest/test-serialize.cc @@ -174,83 +174,32 @@ TEST(ExternalReferenceDecoder) { static void Serialize() { -#ifdef DEBUG - FLAG_debug_serialization = true; -#endif - StatsTable::SetCounterFunction(counter_function); - - v8::HandleScope scope; - const int kExtensionCount = 1; - const char* extension_list[kExtensionCount] = { "v8/gc" }; - v8::ExtensionConfiguration extensions(kExtensionCount, extension_list); - Serializer::Enable(); - v8::Persistent env = v8::Context::New(&extensions); - env->Enter(); - - Snapshot::WriteToFile(FLAG_testing_serialization_file); -} - - -static void Serialize2() { // We have to create one context. One reason for this is so that the builtins // can be loaded from v8natives.js and their addresses can be processed. This // will clear the pending fixups array, which would otherwise contain GC roots // that would confuse the serialization/deserialization process. v8::Persistent env = v8::Context::New(); env.Dispose(); - Snapshot::WriteToFile2(FLAG_testing_serialization_file); -} - - -// Test that the whole heap can be serialized when running from a -// bootstrapped heap. -// (Smoke test.) -TEST(Serialize) { - if (Snapshot::IsEnabled()) return; - Serialize(); + Snapshot::WriteToFile(FLAG_testing_serialization_file); } // Test that the whole heap can be serialized. -TEST(Serialize2) { +TEST(Serialize) { Serializer::Enable(); v8::V8::Initialize(); - Serialize2(); + Serialize(); } -// Test that the heap isn't destroyed after a serialization. -TEST(SerializeNondestructive) { - if (Snapshot::IsEnabled()) return; - StatsTable::SetCounterFunction(counter_function); - v8::HandleScope scope; - Serializer::Enable(); - v8::Persistent env = v8::Context::New(); - v8::Context::Scope context_scope(env); - Serializer().Serialize(); - const char* c_source = "\"abcd\".charAt(2) == 'c'"; - v8::Local source = v8::String::New(c_source); - v8::Local script = v8::Script::Compile(source); - v8::Local value = script->Run(); - CHECK(value->BooleanValue()); -} - //---------------------------------------------------------------------------- // Tests that the heap can be deserialized. static void Deserialize() { -#ifdef DEBUG - FLAG_debug_serialization = true; -#endif CHECK(Snapshot::Initialize(FLAG_testing_serialization_file)); } -static void Deserialize2() { - CHECK(Snapshot::Initialize2(FLAG_testing_serialization_file)); -} - - static void SanityCheck() { v8::HandleScope scope; #ifdef DEBUG @@ -269,15 +218,6 @@ DEPENDENT_TEST(Deserialize, Serialize) { Deserialize(); - SanityCheck(); -} - - -DEPENDENT_TEST(Deserialize2, Serialize2) { - v8::HandleScope scope; - - Deserialize2(); - fflush(stdout); v8::Persistent env = v8::Context::New(); @@ -287,23 +227,11 @@ DEPENDENT_TEST(Deserialize2, Serialize2) { } -DEPENDENT_TEST(DeserializeAndRunScript, Serialize) { +DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) { v8::HandleScope scope; Deserialize(); - const char* c_source = "\"1234\".length"; - v8::Local source = v8::String::New(c_source); - v8::Local script = v8::Script::Compile(source); - CHECK_EQ(4, script->Run()->Int32Value()); -} - - -DEPENDENT_TEST(DeserializeAndRunScript2, Serialize2) { - v8::HandleScope scope; - - Deserialize2(); - v8::Persistent env = v8::Context::New(); env->Enter(); @@ -314,31 +242,6 @@ DEPENDENT_TEST(DeserializeAndRunScript2, Serialize2) { } -DEPENDENT_TEST(DeserializeNatives, Serialize) { - v8::HandleScope scope; - - Deserialize(); - - const char* c_source = "\"abcd\".charAt(2) == 'c'"; - v8::Local source = v8::String::New(c_source); - v8::Local script = v8::Script::Compile(source); - v8::Local value = script->Run(); - CHECK(value->BooleanValue()); -} - - -DEPENDENT_TEST(DeserializeExtensions, Serialize) { - v8::HandleScope scope; - - Deserialize(); - const char* c_source = "gc();"; - v8::Local source = v8::String::New(c_source); - v8::Local script = v8::Script::Compile(source); - v8::Local value = script->Run(); - CHECK(value->IsUndefined()); -} - - TEST(TestThatAlwaysSucceeds) { }