Chromium Code Reviews| Index: src/serialize.cc |
| diff --git a/src/serialize.cc b/src/serialize.cc |
| index 8464bc86a9abeee479b8506540dd5a52edbf7559..699448c133324d0f8438874813d456bf231ada52 100644 |
| --- a/src/serialize.cc |
| +++ b/src/serialize.cc |
| @@ -611,12 +611,21 @@ class CodeAddressMap: public CodeEventLogger { |
| }; |
| -Deserializer::Deserializer(SnapshotByteSource* source) |
| +Deserializer::Deserializer(SerializedData* sd) |
| : isolate_(NULL), |
| attached_objects_(NULL), |
| - source_(source), |
| + source_(sd->Payload()), |
| external_reference_decoder_(NULL), |
| deserialized_large_objects_(0) { |
| + // Set reservations. |
| + STATIC_ASSERT(NEW_SPACE == 0); |
| + int current_space = NEW_SPACE; |
| + Vector<const SerializedData::Reservation> res = sd->Reservations(); |
| + for (const auto& r : res) { |
| + reservations_[current_space].Add({r.chunk_size(), NULL, NULL}); |
| + if (r.is_last()) current_space++; |
| + } |
| + DCHECK_EQ(kNumberOfSpaces, current_space); |
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0; |
| } |
| @@ -716,7 +725,7 @@ void Deserializer::DeserializePartial(Isolate* isolate, Object** root, |
| Deserializer::~Deserializer() { |
| // TODO(svenpanne) Re-enable this assertion when v8 initialization is fixed. |
| - // DCHECK(source_->AtEOF()); |
| + // DCHECK(source_.AtEOF()); |
| if (external_reference_decoder_) { |
| delete external_reference_decoder_; |
| external_reference_decoder_ = NULL; |
| @@ -810,12 +819,12 @@ Object* Deserializer::ProcessBackRefInSerializedCode(Object* obj) { |
| void Deserializer::ReadObject(int space_number, Object** write_back) { |
| Address address; |
| HeapObject* obj; |
| - int next_int = source_->GetInt(); |
| + int next_int = source_.GetInt(); |
| bool double_align = false; |
| #ifndef V8_HOST_ARCH_64_BIT |
| double_align = next_int == kDoubleAlignmentSentinel; |
| - if (double_align) next_int = source_->GetInt(); |
| + if (double_align) next_int = source_.GetInt(); |
| #endif |
| DCHECK_NE(kDoubleAlignmentSentinel, next_int); |
| @@ -832,7 +841,7 @@ void Deserializer::ReadObject(int space_number, Object** write_back) { |
| Object** current = reinterpret_cast<Object**>(address); |
| Object** limit = current + (size >> kPointerSizeLog2); |
| if (FLAG_log_snapshot_positions) { |
| - LOG(isolate_, SnapshotPositionEvent(address, source_->position())); |
| + LOG(isolate_, SnapshotPositionEvent(address, source_.position())); |
| } |
| ReadData(current, limit, space_number, address); |
| @@ -870,7 +879,7 @@ Address Deserializer::Allocate(int space_index, int size) { |
| if (space_index == LO_SPACE) { |
| AlwaysAllocateScope scope(isolate_); |
| LargeObjectSpace* lo_space = isolate_->heap()->lo_space(); |
| - Executability exec = static_cast<Executability>(source_->Get()); |
| + Executability exec = static_cast<Executability>(source_.Get()); |
| AllocationResult result = lo_space->AllocateRaw(size, exec); |
| HeapObject* obj = HeapObject::cast(result.ToObjectChecked()); |
| deserialized_large_objects_.Add(obj); |
| @@ -904,7 +913,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| source_space != CODE_SPACE && |
| source_space != OLD_DATA_SPACE); |
| while (current < limit) { |
| - int data = source_->Get(); |
| + int data = source_.Get(); |
| switch (data) { |
| #define CASE_STATEMENT(where, how, within, space_number) \ |
| case where + how + within + space_number: \ |
| @@ -928,18 +937,18 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| if (where == kNewObject) { \ |
| ReadObject(space_number, &new_object); \ |
| } else if (where == kRootArray) { \ |
| - int root_id = source_->GetInt(); \ |
| + int root_id = source_.GetInt(); \ |
| new_object = isolate->heap()->roots_array_start()[root_id]; \ |
| emit_write_barrier = isolate->heap()->InNewSpace(new_object); \ |
| } else if (where == kPartialSnapshotCache) { \ |
| - int cache_index = source_->GetInt(); \ |
| + int cache_index = source_.GetInt(); \ |
| new_object = isolate->serialize_partial_snapshot_cache()[cache_index]; \ |
| emit_write_barrier = isolate->heap()->InNewSpace(new_object); \ |
| } else if (where == kExternalReference) { \ |
| - int skip = source_->GetInt(); \ |
| + int skip = source_.GetInt(); \ |
| current = reinterpret_cast<Object**>( \ |
| reinterpret_cast<Address>(current) + skip); \ |
| - int reference_id = source_->GetInt(); \ |
| + int reference_id = source_.GetInt(); \ |
| Address address = external_reference_decoder_->Decode(reference_id); \ |
| new_object = reinterpret_cast<Object*>(address); \ |
| } else if (where == kBackref) { \ |
| @@ -950,7 +959,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| } \ |
| } else if (where == kBuiltin) { \ |
| DCHECK(deserializing_user_code()); \ |
| - int builtin_id = source_->GetInt(); \ |
| + int builtin_id = source_.GetInt(); \ |
| DCHECK_LE(0, builtin_id); \ |
| DCHECK_LT(builtin_id, Builtins::builtin_count); \ |
| Builtins::Name name = static_cast<Builtins::Name>(builtin_id); \ |
| @@ -958,12 +967,12 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| emit_write_barrier = false; \ |
| } else if (where == kAttachedReference) { \ |
| DCHECK(deserializing_user_code()); \ |
| - int index = source_->GetInt(); \ |
| + int index = source_.GetInt(); \ |
| new_object = *attached_objects_->at(index); \ |
| emit_write_barrier = isolate->heap()->InNewSpace(new_object); \ |
| } else { \ |
| DCHECK(where == kBackrefWithSkip); \ |
| - int skip = source_->GetInt(); \ |
| + int skip = source_.GetInt(); \ |
| current = reinterpret_cast<Object**>( \ |
| reinterpret_cast<Address>(current) + skip); \ |
| emit_write_barrier = (space_number == NEW_SPACE); \ |
| @@ -1070,23 +1079,22 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| // 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) \ |
| - case kRawData + index: { \ |
| - byte* raw_data_out = reinterpret_cast<byte*>(current); \ |
| - source_->CopyRaw(raw_data_out, index * kPointerSize); \ |
| - current = \ |
| - reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \ |
| - break; \ |
| - } |
| +#define RAW_CASE(index) \ |
| + case kRawData + index: { \ |
| + byte* raw_data_out = reinterpret_cast<byte*>(current); \ |
| + source_.CopyRaw(raw_data_out, index* kPointerSize); \ |
| + current = reinterpret_cast<Object**>(raw_data_out + index * kPointerSize); \ |
| + break; \ |
| + } |
| COMMON_RAW_LENGTHS(RAW_CASE) |
| #undef RAW_CASE |
| // Deserialize a chunk of raw data that doesn't have one of the popular |
| // lengths. |
| case kRawData: { |
| - int size = source_->GetInt(); |
| + int size = source_.GetInt(); |
| byte* raw_data_out = reinterpret_cast<byte*>(current); |
| - source_->CopyRaw(raw_data_out, size); |
| + source_.CopyRaw(raw_data_out, size); |
| break; |
| } |
| @@ -1102,7 +1110,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance) |
| SIXTEEN_CASES(kRootArrayConstants + kHasSkipDistance + 16) { |
| int root_id = RootArrayConstantFromByteCode(data); |
| - int skip = source_->GetInt(); |
| + int skip = source_.GetInt(); |
| current = reinterpret_cast<Object**>( |
| reinterpret_cast<intptr_t>(current) + skip); |
| Object* object = isolate->heap()->roots_array_start()[root_id]; |
| @@ -1112,7 +1120,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| } |
| case kRepeat: { |
| - int repeats = source_->GetInt(); |
| + int repeats = source_.GetInt(); |
| Object* object = current[-1]; |
| DCHECK(!isolate->heap()->InNewSpace(object)); |
| for (int i = 0; i < repeats; i++) current[i] = object; |
| @@ -1230,14 +1238,14 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| #undef ALL_SPACES |
| case kSkip: { |
| - int size = source_->GetInt(); |
| + int size = source_.GetInt(); |
| current = reinterpret_cast<Object**>( |
| reinterpret_cast<intptr_t>(current) + size); |
| break; |
| } |
| case kNativesStringResource: { |
| - int index = source_->Get(); |
| + int index = source_.Get(); |
| Vector<const char> source_vector = Natives::GetRawScriptSource(index); |
| NativesExternalStringResource* resource = |
| new NativesExternalStringResource(isolate->bootstrapper(), |
| @@ -1248,7 +1256,7 @@ void Deserializer::ReadData(Object** current, Object** limit, int source_space, |
| } |
| case kNextChunk: { |
| - int space = source_->Get(); |
| + int space = source_.Get(); |
| DCHECK(space < kNumberOfPreallocatedSpaces); |
| int chunk_index = current_chunk_[space]; |
| const Heap::Reservation& reservation = reservations_[space]; |
| @@ -1363,15 +1371,21 @@ void Serializer::VisitPointers(Object** start, Object** end) { |
| } |
| -void Serializer::FinalizeAllocation() { |
| +void Serializer::EncodeReservations( |
| + List<SerializedData::Reservation>* out) const { |
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { |
| - // Complete the last pending chunk and if there are no completed chunks, |
| - // make sure there is at least one empty chunk. |
| + for (int j = 0; j < completed_chunks_[i].length(); j++) { |
| + out->Add(SerializedData::Reservation(completed_chunks_[i][j])); |
| + } |
| + |
| if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 0) { |
| - completed_chunks_[i].Add(pending_chunk_[i]); |
| - pending_chunk_[i] = 0; |
| + out->Add(SerializedData::Reservation(pending_chunk_[i])); |
| } |
| + out->last().mark_as_last(); |
| } |
| + |
| + out->Add(SerializedData::Reservation(large_objects_total_size_)); |
| + out->last().mark_as_last(); |
| } |
| @@ -1663,7 +1677,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() { |
| } |
| // Serialize string content. |
| - sink_->PutRaw(const_cast<byte*>(resource), content_size, "StringContent"); |
| + sink_->PutRaw(resource, content_size, "StringContent"); |
| // Since the allocation size is rounded up to object alignment, there |
| // maybe left-over bytes that need to be padded. |
| @@ -1960,6 +1974,7 @@ BackReference Serializer::Allocate(AllocationSpace space, int size) { |
| sink_->Put(kNextChunk, "move to next chunk"); |
| sink_->Put(space, "space of next chunk"); |
| completed_chunks_[space].Add(pending_chunk_[space]); |
| + DCHECK_LE(completed_chunks_[space].length(), BackReference::kMaxChunkIndex); |
| pending_chunk_[space] = 0; |
| new_chunk_size = size; |
| } |
| @@ -2004,16 +2019,8 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, |
| Object** location = Handle<Object>::cast(info).location(); |
| cs.VisitPointer(location); |
| cs.Pad(); |
| - cs.FinalizeAllocation(); |
| - |
| - for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { |
| - // Fail if any chunk index exceeds the limit. |
| - if (cs.FinalAllocationChunks(i).length() > BackReference::kMaxChunkIndex) { |
| - return NULL; |
| - } |
| - } |
| - SerializedCodeData data(sink.data(), &cs); |
| + SerializedCodeData data(sink.data(), cs); |
| ScriptData* script_data = data.GetScriptData(); |
| if (FLAG_profile_deserialization) { |
| @@ -2240,23 +2247,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( |
| DCHECK(cached_data->rejected()); |
| return MaybeHandle<SharedFunctionInfo>(); |
| } |
| - SnapshotByteSource payload(scd->Payload(), scd->PayloadLength()); |
| - Deserializer deserializer(&payload); |
| // Eagerly expand string table to avoid allocations during deserialization. |
| StringTable::EnsureCapacityForDeserialization( |
| isolate, scd->NumInternalizedStrings()); |
| - // Set reservations. |
| - STATIC_ASSERT(NEW_SPACE == 0); |
| - int current_space = NEW_SPACE; |
| - Vector<const SerializedCodeData::Reservation> res = scd->Reservations(); |
| - for (const auto& r : res) { |
| - deserializer.AddReservation(current_space, r.chunk_size()); |
| - if (r.is_last_chunk()) current_space++; |
| - } |
| - DCHECK_EQ(kNumberOfSpaces, current_space); |
| - |
| // Prepare and register list of attached objects. |
| Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys(); |
| Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New( |
| @@ -2266,6 +2261,8 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( |
| attached_objects[i + kCodeStubsBaseIndex] = |
| CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked(); |
| } |
| + |
| + Deserializer deserializer(scd.get()); |
| deserializer.SetAttachedObjects(&attached_objects); |
| // Deserialize. |
| @@ -2301,23 +2298,64 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( |
| } |
| +SnapshotData::SnapshotData(const SnapshotByteSink& sink, |
| + const Serializer& ser) { |
| + DisallowHeapAllocation no_gc; |
| + List<Reservation> reservations; |
| + ser.EncodeReservations(&reservations); |
| + const List<byte>& payload = sink.data(); |
| + |
| + // Calculate sizes. |
| + int reservation_size = reservations.length() * kInt32Size; |
| + size_ = kHeaderSize + reservation_size + payload.length(); |
| + |
| + // Allocate backing store and create result data. |
| + data_ = NewArray<byte>(size_); |
|
vogelheim
2014/12/03 18:49:25
Related to the comment in serialize.h:
I was tryi
Yang
2014/12/04 08:51:43
I moved allocation into a helper method in the par
|
| + DCHECK(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment)); |
| + |
| + // Set header values. |
| + SetHeaderValue(kCheckSumOffset, Version::Hash()); |
| + SetHeaderValue(kReservationsOffset, reservations.length()); |
| + SetHeaderValue(kPayloadLengthOffset, payload.length()); |
| + |
| + // Copy reservation chunk sizes. |
| + CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()), |
| + reservation_size); |
| + |
| + // Copy serialized data. |
| + CopyBytes(data_ + kHeaderSize + reservation_size, payload.begin(), |
| + static_cast<size_t>(payload.length())); |
| +} |
| + |
| + |
| +bool SnapshotData::IsSane() { |
| + return GetHeaderValue(kCheckSumOffset) == Version::Hash(); |
| +} |
| + |
| + |
| +Vector<const SerializedData::Reservation> SnapshotData::Reservations() const { |
| + return Vector<const Reservation>( |
| + reinterpret_cast<const Reservation*>(data_ + kHeaderSize), |
| + GetHeaderValue(kReservationsOffset)); |
| +} |
| + |
| + |
| +Vector<const byte> SnapshotData::Payload() const { |
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; |
| + const byte* payload = data_ + kHeaderSize + reservations_size; |
| + int length = GetHeaderValue(kPayloadLengthOffset); |
| + DCHECK_EQ(data_ + size_, payload + length); |
| + return Vector<const byte>(payload, length); |
| +} |
| + |
| + |
| SerializedCodeData::SerializedCodeData(const List<byte>& payload, |
| - CodeSerializer* cs) |
| - : data_(NULL), size_(0), owns_script_data_(true) { |
| + const CodeSerializer& cs) { |
| DisallowHeapAllocation no_gc; |
| - List<uint32_t>* stub_keys = cs->stub_keys(); |
| + const List<uint32_t>* stub_keys = cs.stub_keys(); |
| - // Gather reservation chunk sizes. |
| - List<uint32_t> reservations(SerializerDeserializer::kNumberOfSpaces); |
| - STATIC_ASSERT(NEW_SPACE == 0); |
| - for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) { |
| - Vector<const uint32_t> chunks = cs->FinalAllocationChunks(i); |
| - for (int j = 0; j < chunks.length(); j++) { |
| - uint32_t chunk = ChunkSizeBits::encode(chunks[j]) | |
| - IsLastChunkBits::encode(j == chunks.length() - 1); |
| - reservations.Add(chunk); |
| - } |
| - } |
| + List<Reservation> reservations; |
| + cs.EncodeReservations(&reservations); |
| // Calculate sizes. |
| int reservation_size = reservations.length() * kInt32Size; |
| @@ -2330,8 +2368,8 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload, |
| DCHECK(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment)); |
| // Set header values. |
| - SetHeaderValue(kCheckSumOffset, CheckSum(cs->source())); |
| - SetHeaderValue(kNumInternalizedStringsOffset, cs->num_internalized_strings()); |
| + SetHeaderValue(kCheckSumOffset, CheckSum(cs.source())); |
| + SetHeaderValue(kNumInternalizedStringsOffset, cs.num_internalized_strings()); |
| SetHeaderValue(kReservationsOffset, reservations.length()); |
| SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); |
| SetHeaderValue(kPayloadLengthOffset, payload.length()); |
| @@ -2352,11 +2390,52 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload, |
| bool SerializedCodeData::IsSane(String* source) { |
| return GetHeaderValue(kCheckSumOffset) == CheckSum(source) && |
| - PayloadLength() >= SharedFunctionInfo::kSize; |
| + Payload().length() >= SharedFunctionInfo::kSize; |
| } |
| int SerializedCodeData::CheckSum(String* string) { |
| return Version::Hash() ^ string->length(); |
| } |
| + |
| + |
| +// Return ScriptData object and relinquish ownership over it to the caller. |
| +ScriptData* SerializedCodeData::GetScriptData() { |
| + DCHECK(owns_data_); |
| + ScriptData* result = new ScriptData(data_, size_); |
| + result->AcquireDataOwnership(); |
| + owns_data_ = false; |
| + return result; |
|
vogelheim
2014/12/03 18:49:25
Is this expected to the last method call on a part
Yang
2014/12/04 08:51:43
Done.
|
| +} |
| + |
| + |
| +Vector<const SerializedData::Reservation> SerializedCodeData::Reservations() |
| + const { |
| + return Vector<const Reservation>( |
| + reinterpret_cast<const Reservation*>(data_ + kHeaderSize), |
| + GetHeaderValue(kReservationsOffset)); |
| +} |
| + |
| + |
| +Vector<const byte> SerializedCodeData::Payload() const { |
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; |
| + int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size; |
| + const byte* payload = |
| + data_ + kHeaderSize + reservations_size + code_stubs_size; |
| + int length = GetHeaderValue(kPayloadLengthOffset); |
| + DCHECK_EQ(data_ + size_, payload + length); |
| + return Vector<const byte>(payload, length); |
| +} |
| + |
| + |
| +int SerializedCodeData::NumInternalizedStrings() const { |
| + return GetHeaderValue(kNumInternalizedStringsOffset); |
| +} |
| + |
| +Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const { |
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; |
| + const byte* start = data_ + kHeaderSize + reservations_size; |
| + return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start), |
| + GetHeaderValue(kNumCodeStubKeysOffset)); |
| +} |
| } } // namespace v8::internal |