Chromium Code Reviews| Index: src/serialize.h |
| diff --git a/src/serialize.h b/src/serialize.h |
| index 6fa7a341e7a2de1589a9e886f56caec03a6efd65..ff8ff148ec1fed535f094e98262b224e7b28bbb5 100644 |
| --- a/src/serialize.h |
| +++ b/src/serialize.h |
| @@ -152,6 +152,11 @@ class SerializerDeserializer: public ObjectVisitor { |
| static const int kNumberOfPreallocatedSpaces = LO_SPACE; |
| static const int kNumberOfSpaces = INVALID_SPACE; |
| + // To encode object for back-references. |
| + class OffsetBits : public BitField<uint32_t, 0, kPageSizeBits> {}; |
| + class ChunkIndexBits |
| + : public BitField<uint32_t, kPageSizeBits, 32 - kPageSizeBits> {}; |
| + |
| protected: |
| // Where the pointed-to object can be found: |
| enum Where { |
| @@ -248,13 +253,18 @@ class Deserializer: public SerializerDeserializer { |
| // Deserialize the snapshot into an empty heap. |
| void Deserialize(Isolate* isolate); |
| + enum OnOOM { FATAL_ON_OOM, NULL_ON_OOM }; |
| + |
| // Deserialize a single object and the objects reachable from it. |
| - void DeserializePartial(Isolate* isolate, Object** root); |
| + // We may want to abort and gracefully even if deserialization fails. |
|
mvstanton
2014/10/15 12:30:56
Remove the and to get "...abort gracefully..."
|
| + void DeserializePartial(Isolate* isolate, Object** root, |
| + OnOOM on_oom = FATAL_ON_OOM); |
| - void set_reservation(int space_number, int reservation) { |
| - DCHECK(space_number >= 0); |
| - DCHECK(space_number < kNumberOfSpaces); |
| - reservations_[space_number] = reservation; |
| + void AddReservation(int space, uint32_t chunk) { |
| + DCHECK(space >= 0); |
| + DCHECK(space < kNumberOfSpaces); |
| + DCHECK(space == LO_SPACE || chunk < Page::kMaxRegularHeapObjectSize); |
| + reservations_[space].Add({chunk, NULL, NULL}); |
| } |
| void FlushICacheForNewCodeObjects(); |
| @@ -274,6 +284,8 @@ class Deserializer: public SerializerDeserializer { |
| UNREACHABLE(); |
| } |
| + bool ReserveSpace(); |
| + |
| // Allocation sites are present in the snapshot, and must be linked into |
| // a list at deserialization time. |
| void RelinkAllocationSite(AllocationSite* site); |
| @@ -283,8 +295,8 @@ class Deserializer: public SerializerDeserializer { |
| // of the object we are writing into, or NULL if we are not writing into an |
| // object, i.e. if we are writing a series of tagged values that are not on |
| // the heap. |
| - void ReadChunk( |
| - Object** start, Object** end, int space, Address object_address); |
| + void ReadData(Object** start, Object** end, int space, |
| + Address object_address); |
| void ReadObject(int space_number, Object** write_back); |
| Address Allocate(int space_index, int size); |
| @@ -293,13 +305,20 @@ class Deserializer: public SerializerDeserializer { |
| Object* ProcessBackRefInSerializedCode(Object* obj); |
| // This returns the address of an object that has been described in the |
| - // snapshot as being offset bytes back in a particular space. |
| - HeapObject* GetAddressFromEnd(int space) { |
| - int offset = source_->GetInt(); |
| - if (space == LO_SPACE) return deserialized_large_objects_[offset]; |
| - DCHECK(space < kNumberOfPreallocatedSpaces); |
| - offset <<= kObjectAlignmentBits; |
| - return HeapObject::FromAddress(high_water_[space] - offset); |
| + // snapshot by chunk index and offset. |
| + HeapObject* GetBackReferencedObject(int space) { |
| + if (space == LO_SPACE) { |
| + uint32_t index = source_->GetInt(); |
| + return deserialized_large_objects_[index]; |
| + } else { |
| + uint32_t allocation = source_->GetInt() << kObjectAlignmentBits; |
| + DCHECK(space < kNumberOfPreallocatedSpaces); |
| + uint32_t chunk_index = ChunkIndexBits::decode(allocation); |
| + uint32_t offset = OffsetBits::decode(allocation); |
| + DCHECK_LE(chunk_index, current_chunk_[space]); |
| + return HeapObject::FromAddress(reservations_[space][chunk_index].start + |
| + offset); |
| + } |
| } |
| // Cached current isolate. |
| @@ -309,13 +328,14 @@ class Deserializer: public SerializerDeserializer { |
| Vector<Handle<Object> >* attached_objects_; |
| SnapshotByteSource* source_; |
| - // This is the address of the next object that will be allocated in each |
| - // space. It is used to calculate the addresses of back-references. |
| + // The address of the next object that will be allocated in each space. |
| + // Each space has a number of chunks reserved by the GC, with each chunk |
| + // fitting into a page. Deserialized objects are allocated into the |
| + // current chunk of the target space by bumping up high water mark. |
| + Heap::Reservation reservations_[kNumberOfSpaces]; |
| + uint32_t current_chunk_[kNumberOfPreallocatedSpaces]; |
| Address high_water_[kNumberOfPreallocatedSpaces]; |
| - int reservations_[kNumberOfSpaces]; |
| - static const intptr_t kUninitializedReservation = -1; |
| - |
| ExternalReferenceDecoder* external_reference_decoder_; |
| List<HeapObject*> deserialized_large_objects_; |
| @@ -380,11 +400,13 @@ class Serializer : public SerializerDeserializer { |
| Serializer(Isolate* isolate, SnapshotByteSink* sink); |
| ~Serializer(); |
| void VisitPointers(Object** start, Object** end); |
| - // You can call this after serialization to find out how much space was used |
| - // in each space. |
| - int CurrentAllocationAddress(int space) const { |
| - DCHECK(space < kNumberOfSpaces); |
| - return fullness_[space]; |
| + |
| + void FinalizeAllocation(); |
| + |
| + Vector<const uint32_t> FinalAllocationChunks(int space) const { |
| + DCHECK_EQ(1, completed_chunks_[LO_SPACE].length()); // Already finalized. |
| + DCHECK_EQ(0, pending_chunk_[space]); // No pending chunks. |
| + return completed_chunks_[space].ToConstVector(); |
| } |
| Isolate* isolate() const { return isolate_; } |
| @@ -470,8 +492,8 @@ class Serializer : public SerializerDeserializer { |
| void InitializeAllocators(); |
| // This will return the space for an object. |
| static int SpaceOfObject(HeapObject* object); |
| - int AllocateLargeObject(int size); |
| - int Allocate(int space, int size); |
| + uint32_t AllocateLargeObject(int size); |
| + uint32_t Allocate(int space, int size); |
| int EncodeExternalReference(Address addr) { |
| return external_reference_encoder_->Encode(addr); |
| } |
| @@ -483,9 +505,14 @@ class Serializer : public SerializerDeserializer { |
| bool ShouldBeSkipped(Object** current); |
| Isolate* isolate_; |
| - // Keep track of the fullness of each space in order to generate |
| - // relative addresses for back references. |
| - int fullness_[kNumberOfSpaces]; |
| + |
| + // Objects from the same space are put into chunks for bulk-allocation |
| + // when deserializing. We have to make sure that each chunk fits into a |
| + // page. So we track the chunk size in pending_chunk_ of a space, but |
| + // when it exceeds a page, we complete the current chunk and start a new one. |
| + uint32_t pending_chunk_[kNumberOfSpaces]; |
| + List<uint32_t> completed_chunks_[kNumberOfSpaces]; |
| + |
| SnapshotByteSink* sink_; |
| ExternalReferenceEncoder* external_reference_encoder_; |
| @@ -503,7 +530,7 @@ class Serializer : public SerializerDeserializer { |
| private: |
| CodeAddressMap* code_address_map_; |
| // We map serialized large objects to indexes for back-referencing. |
| - int seen_large_objects_index_; |
| + uint32_t seen_large_objects_index_; |
| DISALLOW_COPY_AND_ASSIGN(Serializer); |
| }; |
| @@ -585,9 +612,8 @@ class CodeSerializer : public Serializer { |
| Handle<SharedFunctionInfo> info, |
| Handle<String> source); |
| - static Handle<SharedFunctionInfo> Deserialize(Isolate* isolate, |
| - ScriptData* data, |
| - Handle<String> source); |
| + MUST_USE_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize( |
| + Isolate* isolate, ScriptData* data, Handle<String> source); |
| static const int kSourceObjectIndex = 0; |
| static const int kCodeStubsBaseIndex = 1; |
| @@ -654,15 +680,35 @@ class SerializedCodeData { |
| return result; |
| } |
| + class Reservation { |
| + public: |
| + uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation); } |
| + bool is_last_chunk() const { return IsLastChunkBits::decode(reservation); } |
| + |
| + private: |
| + uint32_t reservation; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Reservation); |
| + }; |
| + |
| + Vector<const Reservation> Reservations() const { |
| + return Vector<const Reservation>(reinterpret_cast<const Reservation*>( |
| + script_data_->data() + kHeaderSize), |
| + GetHeaderValue(kReservationsOffset)); |
| + } |
| + |
| Vector<const uint32_t> CodeStubKeys() const { |
| - return Vector<const uint32_t>( |
| - reinterpret_cast<const uint32_t*>(script_data_->data() + kHeaderSize), |
| - GetHeaderValue(kNumCodeStubKeysOffset)); |
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; |
| + const byte* start = script_data_->data() + kHeaderSize + reservations_size; |
| + return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start), |
| + GetHeaderValue(kNumCodeStubKeysOffset)); |
| } |
| const byte* Payload() const { |
| + int reservations_size = GetHeaderValue(kReservationsOffset) * kInt32Size; |
| int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size; |
| - return script_data_->data() + kHeaderSize + code_stubs_size; |
| + return script_data_->data() + kHeaderSize + reservations_size + |
| + code_stubs_size; |
| } |
| int PayloadLength() const { |
| @@ -672,10 +718,6 @@ class SerializedCodeData { |
| return payload_length; |
| } |
| - int GetReservation(int space) const { |
| - return GetHeaderValue(kReservationsOffset + space); |
| - } |
| - |
| private: |
| void SetHeaderValue(int offset, int value) { |
| reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] = |
| @@ -696,13 +738,13 @@ class SerializedCodeData { |
| // [2] payload length |
| // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. |
| static const int kCheckSumOffset = 0; |
| - static const int kNumCodeStubKeysOffset = 1; |
| - static const int kPayloadLengthOffset = 2; |
| - static const int kReservationsOffset = 3; |
| + static const int kReservationsOffset = 1; |
| + static const int kNumCodeStubKeysOffset = 2; |
| + static const int kPayloadLengthOffset = 3; |
| + static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize; |
| - static const int kHeaderEntries = |
| - kReservationsOffset + SerializerDeserializer::kNumberOfSpaces; |
| - static const int kHeaderSize = kHeaderEntries * kIntSize; |
| + class ChunkSizeBits : public BitField<uint32_t, 0, 31> {}; |
| + class IsLastChunkBits : public BitField<bool, 31, 1> {}; |
| // Following the header, we store, in sequential order |
| // - code stub keys |