}
-#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 */
+// This macro is always used with a constant argument so it should all fold
+// away to almost nothing in the generated code. It might be nicer to do this
+// with the ternary operator but there are type issues with that.
+#define ASSIGN_DEST_SPACE(space_number) \
+ Space* dest_space; \
+ if (space_number == NEW_SPACE) { \
+ dest_space = Heap::new_space(); \
+ } else if (space_number == OLD_POINTER_SPACE) { \
+ dest_space = Heap::old_pointer_space(); \
+ } else if (space_number == OLD_DATA_SPACE) { \
+ dest_space = Heap::old_data_space(); \
+ } else if (space_number == CODE_SPACE) { \
+ dest_space = Heap::code_space(); \
+ } else if (space_number == MAP_SPACE) { \
+ dest_space = Heap::map_space(); \
+ } else if (space_number == CELL_SPACE) { \
+ dest_space = Heap::cell_space(); \
+ } else { \
+ ASSERT(space_number >= LO_SPACE); \
+ dest_space = Heap::lo_space(); \
+ }
+
+
+static const int kUnknownOffsetFromStart = -1;
void Deserializer::ReadChunk(Object** current,
Object** limit,
- int space,
+ int source_space,
Address address) {
while (current < limit) {
int data = source_->Get();
switch (data) {
+#define CASE_STATEMENT(where, how, within, space_number) \
+ case where + how + within + space_number: \
+ ASSERT((where & ~kPointedToMask) == 0); \
+ ASSERT((how & ~kHowToCodeMask) == 0); \
+ ASSERT((within & ~kWhereToPointMask) == 0); \
+ ASSERT((space_number & ~kSpaceMask) == 0);
+
+#define CASE_BODY(where, how, within, space_number_if_any, offset_from_start) \
+ { \
+ bool emit_write_barrier = false; \
+ bool current_was_incremented = false; \
+ int space_number = space_number_if_any == kAnyOldSpace ? \
+ (data & kSpaceMask) : space_number_if_any; \
+ if (where == kNewObject && how == kPlain && within == kStartOfObject) {\
+ ASSIGN_DEST_SPACE(space_number) \
+ ReadObject(space_number, dest_space, current); \
+ emit_write_barrier = \
+ (space_number == NEW_SPACE && source_space != NEW_SPACE); \
+ } else { \
+ Object* new_object = NULL; /* May not be a real Object pointer. */ \
+ if (where == kNewObject) { \
+ ASSIGN_DEST_SPACE(space_number) \
+ ReadObject(space_number, dest_space, &new_object); \
+ } else if (where == kRootArray) { \
+ int root_id = source_->GetInt(); \
+ new_object = Heap::roots_address()[root_id]; \
+ } else if (where == kPartialSnapshotCache) { \
+ int cache_index = source_->GetInt(); \
+ new_object = partial_snapshot_cache_[cache_index]; \
+ } else if (where == kExternalReference) { \
+ int reference_id = source_->GetInt(); \
+ Address address = \
+ external_reference_decoder_->Decode(reference_id); \
+ new_object = reinterpret_cast<Object*>(address); \
+ } else if (where == kBackref) { \
+ emit_write_barrier = \
+ (space_number == NEW_SPACE && source_space != NEW_SPACE); \
+ new_object = GetAddressFromEnd(data & kSpaceMask); \
+ } else { \
+ ASSERT(where == kFromStart); \
+ if (offset_from_start == kUnknownOffsetFromStart) { \
+ emit_write_barrier = \
+ (space_number == NEW_SPACE && source_space != NEW_SPACE); \
+ new_object = GetAddressFromStart(data & kSpaceMask); \
+ } else { \
+ Address object_address = pages_[space_number][0] + \
+ (offset_from_start << kObjectAlignmentBits); \
+ new_object = HeapObject::FromAddress(object_address); \
+ } \
+ } \
+ if (within == kFirstInstruction) { \
+ Code* new_code_object = reinterpret_cast<Code*>(new_object); \
+ new_object = reinterpret_cast<Object*>( \
+ new_code_object->instruction_start()); \
+ } \
+ if (how == kFromCode) { \
+ Address location_of_branch_data = \
+ reinterpret_cast<Address>(current); \
+ Assembler::set_target_at(location_of_branch_data, \
+ reinterpret_cast<Address>(new_object)); \
+ if (within == kFirstInstruction) { \
+ location_of_branch_data += Assembler::kCallTargetSize; \
+ current = reinterpret_cast<Object**>(location_of_branch_data); \
+ current_was_incremented = true; \
+ } \
+ } else { \
+ *current = new_object; \
+ } \
+ } \
+ if (emit_write_barrier) { \
+ Heap::RecordWrite(address, static_cast<int>( \
+ reinterpret_cast<Address>(current) - address)); \
+ } \
+ if (!current_was_incremented) { \
+ current++; /* Increment current if it wasn't done above. */ \
+ } \
+ break; \
+ } \
+
+// This generates a case and a body for each space. The large object spaces are
+// very rare in snapshots so they are grouped in one body.
+#define ONE_PER_SPACE(where, how, within) \
+ CASE_STATEMENT(where, how, within, NEW_SPACE) \
+ CASE_BODY(where, how, within, NEW_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \
+ CASE_BODY(where, how, within, OLD_DATA_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \
+ CASE_BODY(where, how, within, OLD_POINTER_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, CODE_SPACE) \
+ CASE_BODY(where, how, within, CODE_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, CELL_SPACE) \
+ CASE_BODY(where, how, within, CELL_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, MAP_SPACE) \
+ CASE_BODY(where, how, within, MAP_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, kLargeData) \
+ CASE_STATEMENT(where, how, within, kLargeCode) \
+ CASE_STATEMENT(where, how, within, kLargeFixedArray) \
+ CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart)
+
+// This generates a case and a body for the new space (which has to do extra
+// write barrier handling) and handles the other spaces with 8 fall-through
+// cases and one body.
+#define ALL_SPACES(where, how, within) \
+ CASE_STATEMENT(where, how, within, NEW_SPACE) \
+ CASE_BODY(where, how, within, NEW_SPACE, kUnknownOffsetFromStart) \
+ CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \
+ CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \
+ CASE_STATEMENT(where, how, within, CODE_SPACE) \
+ CASE_STATEMENT(where, how, within, CELL_SPACE) \
+ CASE_STATEMENT(where, how, within, MAP_SPACE) \
+ CASE_STATEMENT(where, how, within, kLargeData) \
+ CASE_STATEMENT(where, how, within, kLargeCode) \
+ CASE_STATEMENT(where, how, within, kLargeFixedArray) \
+ CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart)
+
+#define EMIT_COMMON_REFERENCE_PATTERNS(pseudo_space_number, \
+ space_number, \
+ offset_from_start) \
+ CASE_STATEMENT(kFromStart, kPlain, kStartOfObject, pseudo_space_number) \
+ CASE_BODY(kFromStart, kPlain, kStartOfObject, space_number, offset_from_start)
+
+ // We generate 15 cases and bodies that process special tags that combine
+ // the raw data tag and the length into one byte.
#define RAW_CASE(index, size) \
- case RAW_DATA_SERIALIZATION + index: { \
+ case kRawData + index: { \
byte* raw_data_out = reinterpret_cast<byte*>(current); \
source_->CopyRaw(raw_data_out, size); \
current = reinterpret_cast<Object**>(raw_data_out + size); \
}
COMMON_RAW_LENGTHS(RAW_CASE)
#undef RAW_CASE
- case RAW_DATA_SERIALIZATION: {
+
+ // Deserialize a chunk of raw data that doesn't have one of the popular
+ // lengths.
+ case kRawData: {
int size = source_->GetInt();
byte* raw_data_out = reinterpret_cast<byte*>(current);
source_->CopyRaw(raw_data_out, size);
current = reinterpret_cast<Object**>(raw_data_out + size);
break;
}
- case OBJECT_SERIALIZATION + NEW_SPACE: {
- ReadObject(NEW_SPACE, Heap::new_space(), current);
- if (space != NEW_SPACE) {
- Heap::RecordWrite(address, static_cast<int>(
- reinterpret_cast<Address>(current) - address));
- }
- current++;
- break;
- }
- 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(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);
- 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;
- }
- ONE_CASE_PER_SPACE(BACKREF_SERIALIZATION) {
- // Write a backreference to an object we unpacked earlier.
- int backref_space = (data & kSpaceMask);
- if (backref_space == NEW_SPACE && space != NEW_SPACE) {
- Heap::RecordWrite(address, static_cast<int>(
- reinterpret_cast<Address>(current) - address));
- }
- *current++ = GetAddressFromEnd(backref_space);
- break;
- }
- 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, static_cast<int>(
- 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*>(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,
- code_object->instruction_start());
- 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);
- *current++ = reinterpret_cast<Object*>(address);
- break;
- }
- case EXTERNAL_BRANCH_TARGET_SERIALIZATION: {
- int reference_id = source_->GetInt();
- Address address = external_reference_decoder_->Decode(reference_id);
- Address location_of_branch_data = reinterpret_cast<Address>(current);
- Assembler::set_external_target_at(location_of_branch_data, address);
- location_of_branch_data += Assembler::kExternalTargetSize;
- current = reinterpret_cast<Object**>(location_of_branch_data);
- break;
- }
- case START_NEW_PAGE_SERIALIZATION: {
+
+ // Deserialize a new object and write a pointer to it to the current
+ // object.
+ ONE_PER_SPACE(kNewObject, kPlain, kStartOfObject)
+ // Deserialize a new code object and write a pointer to its first
+ // instruction to the current code object.
+ ONE_PER_SPACE(kNewObject, kFromCode, kFirstInstruction)
+ // Find a recently deserialized object using its offset from the current
+ // allocation point and write a pointer to it to the current object.
+ ALL_SPACES(kBackref, kPlain, kStartOfObject)
+ // Find a recently deserialized code object using its offset from the
+ // current allocation point and write a pointer to its first instruction
+ // to the current code object.
+ ALL_SPACES(kBackref, kFromCode, kFirstInstruction)
+ // Find an already deserialized object using its offset from the start
+ // and write a pointer to it to the current object.
+ ALL_SPACES(kFromStart, kPlain, kStartOfObject)
+ // Find an already deserialized code object using its offset from the
+ // start and write a pointer to its first instruction to the current code
+ // object.
+ ALL_SPACES(kFromStart, kFromCode, kFirstInstruction)
+ // Find an already deserialized object at one of the predetermined popular
+ // offsets from the start and write a pointer to it in the current object.
+ COMMON_REFERENCE_PATTERNS(EMIT_COMMON_REFERENCE_PATTERNS)
+ // Find an object in the roots array and write a pointer to it to the
+ // current object.
+ CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0)
+ CASE_BODY(kRootArray, kPlain, kStartOfObject, 0, kUnknownOffsetFromStart)
+ // Find an object in the partial snapshots cache and write a pointer to it
+ // to the current object.
+ CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
+ CASE_BODY(kPartialSnapshotCache,
+ kPlain,
+ kStartOfObject,
+ 0,
+ kUnknownOffsetFromStart)
+ // Find an external reference and write a pointer to it to the current
+ // object.
+ CASE_STATEMENT(kExternalReference, kPlain, kStartOfObject, 0)
+ CASE_BODY(kExternalReference,
+ kPlain,
+ kStartOfObject,
+ 0,
+ kUnknownOffsetFromStart)
+ // Find an external reference and write a pointer to it in the current
+ // code object.
+ CASE_STATEMENT(kExternalReference, kFromCode, kStartOfObject, 0)
+ CASE_BODY(kExternalReference,
+ kFromCode,
+ kStartOfObject,
+ 0,
+ kUnknownOffsetFromStart)
+
+#undef CASE_STATEMENT
+#undef CASE_BODY
+#undef ONE_PER_SPACE
+#undef ALL_SPACES
+#undef EMIT_COMMON_REFERENCE_PATTERNS
+#undef ASSIGN_DEST_SPACE
+
+ case kNewPage: {
int space = source_->Get();
pages_[space].Add(last_object_address_);
if (space == CODE_SPACE) {
}
break;
}
- case NATIVES_STRING_RESOURCE: {
+
+ case kNativesStringResource: {
int index = source_->Get();
Vector<const char> source_vector = Natives::GetScriptSource(index);
NativesExternalStringResource* resource =
*current++ = reinterpret_cast<Object*>(resource);
break;
}
- case ROOT_SERIALIZATION: {
- int root_id = source_->GetInt();
- *current++ = Heap::roots_address()[root_id];
- break;
- }
- case PARTIAL_SNAPSHOT_CACHE_ENTRY: {
- int cache_index = source_->GetInt();
- *current++ = partial_snapshot_cache_[cache_index];
- break;
- }
- case SYNCHRONIZE: {
+
+ case kSynchronize: {
// If we get here then that indicates that you have a mismatch between
// the number of GC roots when serializing and deserializing.
UNREACHABLE();
}
+
default:
UNREACHABLE();
}
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_EQ(SYNCHRONIZE, data);
+ ASSERT_EQ(kSynchronize, data);
do {
int character = source_->Get();
if (character == 0) break;
void Serializer::Synchronize(const char* tag) {
- sink_->Put(SYNCHRONIZE, tag);
+ sink_->Put(kSynchronize, tag);
int character;
do {
character = *tag++;
void Serializer::VisitPointers(Object** start, Object** end) {
for (Object** current = start; current < end; current++) {
if ((*current)->IsSmi()) {
- sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
+ sink_->Put(kRawData, "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);
+ SerializeObject(*current, kPlain, kStartOfObject);
}
}
}
void Serializer::SerializeReferenceToPreviousObject(
int space,
int address,
- ReferenceRepresentation reference_representation) {
+ HowToCode how_to_code,
+ WhereToPoint where_to_point) {
int offset = CurrentAllocationAddress(space) - address;
bool from_start = true;
if (SpaceIsPaged(space)) {
// 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;
- // On some architectures references between code objects are encoded
- // specially (as relative offsets). Such references have their own
- // special tags to simplify the deserializer.
- if (reference_representation == CODE_TARGET_REPRESENTATION) {
- if (from_start) {
- sink_->Put(CODE_REFERENCE_SERIALIZATION + space, "RefCodeSer");
- sink_->PutInt(address, "address");
- } else {
- sink_->Put(CODE_BACKREF_SERIALIZATION + space, "BackRefCodeSer");
- sink_->PutInt(address, "address");
- }
- } else {
- // Regular absolute references.
- CHECK_EQ(TAGGED_REPRESENTATION, reference_representation);
- if (from_start) {
- // There are some common offsets that have their own specialized encoding.
-#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)
+ if (from_start) {
+#define COMMON_REFS_CASE(pseudo_space, actual_space, offset) \
+ if (space == actual_space && address == offset && \
+ how_to_code == kPlain && where_to_point == kStartOfObject) { \
+ sink_->Put(kFromStart + how_to_code + where_to_point + \
+ pseudo_space, "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");
+ { /* NOLINT */
+ sink_->Put(kFromStart + how_to_code + where_to_point + space, "RefSer");
sink_->PutInt(address, "address");
}
+ } else {
+ sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
+ sink_->PutInt(address, "address");
}
}
void StartupSerializer::SerializeObject(
Object* o,
- ReferenceRepresentation reference_representation) {
+ HowToCode how_to_code,
+ WhereToPoint where_to_point) {
CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o);
int address = address_mapper_.MappedTo(heap_object);
SerializeReferenceToPreviousObject(space,
address,
- reference_representation);
+ how_to_code,
+ where_to_point);
} else {
// Object has not yet been serialized. Serialize it here.
ObjectSerializer object_serializer(this,
heap_object,
sink_,
- reference_representation);
+ how_to_code,
+ where_to_point);
object_serializer.Serialize();
}
}
for (int i = partial_snapshot_cache_length_;
i < kPartialSnapshotCacheCapacity;
i++) {
- sink_->Put(ROOT_SERIALIZATION, "RootSerialization");
+ sink_->Put(kRootArray + kPlain + kStartOfObject, "RootSerialization");
sink_->PutInt(Heap::kUndefinedValueRootIndex, "root_index");
}
Heap::IterateWeakRoots(this, VISIT_ALL);
void PartialSerializer::SerializeObject(
Object* o,
- ReferenceRepresentation reference_representation) {
+ HowToCode how_to_code,
+ WhereToPoint where_to_point) {
CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o);
int root_index;
if ((root_index = RootIndex(heap_object)) != kInvalidRootIndex) {
- sink_->Put(ROOT_SERIALIZATION, "RootSerialization");
+ sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
sink_->PutInt(root_index, "root_index");
return;
}
if (ShouldBeInThePartialSnapshotCache(heap_object)) {
int cache_index = PartialSnapshotCacheIndex(heap_object);
- sink_->Put(PARTIAL_SNAPSHOT_CACHE_ENTRY, "PartialSnapshotCache");
+ sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point,
+ "PartialSnapshotCache");
sink_->PutInt(cache_index, "partial_snapshot_cache_index");
return;
}
int address = address_mapper_.MappedTo(heap_object);
SerializeReferenceToPreviousObject(space,
address,
- reference_representation);
+ how_to_code,
+ where_to_point);
} else {
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this,
heap_object,
sink_,
- reference_representation);
+ how_to_code,
+ where_to_point);
serializer.Serialize();
}
}
int space = Serializer::SpaceOfObject(object_);
int size = object_->Size();
- if (reference_representation_ == TAGGED_REPRESENTATION) {
- sink_->Put(OBJECT_SERIALIZATION + space, "ObjectSerialization");
- } else {
- CHECK_EQ(CODE_TARGET_REPRESENTATION, reference_representation_);
- sink_->Put(CODE_OBJECT_SERIALIZATION + space, "ObjectSerialization");
- }
+ sink_->Put(kNewObject + reference_representation_ + space,
+ "ObjectSerialization");
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
LOG(SnapshotPositionEvent(object_->address(), sink_->Position()));
int offset = serializer_->Allocate(space, size, &start_new_page);
serializer_->address_mapper()->AddMapping(object_, offset);
if (start_new_page) {
- sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
+ sink_->Put(kNewPage, "NewPage");
sink_->PutSection(space, "NewPageSpace");
}
// Serialize the map (first word of the object).
- serializer_->SerializeObject(object_->map(), TAGGED_REPRESENTATION);
+ serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject);
// Serialize the rest of the object.
CHECK_EQ(0, bytes_processed_so_far_);
if (current < end) OutputRawData(reinterpret_cast<Address>(current));
while (current < end && !(*current)->IsSmi()) {
- serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
+ serializer_->SerializeObject(*current, kPlain, kStartOfObject);
bytes_processed_so_far_ += kPointerSize;
current++;
}
OutputRawData(references_start);
for (Address* current = start; current < end; current++) {
- sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "ExternalReference");
+ sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef");
int reference_id = serializer_->EncodeExternalReference(*current);
sink_->PutInt(reference_id, "reference id");
}
Address target = rinfo->target_address();
uint32_t encoding = serializer_->EncodeExternalReference(target);
CHECK(target == NULL ? encoding == 0 : encoding != 0);
- sink_->Put(EXTERNAL_BRANCH_TARGET_SERIALIZATION, "ExternalReference");
+ int representation;
+ // Can't use a ternary operator because of gcc.
+ if (rinfo->IsCodedSpecially()) {
+ representation = kStartOfObject + kFromCode;
+ } else {
+ representation = kStartOfObject + kPlain;
+ }
+ sink_->Put(kExternalReference + representation, "ExternalReference");
sink_->PutInt(encoding, "reference id");
bytes_processed_so_far_ += Assembler::kExternalTargetSize;
}
Address target_start = rinfo->target_address_address();
OutputRawData(target_start);
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
- serializer_->SerializeObject(target, CODE_TARGET_REPRESENTATION);
+ serializer_->SerializeObject(target, kFromCode, kFirstInstruction);
bytes_processed_so_far_ += Assembler::kCallTargetSize;
}
typedef v8::String::ExternalAsciiStringResource Resource;
Resource* resource = string->resource();
if (resource == *resource_pointer) {
- sink_->Put(NATIVES_STRING_RESOURCE, "NativesStringResource");
+ sink_->Put(kNativesStringResource, "NativesStringResource");
sink_->PutSection(i, "NativesStringResourceEnd");
bytes_processed_so_far_ += sizeof(resource);
return;
Address base = object_start + bytes_processed_so_far_;
#define RAW_CASE(index, length) \
if (skipped == length) { \
- sink_->PutSection(RAW_DATA_SERIALIZATION + index, "RawDataFixed"); \
+ sink_->PutSection(kRawData + index, "RawDataFixed"); \
} else /* NOLINT */
COMMON_RAW_LENGTHS(RAW_CASE)
#undef RAW_CASE
{ /* NOLINT */
- sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
+ sink_->Put(kRawData, "RawData");
sink_->PutInt(skipped, "length");
}
for (int i = 0; i < skipped; i++) {
};
-// 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)
+// It is very common to have a reference to objects at certain offsets in the
+// heap. These offsets have been determined experimentally. We code
+// references to such objects in a single byte that encodes the way the pointer
+// is written (only plain pointers allowed), the space number and the offset.
+// This only works for objects in the first page of a space. Don't use this for
+// things in newspace since it bypasses the write barrier.
+
+static const int k64 = (sizeof(uintptr_t) - 4) / 4;
+
+#define COMMON_REFERENCE_PATTERNS(f) \
+ f(kNumberOfSpaces, 2, 11 - k64) \
+ f(kNumberOfSpaces + 1, 2, 0) \
+ f(kNumberOfSpaces + 2, 2, 142 - 16 * k64) \
+ f(kNumberOfSpaces + 3, 2, 74 - 15 * k64) \
+ f(kNumberOfSpaces + 4, 2, 5) \
+ f(kNumberOfSpaces + 5, 1, 135) \
+ f(kNumberOfSpaces + 6, 2, 228 - 39 * k64)
#define COMMON_RAW_LENGTHS(f) \
f(1, 1) \
static void SetSnapshotCacheSize(int size);
protected:
- enum DataType {
- 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,
- NATIVES_STRING_RESOURCE = 38,
- ROOT_SERIALIZATION = 39,
- PARTIAL_SNAPSHOT_CACHE_ENTRY = 40,
- // Free: 41-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.
+ // Where the pointed-to object can be found:
+ enum Where {
+ kNewObject = 0, // Object is next in snapshot.
+ // 1-8 One per space.
+ kRootArray = 0x9, // Object is found in root array.
+ kPartialSnapshotCache = 0xa, // Object is in the cache.
+ kExternalReference = 0xb, // Pointer to an external reference.
+ // 0xc-0xf Free.
+ kBackref = 0x10, // Object is described relative to end.
+ // 0x11-0x18 One per space.
+ // 0x19-0x1f Common backref offsets.
+ kFromStart = 0x20, // Object is described relative to start.
+ // 0x21-0x28 One per space.
+ // 0x29-0x2f Free.
+ // 0x30-0x3f Used by misc tags below.
+ kPointedToMask = 0x3f
};
+
+ // How to code the pointer to the object.
+ enum HowToCode {
+ kPlain = 0, // Straight pointer.
+ // What this means depends on the architecture:
+ kFromCode = 0x40, // A pointer inlined in code.
+ kHowToCodeMask = 0x40
+ };
+
+ // Where to point within the object.
+ enum WhereToPoint {
+ kStartOfObject = 0,
+ kFirstInstruction = 0x80,
+ kWhereToPointMask = 0x80
+ };
+
+ // Misc.
+ // Raw data to be copied from the snapshot.
+ static const int kRawData = 0x30;
+ // Some common raw lengths: 0x31-0x3f
+ // A tag emitted at strategic points in the snapshot to delineate sections.
+ // If the deserializer does not find these at the expected moments then it
+ // is an indication that the snapshot and the VM do not fit together.
+ // Examine the build process for architecture, version or configuration
+ // mismatches.
+ static const int kSynchronize = 0x70;
+ // Used for the source code of the natives, which is in the executable, but
+ // is referred to from external strings in the snapshot.
+ static const int kNativesStringResource = 0x71;
+ static const int kNewPage = 0x72;
+ // 0x73-0x7f Free.
+ // 0xb0-0xbf Free.
+ // 0xf0-0xff Free.
+
+
static const int kLargeData = LAST_SPACE;
static const int kLargeCode = kLargeData + 1;
static const int kLargeFixedArray = kLargeCode + 1;
static const int kNumberOfSpaces = kLargeFixedArray + 1;
+ static const int kAnyOldSpace = -1;
// A bitmask for getting the space out of an instruction.
static const int kSpaceMask = 15;
#endif
protected:
- enum ReferenceRepresentation {
- TAGGED_REPRESENTATION, // A tagged object reference.
- CODE_TARGET_REPRESENTATION // A reference to first instruction in target.
- };
static const int kInvalidRootIndex = -1;
virtual int RootIndex(HeapObject* heap_object) = 0;
virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
ObjectSerializer(Serializer* serializer,
Object* o,
SnapshotByteSink* sink,
- ReferenceRepresentation representation)
+ HowToCode how_to_code,
+ WhereToPoint where_to_point)
: serializer_(serializer),
object_(HeapObject::cast(o)),
sink_(sink),
- reference_representation_(representation),
+ reference_representation_(how_to_code + where_to_point),
bytes_processed_so_far_(0) { }
void Serialize();
void VisitPointers(Object** start, Object** end);
Serializer* serializer_;
HeapObject* object_;
SnapshotByteSink* sink_;
- ReferenceRepresentation reference_representation_;
+ int reference_representation_;
int bytes_processed_so_far_;
};
virtual void SerializeObject(Object* o,
- ReferenceRepresentation representation) = 0;
+ HowToCode how_to_code,
+ WhereToPoint where_to_point) = 0;
void SerializeReferenceToPreviousObject(
int space,
int address,
- ReferenceRepresentation reference_representation);
+ HowToCode how_to_code,
+ WhereToPoint where_to_point);
void InitializeAllocators();
// This will return the space for an object. If the object is in large
// object space it may return kLargeCode or kLargeFixedArray in order
// Serialize the objects reachable from a single object pointer.
virtual void Serialize(Object** o);
virtual void SerializeObject(Object* o,
- ReferenceRepresentation representation);
+ HowToCode how_to_code,
+ WhereToPoint where_to_point);
protected:
virtual int RootIndex(HeapObject* o);
// 3) Weak references (eg the symbol table).
virtual void SerializeStrongReferences();
virtual void SerializeObject(Object* o,
- ReferenceRepresentation representation);
+ HowToCode how_to_code,
+ WhereToPoint where_to_point);
void SerializeWeakReferences();
void Serialize() {
SerializeStrongReferences();