| Index: src/serialize.h
|
| diff --git a/src/serialize.h b/src/serialize.h
|
| index 6fa7a341e7a2de1589a9e886f56caec03a6efd65..6e1f6512350b24dc56e39b1b25d38ce5b8095652 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 gracefully even if deserialization fails.
|
| + 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
|
|
|