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

* 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
parent 6d425b70
......@@ -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;
}
......
......@@ -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.
......
......@@ -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<NewSpace*>(space)->AllocateRaw(size);
} else {
new_allocation = reinterpret_cast<PagedSpace*>(space)->AllocateRaw(size);
}
fullness_[space_index] = new_fullness;
Object* new_allocation = space->AllocateRaw(size);
new_object = HeapObject::cast(new_allocation);
HeapObject* new_object = HeapObject::cast(new_allocation);
ASSERT(!new_object->IsFailure());
ASSERT((reinterpret_cast<intptr_t>(new_object->address()) &
Page::kPageAlignmentMask) ==
(old_fullness & Page::kPageAlignmentMask) +
Page::kObjectStartOffset);
} else if (SpaceIsLarge(space_index)) {
address = new_object->address();
high_water_[space_index] = address + size;
} else {
ASSERT(SpaceIsLarge(space_index));
ASSERT(size > Page::kPageSize - Page::kObjectStartOffset);
fullness_[LO_SPACE]++;
LargeObjectSpace* lo_space = Heap::lo_space();
LargeObjectSpace* lo_space = reinterpret_cast<LargeObjectSpace*>(space);
Object* new_allocation;
if (space_index == kLargeData) {
new_allocation = lo_space->AllocateRaw(size);
......@@ -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<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);
}
}
// 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<Object**>(address);
Object** limit = current + (size >> kPointerSizeLog2);
ReadChunk(current, limit, space_number, address);
}
#define ONE_CASE_PER_SPACE(base_tag) \
case (base_tag) + NEW_SPACE: /* NOLINT */ \
case (base_tag) + OLD_POINTER_SPACE: /* NOLINT */ \
case (base_tag) + OLD_DATA_SPACE: /* NOLINT */ \
case (base_tag) + CODE_SPACE: /* NOLINT */ \
case (base_tag) + MAP_SPACE: /* NOLINT */ \
case (base_tag) + CELL_SPACE: /* NOLINT */ \
case (base_tag) + kLargeData: /* NOLINT */ \
case (base_tag) + kLargeCode: /* NOLINT */ \
case (base_tag) + kLargeFixedArray: /* NOLINT */
void Deserializer2::ReadChunk(Object** current,
Object** limit,
int space,
Address address) {
while (current < limit) {
DataType data = static_cast<DataType>(source_->Get());
int data = source_->Get();
switch (data) {
case SMI_SERIALIZATION:
*current++ = Smi::FromInt(source_->GetInt() - kSmiBias);
break;
#define RAW_CASE(index, size) \
case RAW_DATA_SERIALIZATION + index: { \
byte* raw_data_out = reinterpret_cast<byte*>(current); \
source_->CopyRaw(raw_data_out, size); \
current = reinterpret_cast<Object**>(raw_data_out + size); \
break; \
}
COMMON_RAW_LENGTHS(RAW_CASE)
#undef RAW_CASE
case RAW_DATA_SERIALIZATION: {
int size = source_->GetInt();
byte* raw_data_out = reinterpret_cast<byte*>(current);
......@@ -1931,19 +1923,54 @@ bool Deserializer2::ReadObject(Object** write_back) {
current = reinterpret_cast<Object**>(raw_data_out + size);
break;
}
case OBJECT_SERIALIZATION: {
// Recurse to unpack an object that is forward-referenced from here.
bool in_new_space = ReadObject(current);
if (in_new_space && space != NEW_SPACE) {
case OBJECT_SERIALIZATION + NEW_SPACE: {
ReadObject(NEW_SPACE, Heap::new_space(), current);
if (space != NEW_SPACE) {
Heap::RecordWrite(address,
reinterpret_cast<Address>(current) - address);
}
current++;
break;
}
case CODE_OBJECT_SERIALIZATION: {
case OBJECT_SERIALIZATION + OLD_DATA_SPACE:
ReadObject(OLD_DATA_SPACE, Heap::old_data_space(), current++);
break;
case OBJECT_SERIALIZATION + OLD_POINTER_SPACE:
ReadObject(OLD_POINTER_SPACE, Heap::old_pointer_space(), current++);
break;
case OBJECT_SERIALIZATION + MAP_SPACE:
ReadObject(MAP_SPACE, Heap::map_space(), current++);
break;
case OBJECT_SERIALIZATION + CODE_SPACE:
ReadObject(CODE_SPACE, Heap::code_space(), current++);
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<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_at(location_of_branch_data,
code_object->instruction_start());
location_of_branch_data += Assembler::kCallTargetSize;
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
}
case CODE_OBJECT_SERIALIZATION + CODE_SPACE: {
Object* new_code_object = NULL;
ReadObject(&new_code_object);
ReadObject(CODE_SPACE, Heap::code_space(), &new_code_object);
Code* code_object = reinterpret_cast<Code*>(new_code_object);
// Setting a branch/call to another code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
......@@ -1953,21 +1980,42 @@ bool Deserializer2::ReadObject(Object** write_back) {
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
}
case BACKREF_SERIALIZATION: {
ONE_CASE_PER_SPACE(BACKREF_SERIALIZATION) {
// Write a backreference to an object we unpacked earlier.
int backref_space = source_->Get();
int backref_space = (data & kSpaceMask);
if (backref_space == NEW_SPACE && space != NEW_SPACE) {
Heap::RecordWrite(address,
reinterpret_cast<Address>(current) - address);
}
*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<Address>(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<Code*>(GetAddress(backref_space));
Code* code_object =
reinterpret_cast<Code*>(GetAddressFromEnd(backref_space));
// Setting a branch/call to previously decoded code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
Assembler::set_target_at(location_of_branch_data,
......@@ -1975,7 +2023,21 @@ bool Deserializer2::ReadObject(Object** write_back) {
location_of_branch_data += Assembler::kCallTargetSize;
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
}
}
ONE_CASE_PER_SPACE(CODE_REFERENCE_SERIALIZATION) {
int backref_space = (data & kSpaceMask);
// Can't use Code::cast because heap is not set up yet and assertions
// will fail.
Code* code_object =
reinterpret_cast<Code*>(GetAddressFromStart(backref_space));
// Setting a branch/call to previously decoded code object from code.
Address location_of_branch_data = reinterpret_cast<Address>(current);
Assembler::set_target_at(location_of_branch_data,
code_object->instruction_start());
location_of_branch_data += Assembler::kCallTargetSize;
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
}
case EXTERNAL_REFERENCE_SERIALIZATION: {
int reference_id = source_->GetInt();
Address address = external_reference_decoder_->Decode(reference_id);
......@@ -1991,12 +2053,16 @@ bool Deserializer2::ReadObject(Object** write_back) {
current = reinterpret_cast<Object**>(location_of_branch_data);
break;
}
case START_NEW_PAGE_SERIALIZATION: {
int space = source_->Get();
pages_[space].Add(last_object_address_);
break;
}
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<byte*>(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<Address>(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<Address>(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);
}
}
......
......@@ -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];
......
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