Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1389)

Unified Diff: src/serialize.cc

Issue 335009: New snapshot framework. Doesn't work on ARM yet (code targets... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/serialize.cc
===================================================================
--- src/serialize.cc (revision 3115)
+++ src/serialize.cc (working copy)
@@ -1417,7 +1417,18 @@
#endif
+class NoGlobalHandlesChecker : public ObjectVisitor {
+ public:
+ virtual void VisitPointers(Object** start, Object** end) {
+ ASSERT(false);
+ }
+};
+
+
void Deserializer::Deserialize() {
+ // No global handles.
+ NoGlobalHandlesChecker checker;
+ GlobalHandles::IterateRoots(&checker);
// No active threads.
ASSERT_EQ(NULL, ThreadState::FirstInUse());
// No active handles.
@@ -1428,6 +1439,9 @@
GetHeader();
Heap::IterateRoots(this);
GetContextStack();
+ // Any global handles that have been set up by deserialization are leaked
+ // since noone is keeping track of them.
+ GlobalHandles::TearDown();
Mads Ager (chromium) 2009/10/26 11:14:05 Shouldn't we be checking that there are no global
Erik Corry 2009/10/27 09:49:58 No. Even if there are global handles we want to d
}
@@ -1740,4 +1754,475 @@
}
+Deserializer2::Deserializer2(SnapshotByteSource* source)
+ : source_(source),
Mads Ager (chromium) 2009/10/26 11:14:05 Four space indent.
+ external_reference_decoder_(NULL) {
+ for (int i = 0; i <= LAST_SPACE; i++) {
+ fullness_[i] = 0;
+ }
+}
+
+
+// This routine both allocates a new object, and also keeps
+// track of where objects have been allocated so that we can
+// fix back references when deserializing.
+Address Deserializer2::Allocate(int space_index, int size) {
+ HeapObject* new_object;
+ int old_fullness = CurrentAllocationAddress(space_index);
+ // When we start a new page we need to record its location.
+ bool record_page = (old_fullness == 0);
+ if (SpaceIsPaged(space_index)) {
+ PagedSpace* space;
+ switch (space_index) {
+ case OLD_DATA_SPACE: space = Heap::old_data_space(); break;
+ case OLD_POINTER_SPACE: space = Heap::old_pointer_space(); break;
+ case MAP_SPACE: space = Heap::map_space(); break;
+ case CODE_SPACE: space = Heap::code_space(); break;
+ case CELL_SPACE: space = Heap::cell_space(); break;
+ default: UNREACHABLE(); space = NULL; break;
+ }
+ ASSERT(size <= Page::kPageSize - Page::kObjectStartOffset);
+ int current_page = old_fullness >> Page::kPageSizeBits;
+ int new_fullness = old_fullness + size;
+ int new_page = new_fullness >> Page::kPageSizeBits;
+ // What is our new position within the current page.
+ int intra_page_offset = new_fullness - current_page * Page::kPageSize;
+ if (intra_page_offset > Page::kPageSize - Page::kObjectStartOffset) {
+ // This object will not fit in a page and we have to move to the next.
+ new_page = (old_fullness >> Page::kPageSizeBits) + 1;
Mads Ager (chromium) 2009/10/26 11:14:05 current_page + 1?
+ old_fullness = new_page << Page::kPageSizeBits;
+ new_fullness = old_fullness + size;
+ record_page = true;
+ }
+ fullness_[space_index] = new_fullness;
+ Object* new_allocation = space->AllocateRaw(size);
+ new_object = HeapObject::cast(new_allocation);
+ ASSERT(!new_object->IsFailure());
+ ASSERT((reinterpret_cast<intptr_t>(new_object->address()) &
+ Page::kPageAlignmentMask) ==
Mads Ager (chromium) 2009/10/26 11:14:05 Funky indentation. I would do: ASSERT((reinterpr
+ (old_fullness & Page::kPageAlignmentMask) +
+ Page::kObjectStartOffset);
+ } else if (SpaceIsLarge(space_index)) {
+ ASSERT(size > Page::kPageSize - Page::kObjectStartOffset);
+ fullness_[LO_SPACE]++;
+ LargeObjectSpace* lo_space = Heap::lo_space();
+ Object* new_allocation;
+ if (space_index == kLargeData) {
+ new_allocation = lo_space->AllocateRaw(size);
+ } else if (space_index == kLargeFixedArray) {
+ new_allocation = lo_space->AllocateRawFixedArray(size);
+ } else {
+ ASSERT(space_index == kLargeCode);
+ new_allocation = lo_space->AllocateRawCode(size);
+ }
+ ASSERT(!new_allocation->IsFailure());
+ new_object = HeapObject::cast(new_allocation);
+ record_page = true;
+ // The page recording below records all large objects in the same space.
+ space_index = LO_SPACE;
+ } else {
+ ASSERT(space_index == NEW_SPACE);
+ Object* new_allocation = Heap::new_space()->AllocateRaw(size);
+ fullness_[space_index] += size;
+ ASSERT(!new_allocation->IsFailure());
+ new_object = HeapObject::cast(new_allocation);
+ }
+ Address address = new_object->address();
+ if (record_page) {
+ pages_[space_index].Add(address);
+ }
+ return address;
+}
+
+
+// This returns the address of an object that has been described in the
+// snapshot as being offset bytes back in a particular space.
+HeapObject* Deserializer2::GetAddress(int space) {
+ int offset = source_->GetInt();
+ if (SpaceIsLarge(space)) {
+ // Large spaces have one object per 'page'.
+ return HeapObject::FromAddress(
+ pages_[LO_SPACE][fullness_[LO_SPACE] - offset]);
+ }
+ offset <<= kObjectAlignmentBits;
+ if (space == NEW_SPACE) {
+ // New space has only one space - numbered 0.
+ return HeapObject::FromAddress(
+ pages_[space][0] + fullness_[space] - offset);
+ }
+ ASSERT(SpaceIsPaged(space));
+ int virtual_address = fullness_[space] - offset;
+ int page_of_pointee = (virtual_address) >> Page::kPageSizeBits;
+ Address object_address = pages_[space][page_of_pointee] +
+ (virtual_address & Page::kPageAlignmentMask);
+ return HeapObject::FromAddress(object_address);
+}
+
+
+void Deserializer2::Deserialize() {
+ // Don't GC while deserializing - just expand the heap.
+ AlwaysAllocateScope always_allocate;
+ // Don't use the free lists while deserializing.
+ LinearAllocationScope allocate_linearly;
+ // No active threads.
+ ASSERT_EQ(NULL, ThreadState::FirstInUse());
+ // No active handles.
+ ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
+ ASSERT(external_reference_decoder_ == NULL);
+ external_reference_decoder_ = new ExternalReferenceDecoder();
+ Heap::IterateRoots(this);
+ ASSERT(source_->AtEOF());
+ delete external_reference_decoder_;
+ external_reference_decoder_ = NULL;
+}
+
+
+// This is called on the roots. It is the driver of the deserialization
+// process.
+void Deserializer2::VisitPointers(Object** start, Object** end) {
+ for (Object** current = start; current < end; current++) {
+ DataType data = static_cast<DataType>(source_->Get());
+ if (data == SMI_SERIALIZATION) {
+ *current = Smi::FromInt(source_->GetInt() - kSmiBias);
+ } else if (data == BACKREF_SERIALIZATION) {
+ int space = source_->Get();
+ *current = GetAddress(space);
+ } else {
+ ASSERT(data == OBJECT_SERIALIZATION);
+ ReadObject(current);
+ }
+ }
+}
+
+
+// This routine writes the new object into the pointer provided and then
+// returns a true of the new object was in young space and false otherwise.
Mads Ager (chromium) 2009/10/26 11:14:05 returns true if the new ...
+// The reason for this strange interface is that otherwise the object is
+// written very late, which means the ByteArray map is not set up by the
+// time we need to use it to mark the space at the end of a page free (by
+// making it into a byte array).
+bool Deserializer2::ReadObject(Object** write_back) {
+ int space = source_->Get();
+ int size = source_->GetInt() << kObjectAlignmentBits;
+ Address address = Allocate(space, size);
+ *write_back = HeapObject::FromAddress(address);
+ Object** current = reinterpret_cast<Object**>(address);
+ Object** limit = current + (size >> kPointerSizeLog2);
+ while (current < limit) {
+ DataType data = static_cast<DataType>(source_->Get());
+ switch (data) {
+ case SMI_SERIALIZATION:
+ *current++ = Smi::FromInt(source_->GetInt() - kSmiBias);
+ break;
+ case RAW_DATA_SERIALIZATION: {
+ int size = source_->GetInt();
+ byte* raw_data_out = reinterpret_cast<byte*>(current);
+ for (int j = 0; j < size; j++) {
+ *raw_data_out++ = source_->Get();
+ }
+ current = reinterpret_cast<Object**>(raw_data_out);
+ break;
+ }
+ case OBJECT_SERIALIZATION: {
+ // Recurse to unpack an object that is forward-referenced from here.
+ bool in_new_space = ReadObject(current);
+ if (in_new_space && space != NEW_SPACE) {
+ Heap::RecordWrite(address,
+ reinterpret_cast<Address>(current) - address);
+ }
+ current++;
+ break;
+ }
+ case CODE_OBJECT_SERIALIZATION: {
+ Object* new_code_object = NULL;
+ ReadObject(&new_code_object);
+ Code* code_object = reinterpret_cast<Code*>(new_code_object);
+ // Setting a branch/call to another code object from code.
+ Address location_of_branch_data = reinterpret_cast<Address>(current);
+ Assembler::set_target_address_at(location_of_branch_data,
+ code_object->instruction_start());
+ location_of_branch_data += Assembler::kCallTargetSize;
+ current = reinterpret_cast<Object**>(location_of_branch_data);
+ break;
+ }
+ case BACKREF_SERIALIZATION: {
+ // Write a backreference to an object we unpacked earlier.
+ int backref_space = source_->Get();
+ if (backref_space == NEW_SPACE && space != NEW_SPACE) {
+ Heap::RecordWrite(address,
+ reinterpret_cast<Address>(current) - address);
+ }
+ *current++ = GetAddress(backref_space);
+ break;
+ }
+ case CODE_BACKREF_SERIALIZATION: {
+ int backref_space = source_->Get();
+ // Can't use Code::cast because heap is not set up yet and assertions
+ // will fail.
+ Code* code_object = reinterpret_cast<Code*>(GetAddress(backref_space));
+ // Setting a branch/call to previously decoded code object from code.
+ Address location_of_branch_data = reinterpret_cast<Address>(current);
+ Assembler::set_target_address_at(location_of_branch_data,
+ code_object->instruction_start());
+ location_of_branch_data += Assembler::kCallTargetSize;
+ current = reinterpret_cast<Object**>(location_of_branch_data);
+ break;
+ }
+ case EXTERNAL_REFERENCE_SERIALIZATION: {
+ int reference_id = source_->GetInt();
+ Address address = external_reference_decoder_->Decode(reference_id);
+ *current++ = reinterpret_cast<Object*>(address);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ ASSERT(current == limit);
+ return space == NEW_SPACE;
+}
+
+#ifdef DEBUG
+
+void Deserializer2::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);
+ do {
+ int character = source_->Get();
+ if (character == 0) break;
+ if (FLAG_debug_serialization) {
+ PrintF("%c", character);
+ }
+ } while (true);
+ if (FLAG_debug_serialization) {
+ PrintF("\n");
+ }
+}
+
+
+void Serializer2::Synchronize(const char* tag) {
+ sink_->Put(SYNCHRONIZE, tag);
+ int character;
+ do {
+ character = *tag++;
+ sink_->Put(character, "tagcharacter");
+ } while (character != 0);
+}
+
+#endif
+
+Serializer2::Serializer2(SnapshotByteSink* sink)
+ : sink_(sink),
Mads Ager (chromium) 2009/10/26 11:14:05 Four space indent.
+ current_root_index_(0),
+ external_reference_encoder_(NULL) {
+ for (int i = 0; i <= LAST_SPACE; i++) {
+ fullness_[i] = 0;
+ }
+}
+
+
+void Serializer2::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);
+ external_reference_encoder_ = new ExternalReferenceEncoder();
+ Heap::IterateRoots(this);
+ delete external_reference_encoder_;
+ external_reference_encoder_ = NULL;
+}
+
+
+void Serializer2::VisitPointers(Object** start, Object** end) {
+ for (Object** current = start; current < end; current++) {
+ SerializeObject(*current, TAGGED_REPRESENTATION);
+ }
+}
+
+
+void Serializer2::SerializeObject(
+ Object* o,
+ ReferenceRepresentation reference_representation) {
+ if (o->IsHeapObject()) {
+ HeapObject* heap_object = HeapObject::cast(o);
+ MapWord map_word = heap_object->map_word();
+ if (map_word.IsSerializationAddress()) {
+ int space = SpaceOfAlreadySerializedObject(heap_object);
+ int offset =
+ CurrentAllocationAddress(space) - map_word.ToSerializationAddress();
+ // If we are actually dealing with real offsets (and not a numbering of
+ // all objects) then we should shift out the bits that are always 0.
+ if (!SpaceIsLarge(space)) offset >>= kObjectAlignmentBits;
+ if (reference_representation == CODE_TARGET_REPRESENTATION) {
+ sink_->Put(CODE_BACKREF_SERIALIZATION, "BackRefCodeSerialization");
+ } else {
+ ASSERT(reference_representation == TAGGED_REPRESENTATION);
+ sink_->Put(BACKREF_SERIALIZATION, "BackRefSerialization");
+ }
+ sink_->Put(space, "space");
+ sink_->PutInt(offset, "offset");
+ } else {
+ // Object has not yet been serialized. Serialize it here.
+ ObjectSerializer serializer(this,
+ heap_object,
+ sink_,
+ reference_representation);
+ serializer.Serialize();
+ }
+ } else {
+ // Serialize a Smi.
+ unsigned int value = Smi::cast(o)->value() + kSmiBias;
+ sink_->Put(SMI_SERIALIZATION, "SmiSerialization");
+ sink_->PutInt(value, "smi");
+ }
+}
+
+
+void Serializer2::ObjectSerializer::Serialize() {
+ int space = Serializer2::SpaceOfObject(object_);
+ int size = object_->Size();
+
+ if (reference_representation_ == TAGGED_REPRESENTATION) {
+ sink_->Put(OBJECT_SERIALIZATION, "ObjectSerialization");
+ } else {
+ ASSERT(reference_representation_ == CODE_TARGET_REPRESENTATION);
+ sink_->Put(CODE_OBJECT_SERIALIZATION, "ObjectSerialization");
+ }
+ sink_->Put(space, "space");
+ sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
+
+ // Get the map before overwriting it.
+ Map* map = object_->map();
+ // Mark this object as already serialized.
+ object_->set_map_word(
+ MapWord::FromSerializationAddress(serializer_->Allocate(space, size)));
+
+ // Serialize the map (first word of the object).
+ serializer_->SerializeObject(map, TAGGED_REPRESENTATION);
+
+ // Serialize the rest of the object.
+ ASSERT(bytes_processed_so_far_ == 0);
+ bytes_processed_so_far_ = kPointerSize;
+ object_->IterateBody(map->instance_type(), size, this);
+ OutputRawData(object_->address() + size);
+}
+
+
+void Serializer2::ObjectSerializer::VisitPointers(Object** start,
+ Object** end) {
+ Address pointers_start = reinterpret_cast<Address>(start);
+ OutputRawData(pointers_start);
+
+ for (Object** current = start; current < end; current++) {
+ serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
+ }
+ bytes_processed_so_far_ += (end - start) * kPointerSize;
+}
+
+
+void Serializer2::ObjectSerializer::VisitExternalReferences(Address* start,
+ Address* end) {
+ Address references_start = reinterpret_cast<Address>(start);
+ OutputRawData(references_start);
+
+ for (Address* current = start; current < end; current++) {
+ sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "External reference");
+ int reference_id = serializer_->EncodeExternalReference(*current);
+ sink_->PutInt(reference_id, "reference id");
+ }
+ bytes_processed_so_far_ += (end - start) * kPointerSize;
+}
+
+
+void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+ Address target_start = rinfo->target_address_address();
+ OutputRawData(target_start);
+ Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ serializer_->SerializeObject(target, CODE_TARGET_REPRESENTATION);
+ bytes_processed_so_far_ += Assembler::kCallTargetSize;
+}
+
+
+void Serializer2::ObjectSerializer::OutputRawData(Address up_to) {
+ Address object_start = object_->address();
+ int up_to_offset = up_to - object_start;
+ int skipped = up_to_offset - bytes_processed_so_far_;
+ ASSERT(skipped >= 0);
+ if (skipped != 0) {
+ sink_->Put(RAW_DATA_SERIALIZATION, "raw data");
+ sink_->PutInt(skipped, "length");
+ for (int i = 0; i < skipped; i++) {
+ unsigned int data = object_start[bytes_processed_so_far_ + i];
+ sink_->Put(data, "byte");
+ }
+ }
+ bytes_processed_so_far_ += skipped;
+}
+
+
+int Serializer2::SpaceOfObject(HeapObject* object) {
+ for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
+ AllocationSpace s = static_cast<AllocationSpace>(i);
+ if (Heap::InSpace(object, s)) {
+ if (i == LO_SPACE) {
+ if (object->IsCode()) {
+ return kLargeCode;
+ } else if (object->IsFixedArray()) {
+ return kLargeFixedArray;
+ } else {
+ return kLargeData;
+ }
+ }
+ return i;
+ }
+ }
+ UNREACHABLE();
+ return 0;
+}
+
+
+int Serializer2::SpaceOfAlreadySerializedObject(HeapObject* object) {
+ for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
+ AllocationSpace s = static_cast<AllocationSpace>(i);
+ if (Heap::InSpace(object, s)) {
+ return i;
+ }
+ }
+ UNREACHABLE();
+ return 0;
+}
+
+
+int Serializer2::Allocate(int space, int size) {
+ ASSERT(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.
+ return fullness_[LO_SPACE]++;
+ }
+ if (SpaceIsPaged(space)) {
+ // Paged spaces are a little special. We encode their addresses as if the
+ // pages were all contiguous and each page were filled up in the range
+ // 0 - Page::kObjectAreaSize. In practice the pages may not be contiguous
+ // 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));
+ int used_in_this_page = (fullness_[space] & (Page::kPageSize - 1));
+ ASSERT(size <= Page::kObjectAreaSize);
+ if (used_in_this_page + size > Page::kObjectAreaSize) {
+ fullness_[space] = RoundUp(fullness_[space], Page::kPageSize);
+ }
+ }
+ int allocation_address = fullness_[space];
+ fullness_[space] = allocation_address + size;
+ return allocation_address;
+}
+
+
} } // namespace v8::internal

Powered by Google App Engine
This is Rietveld 408576698