From b9d37517d2225bc236cde005aeb7fa548264fbe6 Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Tue, 3 Nov 2009 21:00:43 +0000 Subject: [PATCH] * Do a GC in mksnapshot to get rid of some extraneous junk. * Make snapshot more compact by coding the tag and the space in one byte. Contract some common sequences to one byte. * Use back references only within one page. Index from the start of the space otherwise. * Serialize Smis as raw data rather than int-encoding them. This takes a little more space but is faster. Review URL: http://codereview.chromium.org/341079 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3208 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mksnapshot.cc | 3 + src/objects.h | 3 +- src/serialize.cc | 411 ++++++++++++++++++++++++++++++---------------- src/serialize.h | 99 +++++++---- 4 files changed, 341 insertions(+), 175 deletions(-) diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc index 083d11f28..f9dbd5c9f 100644 --- a/src/mksnapshot.cc +++ b/src/mksnapshot.cc @@ -194,6 +194,9 @@ int main2(int argc, char** argv) { 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; } diff --git a/src/objects.h b/src/objects.h index a8cbbfc4d..232cabf13 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2910,7 +2910,8 @@ class Code: public HeapObject { void CodeVerify(); #endif // Code entry points are aligned to 32 bytes. - static const int kCodeAlignment = 32; + static const int kCodeAlignmentBits = 5; + static const int kCodeAlignment = 1 << kCodeAlignmentBits; static const int kCodeAlignmentMask = kCodeAlignment - 1; // Layout description. diff --git a/src/serialize.cc b/src/serialize.cc index 398ccc7c9..3c333d068 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -1767,55 +1767,31 @@ Object* Deserializer::Resolve(Address encoded) { Deserializer2::Deserializer2(SnapshotByteSource* source) : source_(source), external_reference_decoder_(NULL) { - for (int i = 0; i <= LAST_SPACE; i++) { - fullness_[i] = 0; - } } // This routine both allocates a new object, and also keeps // track of where objects have been allocated so that we can // fix back references when deserializing. -Address Deserializer2::Allocate(int space_index, int size) { - HeapObject* new_object; - int old_fullness = CurrentAllocationAddress(space_index); - // When we start a new page we need to record its location. - bool record_page = (old_fullness == 0); - if (SpaceIsPaged(space_index)) { - PagedSpace* space; - switch (space_index) { - case OLD_DATA_SPACE: space = Heap::old_data_space(); break; - case OLD_POINTER_SPACE: space = Heap::old_pointer_space(); break; - case MAP_SPACE: space = Heap::map_space(); break; - case CODE_SPACE: space = Heap::code_space(); break; - case CELL_SPACE: space = Heap::cell_space(); break; - default: UNREACHABLE(); space = NULL; break; - } - ASSERT(size <= Page::kPageSize - Page::kObjectStartOffset); - int current_page = old_fullness >> Page::kPageSizeBits; - int new_fullness = old_fullness + size; - int new_page = new_fullness >> Page::kPageSizeBits; - // What is our new position within the current page. - int intra_page_offset = new_fullness - current_page * Page::kPageSize; - if (intra_page_offset > Page::kPageSize - Page::kObjectStartOffset) { - // This object will not fit in a page and we have to move to the next. - new_page = current_page + 1; - old_fullness = new_page << Page::kPageSizeBits; - new_fullness = old_fullness + size; - record_page = true; +Address Deserializer2::Allocate(int space_index, Space* space, int size) { + Address address; + if (!SpaceIsLarge(space_index)) { + ASSERT(!SpaceIsPaged(space_index) || + size <= Page::kPageSize - Page::kObjectStartOffset); + Object* new_allocation; + if (space_index == NEW_SPACE) { + new_allocation = reinterpret_cast(space)->AllocateRaw(size); + } else { + new_allocation = reinterpret_cast(space)->AllocateRaw(size); } - fullness_[space_index] = new_fullness; - Object* new_allocation = space->AllocateRaw(size); - new_object = HeapObject::cast(new_allocation); + HeapObject* new_object = HeapObject::cast(new_allocation); ASSERT(!new_object->IsFailure()); - ASSERT((reinterpret_cast(new_object->address()) & - Page::kPageAlignmentMask) == - (old_fullness & Page::kPageAlignmentMask) + - Page::kObjectStartOffset); - } else if (SpaceIsLarge(space_index)) { + address = new_object->address(); + high_water_[space_index] = address + size; + } else { + ASSERT(SpaceIsLarge(space_index)); ASSERT(size > Page::kPageSize - Page::kObjectStartOffset); - fullness_[LO_SPACE]++; - LargeObjectSpace* lo_space = Heap::lo_space(); + LargeObjectSpace* lo_space = reinterpret_cast(space); Object* new_allocation; if (space_index == kLargeData) { new_allocation = lo_space->AllocateRaw(size); @@ -1826,45 +1802,43 @@ Address Deserializer2::Allocate(int space_index, int size) { new_allocation = lo_space->AllocateRawCode(size); } ASSERT(!new_allocation->IsFailure()); - new_object = HeapObject::cast(new_allocation); - record_page = true; - // The page recording below records all large objects in the same space. - space_index = LO_SPACE; - } else { - ASSERT(space_index == NEW_SPACE); - Object* new_allocation = Heap::new_space()->AllocateRaw(size); - fullness_[space_index] += size; - ASSERT(!new_allocation->IsFailure()); - new_object = HeapObject::cast(new_allocation); - } - Address address = new_object->address(); - if (record_page) { - pages_[space_index].Add(address); + HeapObject* new_object = HeapObject::cast(new_allocation); + // Record all large objects in the same space. + address = new_object->address(); + high_water_[LO_SPACE] = address + size; } + last_object_address_ = address; return address; } // This returns the address of an object that has been described in the // snapshot as being offset bytes back in a particular space. -HeapObject* Deserializer2::GetAddress(int space) { +HeapObject* Deserializer2::GetAddressFromEnd(int space) { + int offset = source_->GetInt(); + ASSERT(!SpaceIsLarge(space)); + offset <<= kObjectAlignmentBits; + return HeapObject::FromAddress(high_water_[space] - offset); +} + + +// This returns the address of an object that has been described in the +// snapshot as being offset bytes into a particular space. +HeapObject* Deserializer2::GetAddressFromStart(int space) { int offset = source_->GetInt(); if (SpaceIsLarge(space)) { // Large spaces have one object per 'page'. - return HeapObject::FromAddress( - pages_[LO_SPACE][fullness_[LO_SPACE] - offset]); + return HeapObject::FromAddress(pages_[LO_SPACE][offset]); } offset <<= kObjectAlignmentBits; if (space == NEW_SPACE) { // New space has only one space - numbered 0. - return HeapObject::FromAddress( - pages_[space][0] + fullness_[space] - offset); + return HeapObject::FromAddress(pages_[space][0] + offset); } ASSERT(SpaceIsPaged(space)); - int virtual_address = fullness_[space] - offset; - int page_of_pointee = (virtual_address) >> Page::kPageSizeBits; + int page_of_pointee = offset >> Page::kPageSizeBits; Address object_address = pages_[space][page_of_pointee] + - (virtual_address & Page::kPageAlignmentMask); + (offset & Page::kPageAlignmentMask); return HeapObject::FromAddress(object_address); } @@ -1888,20 +1862,11 @@ void Deserializer2::Deserialize() { // This is called on the roots. It is the driver of the deserialization -// process. +// process. It is also called on the body of each function. void Deserializer2::VisitPointers(Object** start, Object** end) { - for (Object** current = start; current < end; current++) { - DataType data = static_cast(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); - } - } + // The space must be new space. Any other space would cause ReadChunk to try + // to update the remembered using NULL as the address. + ReadChunk(start, end, NEW_SPACE, NULL); } @@ -1911,19 +1876,46 @@ void Deserializer2::VisitPointers(Object** start, Object** end) { // written very late, which means the ByteArray map is not set up by the // time we need to use it to mark the space at the end of a page free (by // making it into a byte array). -bool Deserializer2::ReadObject(Object** write_back) { - int space = source_->Get(); +void Deserializer2::ReadObject(int space_number, + Space* space, + Object** write_back) { int size = source_->GetInt() << kObjectAlignmentBits; - Address address = Allocate(space, size); + Address address = Allocate(space_number, space, size); *write_back = HeapObject::FromAddress(address); Object** current = reinterpret_cast(address); Object** limit = current + (size >> kPointerSizeLog2); + ReadChunk(current, limit, space_number, address); +} + + +#define ONE_CASE_PER_SPACE(base_tag) \ + case (base_tag) + NEW_SPACE: /* NOLINT */ \ + case (base_tag) + OLD_POINTER_SPACE: /* NOLINT */ \ + case (base_tag) + OLD_DATA_SPACE: /* NOLINT */ \ + case (base_tag) + CODE_SPACE: /* NOLINT */ \ + case (base_tag) + MAP_SPACE: /* NOLINT */ \ + case (base_tag) + CELL_SPACE: /* NOLINT */ \ + case (base_tag) + kLargeData: /* NOLINT */ \ + case (base_tag) + kLargeCode: /* NOLINT */ \ + case (base_tag) + kLargeFixedArray: /* NOLINT */ + + +void Deserializer2::ReadChunk(Object** current, + Object** limit, + int space, + Address address) { while (current < limit) { - DataType data = static_cast(source_->Get()); + int data = source_->Get(); switch (data) { - case SMI_SERIALIZATION: - *current++ = Smi::FromInt(source_->GetInt() - kSmiBias); - break; +#define RAW_CASE(index, size) \ + case RAW_DATA_SERIALIZATION + index: { \ + byte* raw_data_out = reinterpret_cast(current); \ + source_->CopyRaw(raw_data_out, size); \ + current = reinterpret_cast(raw_data_out + size); \ + break; \ + } + COMMON_RAW_LENGTHS(RAW_CASE) +#undef RAW_CASE case RAW_DATA_SERIALIZATION: { int size = source_->GetInt(); byte* raw_data_out = reinterpret_cast(current); @@ -1931,19 +1923,54 @@ bool Deserializer2::ReadObject(Object** write_back) { current = reinterpret_cast(raw_data_out + size); break; } - case OBJECT_SERIALIZATION: { - // Recurse to unpack an object that is forward-referenced from here. - bool in_new_space = ReadObject(current); - if (in_new_space && space != NEW_SPACE) { + case OBJECT_SERIALIZATION + NEW_SPACE: { + ReadObject(NEW_SPACE, Heap::new_space(), current); + if (space != NEW_SPACE) { Heap::RecordWrite(address, reinterpret_cast
(current) - address); } current++; break; } - case CODE_OBJECT_SERIALIZATION: { + case OBJECT_SERIALIZATION + OLD_DATA_SPACE: + ReadObject(OLD_DATA_SPACE, Heap::old_data_space(), current++); + break; + case OBJECT_SERIALIZATION + OLD_POINTER_SPACE: + ReadObject(OLD_POINTER_SPACE, Heap::old_pointer_space(), current++); + break; + case OBJECT_SERIALIZATION + MAP_SPACE: + ReadObject(MAP_SPACE, Heap::map_space(), current++); + break; + case OBJECT_SERIALIZATION + CODE_SPACE: + ReadObject(CODE_SPACE, Heap::code_space(), current++); + break; + case OBJECT_SERIALIZATION + CELL_SPACE: + ReadObject(CELL_SPACE, Heap::cell_space(), current++); + break; + case OBJECT_SERIALIZATION + kLargeData: + ReadObject(kLargeData, Heap::lo_space(), current++); + break; + case OBJECT_SERIALIZATION + kLargeCode: + ReadObject(kLargeCode, Heap::lo_space(), current++); + break; + case OBJECT_SERIALIZATION + kLargeFixedArray: + ReadObject(kLargeFixedArray, Heap::lo_space(), current++); + break; + case CODE_OBJECT_SERIALIZATION + kLargeCode: { + Object* new_code_object = NULL; + ReadObject(kLargeCode, Heap::lo_space(), &new_code_object); + Code* code_object = reinterpret_cast(new_code_object); + // Setting a branch/call to another code object from code. + Address location_of_branch_data = reinterpret_cast
(current); + Assembler::set_target_at(location_of_branch_data, + code_object->instruction_start()); + location_of_branch_data += Assembler::kCallTargetSize; + current = reinterpret_cast(location_of_branch_data); + break; + } + case CODE_OBJECT_SERIALIZATION + CODE_SPACE: { Object* new_code_object = NULL; - ReadObject(&new_code_object); + ReadObject(CODE_SPACE, Heap::code_space(), &new_code_object); Code* code_object = reinterpret_cast(new_code_object); // Setting a branch/call to another code object from code. Address location_of_branch_data = reinterpret_cast
(current); @@ -1953,21 +1980,42 @@ bool Deserializer2::ReadObject(Object** write_back) { current = reinterpret_cast(location_of_branch_data); break; } - case BACKREF_SERIALIZATION: { + ONE_CASE_PER_SPACE(BACKREF_SERIALIZATION) { // Write a backreference to an object we unpacked earlier. - int backref_space = source_->Get(); + int backref_space = (data & kSpaceMask); if (backref_space == NEW_SPACE && space != NEW_SPACE) { Heap::RecordWrite(address, reinterpret_cast
(current) - address); } - *current++ = GetAddress(backref_space); + *current++ = GetAddressFromEnd(backref_space); break; } - case CODE_BACKREF_SERIALIZATION: { - int backref_space = source_->Get(); + ONE_CASE_PER_SPACE(REFERENCE_SERIALIZATION) { + // Write a reference to an object we unpacked earlier. + int reference_space = (data & kSpaceMask); + if (reference_space == NEW_SPACE && space != NEW_SPACE) { + Heap::RecordWrite(address, + reinterpret_cast
(current) - address); + } + *current++ = GetAddressFromStart(reference_space); + break; + } +#define COMMON_REFS_CASE(index, reference_space, address) \ + case REFERENCE_SERIALIZATION + index: { \ + ASSERT(SpaceIsPaged(reference_space)); \ + Address object_address = \ + pages_[reference_space][0] + (address << kObjectAlignmentBits); \ + *current++ = HeapObject::FromAddress(object_address); \ + break; \ + } + COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE) +#undef COMMON_REFS_CASE + ONE_CASE_PER_SPACE(CODE_BACKREF_SERIALIZATION) { + int backref_space = (data & kSpaceMask); // Can't use Code::cast because heap is not set up yet and assertions // will fail. - Code* code_object = reinterpret_cast(GetAddress(backref_space)); + Code* code_object = + reinterpret_cast(GetAddressFromEnd(backref_space)); // Setting a branch/call to previously decoded code object from code. Address location_of_branch_data = reinterpret_cast
(current); Assembler::set_target_at(location_of_branch_data, @@ -1975,7 +2023,21 @@ bool Deserializer2::ReadObject(Object** write_back) { location_of_branch_data += Assembler::kCallTargetSize; current = reinterpret_cast(location_of_branch_data); break; - } + } + ONE_CASE_PER_SPACE(CODE_REFERENCE_SERIALIZATION) { + int backref_space = (data & kSpaceMask); + // Can't use Code::cast because heap is not set up yet and assertions + // will fail. + Code* code_object = + reinterpret_cast(GetAddressFromStart(backref_space)); + // Setting a branch/call to previously decoded code object from code. + Address location_of_branch_data = reinterpret_cast
(current); + Assembler::set_target_at(location_of_branch_data, + code_object->instruction_start()); + location_of_branch_data += Assembler::kCallTargetSize; + current = reinterpret_cast(location_of_branch_data); + break; + } case EXTERNAL_REFERENCE_SERIALIZATION: { int reference_id = source_->GetInt(); Address address = external_reference_decoder_->Decode(reference_id); @@ -1991,12 +2053,16 @@ bool Deserializer2::ReadObject(Object** write_back) { current = reinterpret_cast(location_of_branch_data); break; } + case START_NEW_PAGE_SERIALIZATION: { + int space = source_->Get(); + pages_[space].Add(last_object_address_); + break; + } default: UNREACHABLE(); } } ASSERT(current == limit); - return space == NEW_SPACE; } @@ -2004,10 +2070,10 @@ void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) { const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7; for (int shift = max_shift; shift > 0; shift -= 7) { if (integer >= 1u << shift) { - Put(((integer >> shift) & 0x7f) | 0x80, "intpart"); + Put(((integer >> shift) & 0x7f) | 0x80, "IntPart"); } } - Put(integer & 0x7f, "intlastpart"); + PutSection(integer & 0x7f, "IntLastPart"); } #ifdef DEBUG @@ -2035,7 +2101,7 @@ void Serializer2::Synchronize(const char* tag) { int character; do { character = *tag++; - sink_->Put(character, "tagcharacter"); + sink_->PutSection(character, "TagCharacter"); } while (character != 0); } @@ -2067,7 +2133,15 @@ void Serializer2::Serialize() { void Serializer2::VisitPointers(Object** start, Object** end) { for (Object** current = start; current < end; current++) { - SerializeObject(*current, TAGGED_REPRESENTATION); + if ((*current)->IsSmi()) { + sink_->Put(RAW_DATA_SERIALIZATION, "RawData"); + sink_->PutInt(kPointerSize, "length"); + for (int i = 0; i < kPointerSize; i++) { + sink_->Put(reinterpret_cast(current)[i], "Byte"); + } + } else { + SerializeObject(*current, TAGGED_REPRESENTATION); + } } } @@ -2075,59 +2149,89 @@ void Serializer2::VisitPointers(Object** start, Object** end) { 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"); + ASSERT(o->IsHeapObject()); + HeapObject* heap_object = HeapObject::cast(o); + MapWord map_word = heap_object->map_word(); + if (map_word.IsSerializationAddress()) { + int space = SpaceOfAlreadySerializedObject(heap_object); + int address = map_word.ToSerializationAddress(); + int offset = CurrentAllocationAddress(space) - address; + bool from_start = true; + if (SpaceIsPaged(space)) { + if ((CurrentAllocationAddress(space) >> Page::kPageSizeBits) == + (address >> Page::kPageSizeBits)) { + from_start = false; + address = offset; + } + } else if (space == NEW_SPACE) { + if (offset < address) { + from_start = false; + address = offset; + } + } + // If we are actually dealing with real offsets (and not a numbering of + // all objects) then we should shift out the bits that are always 0. + if (!SpaceIsLarge(space)) address >>= kObjectAlignmentBits; + if (reference_representation == CODE_TARGET_REPRESENTATION) { + if (from_start) { + sink_->Put(CODE_REFERENCE_SERIALIZATION + space, "RefCodeSer"); + sink_->PutInt(address, "address"); } else { - ASSERT(reference_representation == TAGGED_REPRESENTATION); - sink_->Put(BACKREF_SERIALIZATION, "BackRefSerialization"); + sink_->Put(CODE_BACKREF_SERIALIZATION + space, "BackRefCodeSer"); + sink_->PutInt(address, "address"); } - sink_->Put(space, "space"); - sink_->PutInt(offset, "offset"); } else { - // Object has not yet been serialized. Serialize it here. - ObjectSerializer serializer(this, - heap_object, - sink_, - reference_representation); - serializer.Serialize(); + ASSERT(reference_representation == TAGGED_REPRESENTATION); + if (from_start) { +#define COMMON_REFS_CASE(tag, common_space, common_offset) \ + if (space == common_space && address == common_offset) { \ + sink_->PutSection(tag + REFERENCE_SERIALIZATION, "RefSer"); \ + } else /* NOLINT */ + COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE) +#undef COMMON_REFS_CASE + { /* NOLINT */ + sink_->Put(REFERENCE_SERIALIZATION + space, "RefSer"); + sink_->PutInt(address, "address"); + } + } else { + sink_->Put(BACKREF_SERIALIZATION + space, "BackRefSer"); + sink_->PutInt(address, "address"); + } } } else { - // Serialize a Smi. - unsigned int value = Smi::cast(o)->value() + kSmiBias; - sink_->Put(SMI_SERIALIZATION, "SmiSerialization"); - sink_->PutInt(value, "smi"); + // Object has not yet been serialized. Serialize it here. + ObjectSerializer serializer(this, + heap_object, + sink_, + reference_representation); + serializer.Serialize(); } } + void Serializer2::ObjectSerializer::Serialize() { int space = Serializer2::SpaceOfObject(object_); int size = object_->Size(); if (reference_representation_ == TAGGED_REPRESENTATION) { - sink_->Put(OBJECT_SERIALIZATION, "ObjectSerialization"); + sink_->Put(OBJECT_SERIALIZATION + space, "ObjectSerialization"); } else { ASSERT(reference_representation_ == CODE_TARGET_REPRESENTATION); - sink_->Put(CODE_OBJECT_SERIALIZATION, "ObjectSerialization"); + sink_->Put(CODE_OBJECT_SERIALIZATION + space, "ObjectSerialization"); } - sink_->Put(space, "space"); sink_->PutInt(size >> kObjectAlignmentBits, "Size in words"); // Get the map before overwriting it. Map* map = object_->map(); // Mark this object as already serialized. - object_->set_map_word( - MapWord::FromSerializationAddress(serializer_->Allocate(space, size))); + bool start_new_page; + object_->set_map_word(MapWord::FromSerializationAddress( + serializer_->Allocate(space, size, &start_new_page))); + if (start_new_page) { + sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage"); + sink_->PutSection(space, "NewPageSpace"); + } // Serialize the map (first word of the object). serializer_->SerializeObject(map, TAGGED_REPRESENTATION); @@ -2142,13 +2246,17 @@ void Serializer2::ObjectSerializer::Serialize() { void Serializer2::ObjectSerializer::VisitPointers(Object** start, Object** end) { - Address pointers_start = reinterpret_cast
(start); - OutputRawData(pointers_start); - - for (Object** current = start; current < end; current++) { - serializer_->SerializeObject(*current, TAGGED_REPRESENTATION); + Object** current = start; + while (current < end) { + while (current < end && (*current)->IsSmi()) current++; + OutputRawData(reinterpret_cast
(current)); + + while (current < end && !(*current)->IsSmi()) { + serializer_->SerializeObject(*current, TAGGED_REPRESENTATION); + bytes_processed_so_far_ += kPointerSize; + current++; + } } - bytes_processed_so_far_ += (end - start) * kPointerSize; } @@ -2158,7 +2266,7 @@ void Serializer2::ObjectSerializer::VisitExternalReferences(Address* start, OutputRawData(references_start); for (Address* current = start; current < end; current++) { - sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "External reference"); + sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "ExternalReference"); int reference_id = serializer_->EncodeExternalReference(*current); sink_->PutInt(reference_id, "reference id"); } @@ -2172,7 +2280,7 @@ void Serializer2::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) { Address target = rinfo->target_address(); uint32_t encoding = serializer_->EncodeExternalReference(target); CHECK(target == NULL ? encoding == 0 : encoding != 0); - sink_->Put(EXTERNAL_BRANCH_TARGET_SERIALIZATION, "External reference"); + sink_->Put(EXTERNAL_BRANCH_TARGET_SERIALIZATION, "ExternalReference"); sink_->PutInt(encoding, "reference id"); bytes_processed_so_far_ += Assembler::kExternalTargetSize; } @@ -2196,11 +2304,20 @@ void Serializer2::ObjectSerializer::OutputRawData(Address up_to) { // locations in a non-ascending order. Luckily that doesn't happen. ASSERT(skipped >= 0); if (skipped != 0) { - sink_->Put(RAW_DATA_SERIALIZATION, "raw data"); - sink_->PutInt(skipped, "length"); + Address base = object_start + bytes_processed_so_far_; +#define RAW_CASE(index, length) \ + if (skipped == length) { \ + sink_->PutSection(RAW_DATA_SERIALIZATION + index, "RawDataFixed"); \ + } else /* NOLINT */ + COMMON_RAW_LENGTHS(RAW_CASE) +#undef RAW_CASE + { /* NOLINT */ + sink_->Put(RAW_DATA_SERIALIZATION, "RawData"); + sink_->PutInt(skipped, "length"); + } for (int i = 0; i < skipped; i++) { - unsigned int data = object_start[bytes_processed_so_far_ + i]; - sink_->Put(data, "byte"); + unsigned int data = base[i]; + sink_->PutSection(data, "Byte"); } bytes_processed_so_far_ += skipped; } @@ -2240,13 +2357,18 @@ int Serializer2::SpaceOfAlreadySerializedObject(HeapObject* object) { } -int Serializer2::Allocate(int space, int size) { +int Serializer2::Allocate(int space, int size, bool* new_page) { 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. + *new_page = true; return fullness_[LO_SPACE]++; } + *new_page = false; + if (fullness_[space] == 0) { + *new_page = true; + } if (SpaceIsPaged(space)) { // Paged spaces are a little special. We encode their addresses as if the // pages were all contiguous and each page were filled up in the range @@ -2258,6 +2380,7 @@ int Serializer2::Allocate(int space, int size) { int used_in_this_page = (fullness_[space] & (Page::kPageSize - 1)); ASSERT(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 5966cbc3b..d634a807e 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -396,6 +396,34 @@ 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. +#define COMMON_REFERENCE_PATTERNS(f) \ + f(kNumberOfSpaces, 2, 10) \ + f(kNumberOfSpaces + 1, 2, 5) \ + f(kNumberOfSpaces + 2, 4, 28) \ + f(kNumberOfSpaces + 3, 2, 21) \ + f(kNumberOfSpaces + 4, 2, 98) \ + f(kNumberOfSpaces + 5, 2, 67) \ + f(kNumberOfSpaces + 6, 4, 132) + +#define COMMON_RAW_LENGTHS(f) \ + f(1, 1) \ + f(2, 2) \ + f(3, 3) \ + f(4, 4) \ + f(5, 5) \ + f(6, 6) \ + f(7, 7) \ + f(8, 8) \ + f(9, 12) \ + f(10, 16) \ + f(11, 20) \ + f(12, 24) \ + f(13, 28) \ + f(14, 32) \ + f(15, 36) // The SerDes class is a common superclass for Serializer2 and Deserializer2 // which is used to store common constants and methods used by both. @@ -403,25 +431,37 @@ class SnapshotByteSource { class SerDes: public GenericDeserializer { protected: enum DataType { - SMI_SERIALIZATION, - RAW_DATA_SERIALIZATION, - OBJECT_SERIALIZATION, - CODE_OBJECT_SERIALIZATION, - BACKREF_SERIALIZATION, - CODE_BACKREF_SERIALIZATION, - EXTERNAL_REFERENCE_SERIALIZATION, - EXTERNAL_BRANCH_TARGET_SERIALIZATION, - SYNCHRONIZE + RAW_DATA_SERIALIZATION = 0, + // And 15 common raw lengths. + OBJECT_SERIALIZATION = 16, + // One variant per space. + CODE_OBJECT_SERIALIZATION = 25, + // One per space (only code spaces in use). + EXTERNAL_REFERENCE_SERIALIZATION = 34, + EXTERNAL_BRANCH_TARGET_SERIALIZATION = 35, + SYNCHRONIZE = 36, + START_NEW_PAGE_SERIALIZATION = 37, + // Free: 38-47. + BACKREF_SERIALIZATION = 48, + // One per space, must be kSpaceMask aligned. + // Free: 57-63. + REFERENCE_SERIALIZATION = 64, + // One per space and common references. Must be kSpaceMask aligned. + CODE_BACKREF_SERIALIZATION = 80, + // One per space, must be kSpaceMask aligned. + // Free: 89-95. + CODE_REFERENCE_SERIALIZATION = 96 + // One per space, must be kSpaceMask aligned. + // Free: 105-255. }; - // Our Smi encoding is much more efficient for small positive integers than it - // is for negative numbers so we add a bias before encoding and subtract it - // after encoding so that popular small negative Smis are efficiently encoded. - static const int kSmiBias = 16; static const int kLargeData = LAST_SPACE; static const int kLargeCode = kLargeData + 1; static const int kLargeFixedArray = kLargeCode + 1; static const int kNumberOfSpaces = kLargeFixedArray + 1; + // A bitmask for getting the space out of an instruction. + static const int kSpaceMask = 15; + static inline bool SpaceIsLarge(int space) { return space >= kLargeData; } static inline bool SpaceIsPaged(int space) { return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE; @@ -456,17 +496,11 @@ class Deserializer2: public SerDes { UNREACHABLE(); } - int CurrentAllocationAddress(int space) { - // The three different kinds of large objects have different tags in the - // snapshot so the deserializer knows which kind of object to allocate, - // but they share a fullness_ entry. - if (SpaceIsLarge(space)) space = LO_SPACE; - return fullness_[space]; - } - - HeapObject* GetAddress(int space); - Address Allocate(int space, int size); - bool ReadObject(Object** write_back); + void ReadChunk(Object** start, Object** end, int space, Address address); + HeapObject* GetAddressFromStart(int space); + inline HeapObject* GetAddressFromEnd(int space); + Address Allocate(int space_number, Space* space, int size); + void ReadObject(int space_number, Space* space, Object** write_back); // Keep track of the pages in the paged spaces. // (In large object space we are keeping track of individual objects @@ -476,11 +510,13 @@ class Deserializer2: public SerDes { SnapshotByteSource* source_; ExternalReferenceDecoder* external_reference_decoder_; - // Keep track of the fullness of each space in order to generate - // relative addresses for back references. Large objects are - // just numbered sequentially since relative addresses make no - // sense in large object space. - int fullness_[LAST_SPACE + 1]; + // This is the address of the next object that will be allocated in each + // space. It is used to calculate the addresses of back-references. + Address high_water_[LAST_SPACE + 1]; + // This is the address of the most recent object that was allocated. It + // is used to set the location of the new page when we encounter a + // START_NEW_PAGE_SERIALIZATION tag. + Address last_object_address_; DISALLOW_COPY_AND_ASSIGN(Deserializer2); }; @@ -490,6 +526,9 @@ class SnapshotByteSink { public: virtual ~SnapshotByteSink() { } virtual void Put(int byte, const char* description) = 0; + virtual void PutSection(int byte, const char* description) { + Put(byte, description); + } void PutInt(uintptr_t integer, const char* description); }; @@ -550,7 +589,7 @@ class Serializer2 : public SerDes { // for all large objects since you can't check the type of the object // once the map has been used for the serialization address. static int SpaceOfAlreadySerializedObject(HeapObject* object); - int Allocate(int space, int size); + int Allocate(int space, int size, bool* new_page_started); int CurrentAllocationAddress(int space) { if (SpaceIsLarge(space)) space = LO_SPACE; return fullness_[space]; -- 2.34.1