| Index: src/serialize.cc
|
| diff --git a/src/serialize.cc b/src/serialize.cc
|
| index f0bd68e659bc1a0377011bce6b544e2dcdc61ed5..e6aae7fe8de90260da6f3e1e1463ab3544de8cea 100644
|
| --- a/src/serialize.cc
|
| +++ b/src/serialize.cc
|
| @@ -611,16 +611,12 @@
|
| };
|
|
|
|
|
| -void Deserializer::DecodeReservation(
|
| - Vector<const SerializedData::Reservation> res) {
|
| - DCHECK_EQ(0, reservations_[NEW_SPACE].length());
|
| - STATIC_ASSERT(NEW_SPACE == 0);
|
| - int current_space = NEW_SPACE;
|
| - 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);
|
| +Deserializer::Deserializer(SnapshotByteSource* source)
|
| + : isolate_(NULL),
|
| + attached_objects_(NULL),
|
| + source_(source),
|
| + external_reference_decoder_(NULL),
|
| + deserialized_large_objects_(0) {
|
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) current_chunk_[i] = 0;
|
| }
|
|
|
| @@ -720,7 +716,7 @@
|
|
|
| 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;
|
| @@ -801,10 +797,10 @@
|
| HeapObject* Deserializer::GetBackReferencedObject(int space) {
|
| HeapObject* obj;
|
| if (space == LO_SPACE) {
|
| - uint32_t index = source_.GetInt();
|
| + uint32_t index = source_->GetInt();
|
| obj = deserialized_large_objects_[index];
|
| } else {
|
| - BackReference back_reference(source_.GetInt());
|
| + BackReference back_reference(source_->GetInt());
|
| DCHECK(space < kNumberOfPreallocatedSpaces);
|
| uint32_t chunk_index = back_reference.chunk_index();
|
| DCHECK_LE(chunk_index, current_chunk_[space]);
|
| @@ -828,12 +824,12 @@
|
| 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);
|
| @@ -850,7 +846,7 @@
|
| 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);
|
|
|
| @@ -888,7 +884,7 @@
|
| 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);
|
| @@ -922,7 +918,7 @@
|
| source_space != CODE_SPACE &&
|
| source_space != OLD_DATA_SPACE);
|
| while (current < limit) {
|
| - byte data = source_.Get();
|
| + byte data = source_->Get();
|
| switch (data) {
|
| #define CASE_STATEMENT(where, how, within, space_number) \
|
| case where + how + within + space_number: \
|
| @@ -946,18 +942,18 @@
|
| 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) { \
|
| @@ -965,7 +961,7 @@
|
| new_object = GetBackReferencedObject(data & kSpaceMask); \
|
| } 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); \
|
| @@ -973,12 +969,12 @@
|
| 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); \
|
| @@ -1082,22 +1078,23 @@
|
|
|
| // 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;
|
| }
|
|
|
| @@ -1113,7 +1110,7 @@
|
| 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];
|
| @@ -1123,7 +1120,7 @@
|
| }
|
|
|
| case kVariableRepeat: {
|
| - 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;
|
| @@ -1243,14 +1240,14 @@
|
| #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(),
|
| @@ -1261,7 +1258,7 @@
|
| }
|
|
|
| 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];
|
| @@ -1276,7 +1273,7 @@
|
|
|
| FOUR_CASES(kHotObjectWithSkip)
|
| FOUR_CASES(kHotObjectWithSkip + 4) {
|
| - int skip = source_.GetInt();
|
| + int skip = source_->GetInt();
|
| current = reinterpret_cast<Object**>(
|
| reinterpret_cast<Address>(current) + skip);
|
| // Fall through.
|
| @@ -1397,21 +1394,15 @@
|
| }
|
|
|
|
|
| -void Serializer::EncodeReservations(
|
| - List<SerializedData::Reservation>* out) const {
|
| +void Serializer::FinalizeAllocation() {
|
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
|
| - for (int j = 0; j < completed_chunks_[i].length(); j++) {
|
| - out->Add(SerializedData::Reservation(completed_chunks_[i][j]));
|
| - }
|
| -
|
| + // Complete the last pending chunk and if there are no completed chunks,
|
| + // make sure there is at least one empty chunk.
|
| if (pending_chunk_[i] > 0 || completed_chunks_[i].length() == 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();
|
| + completed_chunks_[i].Add(pending_chunk_[i]);
|
| + pending_chunk_[i] = 0;
|
| + }
|
| + }
|
| }
|
|
|
|
|
| @@ -1727,7 +1718,7 @@
|
| }
|
|
|
| // Serialize string content.
|
| - sink_->PutRaw(resource, content_size, "StringContent");
|
| + sink_->PutRaw(const_cast<byte*>(resource), content_size, "StringContent");
|
|
|
| // Since the allocation size is rounded up to object alignment, there
|
| // maybe left-over bytes that need to be padded.
|
| @@ -2030,7 +2021,6 @@
|
| sink_->Put(kNextChunk, "NextChunk");
|
| sink_->Put(space, "NextChunkSpace");
|
| completed_chunks_[space].Add(pending_chunk_[space]);
|
| - DCHECK_LE(completed_chunks_[space].length(), BackReference::kMaxChunkIndex);
|
| pending_chunk_[space] = 0;
|
| new_chunk_size = size;
|
| }
|
| @@ -2075,8 +2065,16 @@
|
| Object** location = Handle<Object>::cast(info).location();
|
| cs.VisitPointer(location);
|
| cs.Pad();
|
| -
|
| - SerializedCodeData data(sink.data(), cs);
|
| + 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);
|
| ScriptData* script_data = data.GetScriptData();
|
|
|
| if (FLAG_profile_deserialization) {
|
| @@ -2277,10 +2275,22 @@
|
| 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();
|
| @@ -2291,8 +2301,6 @@
|
| attached_objects[i + kCodeStubsBaseIndex] =
|
| CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
|
| }
|
| -
|
| - Deserializer deserializer(scd.get());
|
| deserializer.SetAttachedObjects(&attached_objects);
|
|
|
| // Deserialize.
|
| @@ -2328,152 +2336,65 @@
|
| }
|
|
|
|
|
| -void SerializedData::AllocateData(int size) {
|
| - DCHECK(!owns_data_);
|
| - data_ = NewArray<byte>(size);
|
| - size_ = size;
|
| - owns_data_ = true;
|
| - DCHECK(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment));
|
| -}
|
| -
|
| -
|
| -SnapshotData::SnapshotData(const SnapshotByteSink& sink,
|
| - const Serializer& ser) {
|
| +SerializedCodeData::SerializedCodeData(const List<byte>& payload,
|
| + CodeSerializer* cs)
|
| + : script_data_(NULL), owns_script_data_(true) {
|
| DisallowHeapAllocation no_gc;
|
| - List<Reservation> reservations;
|
| - ser.EncodeReservations(&reservations);
|
| - const List<byte>& payload = sink.data();
|
| -
|
| - // Calculate sizes.
|
| - int reservation_size = reservations.length() * kInt32Size;
|
| - int size = kHeaderSize + reservation_size + payload.length();
|
| -
|
| - // Allocate backing store and create result data.
|
| - AllocateData(size);
|
| -
|
| - // 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,
|
| - const CodeSerializer& cs) {
|
| - DisallowHeapAllocation no_gc;
|
| - const List<uint32_t>* stub_keys = cs.stub_keys();
|
| -
|
| - List<Reservation> reservations;
|
| - cs.EncodeReservations(&reservations);
|
| + 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);
|
| + }
|
| + }
|
|
|
| // Calculate sizes.
|
| int reservation_size = reservations.length() * kInt32Size;
|
| int num_stub_keys = stub_keys->length();
|
| int stub_keys_size = stub_keys->length() * kInt32Size;
|
| - int size = kHeaderSize + reservation_size + stub_keys_size + payload.length();
|
| + int data_length =
|
| + kHeaderSize + reservation_size + stub_keys_size + payload.length();
|
|
|
| // Allocate backing store and create result data.
|
| - AllocateData(size);
|
| + byte* data = NewArray<byte>(data_length);
|
| + DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
|
| + script_data_ = new ScriptData(data, data_length);
|
| + script_data_->AcquireDataOwnership();
|
|
|
| // 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());
|
|
|
| // Copy reservation chunk sizes.
|
| - CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
|
| + CopyBytes(data + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
|
| reservation_size);
|
|
|
| // Copy code stub keys.
|
| - CopyBytes(data_ + kHeaderSize + reservation_size,
|
| + CopyBytes(data + kHeaderSize + reservation_size,
|
| reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size);
|
|
|
| // Copy serialized data.
|
| - CopyBytes(data_ + kHeaderSize + reservation_size + stub_keys_size,
|
| + CopyBytes(data + kHeaderSize + reservation_size + stub_keys_size,
|
| payload.begin(), static_cast<size_t>(payload.length()));
|
| }
|
|
|
|
|
| bool SerializedCodeData::IsSane(String* source) {
|
| return GetHeaderValue(kCheckSumOffset) == CheckSum(source) &&
|
| - Payload().length() >= SharedFunctionInfo::kSize;
|
| + PayloadLength() >= 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;
|
| - data_ = NULL;
|
| - return result;
|
| -}
|
| -
|
| -
|
| -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
|
|
|