From 52cef3f0e10a3fc1e38882d15ed9d2597786b760 Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Thu, 20 May 2010 13:54:31 +0000 Subject: [PATCH] Orthogonalize the byte codes used for the snapshot so that the issue of how the pointee is found and how the pointer is encoded are separated out. This will make it simpler to support various pointers from and to code in the future. Review URL: http://codereview.chromium.org/2069013 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4687 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/assembler-arm.cc | 9 + src/assembler.h | 5 + src/ia32/assembler-ia32.cc | 9 + src/serialize.cc | 484 +++++++++++++++++++++++++-------------------- src/serialize.h | 129 +++++++----- src/x64/assembler-x64.cc | 10 + 6 files changed, 386 insertions(+), 260 deletions(-) diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index da32ce9..41a1e5b 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -108,6 +108,15 @@ void CpuFeatures::Probe() { const int RelocInfo::kApplyMask = 0; +bool RelocInfo::IsCodedSpecially() { + // The deserializer needs to know whether a pointer is specially coded. Being + // specially coded on ARM means that it is a movw/movt instruction. We don't + // generate those yet. + return false; +} + + + void RelocInfo::PatchCode(byte* instructions, int instruction_count) { // Patch the code at the current address with the supplied instructions. Instr* pc = reinterpret_cast(pc_); diff --git a/src/assembler.h b/src/assembler.h index 90314e8..f2a6c8b 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -184,6 +184,11 @@ class RelocInfo BASE_EMBEDDED { // Apply a relocation by delta bytes INLINE(void apply(intptr_t delta)); + // Is the pointer this relocation info refers to coded like a plain pointer + // or is it strange in some way (eg relative or patched into a series of + // instructions). + bool IsCodedSpecially(); + // Read/modify the code target in the branch/call instruction // this relocation applies to; // can only be called if IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index a452793..4690c67 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -162,6 +162,15 @@ const int RelocInfo::kApplyMask = 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE; +bool RelocInfo::IsCodedSpecially() { + // The deserializer needs to know whether a pointer is specially coded. Being + // specially coded on IA32 means that it is a relative address, as used by + // branch instructions. These are also the ones that need changing when a + // code object moves. + return (1 << rmode_) & kApplyMask; +} + + void RelocInfo::PatchCode(byte* instructions, int instruction_count) { // Patch the code at the current address with the supplied instructions. for (int i = 0; i < instruction_count; i++) { diff --git a/src/serialize.cc b/src/serialize.cc index dcaa101..9dece32 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -660,27 +660,164 @@ void Deserializer::ReadObject(int space_number, } -#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(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(new_object); \ + new_object = reinterpret_cast( \ + new_code_object->instruction_start()); \ + } \ + if (how == kFromCode) { \ + Address location_of_branch_data = \ + reinterpret_cast
(current); \ + Assembler::set_target_at(location_of_branch_data, \ + reinterpret_cast
(new_object)); \ + if (within == kFirstInstruction) { \ + location_of_branch_data += Assembler::kCallTargetSize; \ + current = reinterpret_cast(location_of_branch_data); \ + current_was_incremented = true; \ + } \ + } else { \ + *current = new_object; \ + } \ + } \ + if (emit_write_barrier) { \ + Heap::RecordWrite(address, static_cast( \ + reinterpret_cast
(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(current); \ source_->CopyRaw(raw_data_out, size); \ current = reinterpret_cast(raw_data_out + size); \ @@ -688,144 +825,77 @@ void Deserializer::ReadChunk(Object** current, } 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(current); source_->CopyRaw(raw_data_out, size); current = reinterpret_cast(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( - reinterpret_cast
(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(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(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); - 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; - } - 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( - reinterpret_cast
(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( - 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(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, - code_object->instruction_start()); - 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); - *current++ = reinterpret_cast(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
(current); - Assembler::set_external_target_at(location_of_branch_data, address); - location_of_branch_data += Assembler::kExternalTargetSize; - current = reinterpret_cast(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) { @@ -833,7 +903,8 @@ void Deserializer::ReadChunk(Object** current, } break; } - case NATIVES_STRING_RESOURCE: { + + case kNativesStringResource: { int index = source_->Get(); Vector source_vector = Natives::GetScriptSource(index); NativesExternalStringResource* resource = @@ -841,21 +912,13 @@ void Deserializer::ReadChunk(Object** current, *current++ = reinterpret_cast(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(); } @@ -880,7 +943,7 @@ void Deserializer::Synchronize(const char* tag) { int data = source_->Get(); // If this assert fails then that indicates that you have a mismatch between // the number of GC roots when serializing and deserializing. - ASSERT_EQ(SYNCHRONIZE, data); + ASSERT_EQ(kSynchronize, data); do { int character = source_->Get(); if (character == 0) break; @@ -895,7 +958,7 @@ void Deserializer::Synchronize(const char* tag) { void Serializer::Synchronize(const char* tag) { - sink_->Put(SYNCHRONIZE, tag); + sink_->Put(kSynchronize, tag); int character; do { character = *tag++; @@ -957,13 +1020,13 @@ void PartialSerializer::Serialize(Object** object) { 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(current)[i], "Byte"); } } else { - SerializeObject(*current, TAGGED_REPRESENTATION); + SerializeObject(*current, kPlain, kStartOfObject); } } } @@ -1033,7 +1096,8 @@ int PartialSerializer::RootIndex(HeapObject* heap_object) { 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)) { @@ -1054,43 +1118,30 @@ void Serializer::SerializeReferenceToPreviousObject( // 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); @@ -1099,13 +1150,15 @@ void StartupSerializer::SerializeObject( 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(); } } @@ -1115,7 +1168,7 @@ void StartupSerializer::SerializeWeakReferences() { 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); @@ -1124,20 +1177,22 @@ void StartupSerializer::SerializeWeakReferences() { 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; } @@ -1155,13 +1210,15 @@ void PartialSerializer::SerializeObject( 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(); } } @@ -1171,12 +1228,8 @@ void Serializer::ObjectSerializer::Serialize() { int space = Serializer::SpaceOfObject(object_); int size = object_->Size(); - if (reference_representation_ == TAGGED_REPRESENTATION) { - sink_->Put(OBJECT_SERIALIZATION + space, "ObjectSerialization"); - } else { - 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())); @@ -1186,12 +1239,12 @@ void Serializer::ObjectSerializer::Serialize() { 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_); @@ -1209,7 +1262,7 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start, if (current < end) OutputRawData(reinterpret_cast
(current)); while (current < end && !(*current)->IsSmi()) { - serializer_->SerializeObject(*current, TAGGED_REPRESENTATION); + serializer_->SerializeObject(*current, kPlain, kStartOfObject); bytes_processed_so_far_ += kPointerSize; current++; } @@ -1223,7 +1276,7 @@ void Serializer::ObjectSerializer::VisitExternalReferences(Address* start, 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"); } @@ -1237,7 +1290,14 @@ void Serializer::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, "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; } @@ -1248,7 +1308,7 @@ void Serializer::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) { 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; } @@ -1264,7 +1324,7 @@ void Serializer::ObjectSerializer::VisitExternalAsciiString( 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; @@ -1288,12 +1348,12 @@ void Serializer::ObjectSerializer::OutputRawData(Address up_to) { 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++) { diff --git a/src/serialize.h b/src/serialize.h index 279bc58..e95de74 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -137,17 +137,23 @@ class SnapshotByteSource { }; -// 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) \ @@ -175,37 +181,63 @@ class SerializerDeserializer: public ObjectVisitor { 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; @@ -396,10 +428,6 @@ class Serializer : public SerializerDeserializer { #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; @@ -409,11 +437,12 @@ class Serializer : public SerializerDeserializer { 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); @@ -435,16 +464,18 @@ class Serializer : public SerializerDeserializer { 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 @@ -492,7 +523,8 @@ class PartialSerializer : public Serializer { // 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); @@ -528,7 +560,8 @@ class StartupSerializer : public Serializer { // 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(); diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 7df89d8..3d03949 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -2800,6 +2800,16 @@ const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask | 1 << RelocInfo::INTERNAL_REFERENCE | 1 << RelocInfo::JS_RETURN; + +bool RelocInfo::IsCodedSpecially() { + // The deserializer needs to know whether a pointer is specially coded. Being + // specially coded on x64 means that it is a relative 32 bit address, as used + // by branch instructions. + return (1 << rmode_) & kApplyMask; +} + + + } } // namespace v8::internal #endif // V8_TARGET_ARCH_X64 -- 2.7.4