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 |