Commit 64941f1c authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

* 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
parent 5f3bdbe5
......@@ -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);
}
......
......@@ -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<void*>(address_arg);
return redirector_ == NULL ? address : (*redirector_)(address, fp_return);
void* answer = (redirector_ == NULL) ?
address :
(*redirector_)(address, fp_return);
return answer;
}
void* address_;
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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<std::string, int*> CounterMap;
typedef std::map<std::string, int*>::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> 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> 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;
}
......@@ -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<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,
static_cast<int>(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<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 = StrLength(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(
static_cast<int>(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(
static_cast<int>(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(
static_cast<int>(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(
static_cast<int>(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 = StrLength(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, 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<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::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<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(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<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) {
}
......@@ -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<Address>(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<Address>(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<int>(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<AllocationSpace>(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<AllocationSpace>(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);
......
// 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<Handle<Object> >& 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<Object**> 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<Address>(&result), sizeof(result));
return result;
}
Address GetAddress() {
Address result;
GetBytes(reinterpret_cast<Address>(&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<char>(size + 1);
GetBytes(reinterpret_cast<Address>(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<Handle<Object> >* 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<Page*> map_pages_; // All pages in the map space.
List<Page*> cell_pages_; // All pages in the cell space.
List<Page*> old_pointer_pages_; // All pages in the old pointer space.
List<Page*> old_data_pages_; // All pages in the old data space.
List<Page*> code_pages_; // All pages in the code space.
List<Object*> large_objects_; // All known large objects.
// A list of global handles at deserialization time.
List<Object**> 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
......
......@@ -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;
}
......
......@@ -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);
};
......
......@@ -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();
......
......@@ -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
......
......@@ -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
......
......@@ -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<v8::Context> 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<v8::Context> 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<v8::Context> env = v8::Context::New();
v8::Context::Scope context_scope(env);
Serializer().Serialize();
const char* c_source = "\"abcd\".charAt(2) == 'c'";
v8::Local<v8::String> source = v8::String::New(c_source);
v8::Local<v8::Script> script = v8::Script::Compile(source);
v8::Local<v8::Value> 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<v8::Context> 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<v8::String> source = v8::String::New(c_source);
v8::Local<v8::Script> script = v8::Script::Compile(source);
CHECK_EQ(4, script->Run()->Int32Value());
}
DEPENDENT_TEST(DeserializeAndRunScript2, Serialize2) {
v8::HandleScope scope;
Deserialize2();
v8::Persistent<v8::Context> 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<v8::String> source = v8::String::New(c_source);
v8::Local<v8::Script> script = v8::Script::Compile(source);
v8::Local<v8::Value> value = script->Run();
CHECK(value->BooleanValue());
}
DEPENDENT_TEST(DeserializeExtensions, Serialize) {
v8::HandleScope scope;
Deserialize();
const char* c_source = "gc();";
v8::Local<v8::String> source = v8::String::New(c_source);
v8::Local<v8::Script> script = v8::Script::Compile(source);
v8::Local<v8::Value> value = script->Run();
CHECK(value->IsUndefined());
}
TEST(TestThatAlwaysSucceeds) {
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment