1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/snapshot/default-serializer-allocator.h"
6 
7 #include "src/heap/heap-inl.h"
8 #include "src/snapshot/references.h"
9 #include "src/snapshot/serializer.h"
10 #include "src/snapshot/snapshot-source-sink.h"
11 
12 namespace v8 {
13 namespace internal {
14 
DefaultSerializerAllocator(Serializer<DefaultSerializerAllocator> * serializer)15 DefaultSerializerAllocator::DefaultSerializerAllocator(
16     Serializer<DefaultSerializerAllocator>* serializer)
17     : serializer_(serializer) {
18   for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
19     pending_chunk_[i] = 0;
20   }
21 }
22 
UseCustomChunkSize(uint32_t chunk_size)23 void DefaultSerializerAllocator::UseCustomChunkSize(uint32_t chunk_size) {
24   custom_chunk_size_ = chunk_size;
25 }
26 
PageSizeOfSpace(int space)27 static uint32_t PageSizeOfSpace(int space) {
28   return static_cast<uint32_t>(
29       MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space)));
30 }
31 
TargetChunkSize(int space)32 uint32_t DefaultSerializerAllocator::TargetChunkSize(int space) {
33   if (custom_chunk_size_ == 0) return PageSizeOfSpace(space);
34   DCHECK_LE(custom_chunk_size_, PageSizeOfSpace(space));
35   return custom_chunk_size_;
36 }
37 
Allocate(AllocationSpace space,uint32_t size)38 SerializerReference DefaultSerializerAllocator::Allocate(AllocationSpace space,
39                                                          uint32_t size) {
40   DCHECK(space >= 0 && space < kNumberOfPreallocatedSpaces);
41   DCHECK(size > 0 && size <= PageSizeOfSpace(space));
42 
43   // Maps are allocated through AllocateMap.
44   DCHECK_NE(MAP_SPACE, space);
45 
46   uint32_t old_chunk_size = pending_chunk_[space];
47   uint32_t new_chunk_size = old_chunk_size + size;
48   // Start a new chunk if the new size exceeds the target chunk size.
49   // We may exceed the target chunk size if the single object size does.
50   if (new_chunk_size > TargetChunkSize(space) && old_chunk_size != 0) {
51     serializer_->PutNextChunk(space);
52     completed_chunks_[space].push_back(pending_chunk_[space]);
53     pending_chunk_[space] = 0;
54     new_chunk_size = size;
55   }
56   uint32_t offset = pending_chunk_[space];
57   pending_chunk_[space] = new_chunk_size;
58   return SerializerReference::BackReference(
59       space, static_cast<uint32_t>(completed_chunks_[space].size()), offset);
60 }
61 
AllocateMap()62 SerializerReference DefaultSerializerAllocator::AllocateMap() {
63   // Maps are allocated one-by-one when deserializing.
64   return SerializerReference::MapReference(num_maps_++);
65 }
66 
AllocateLargeObject(uint32_t size)67 SerializerReference DefaultSerializerAllocator::AllocateLargeObject(
68     uint32_t size) {
69   // Large objects are allocated one-by-one when deserializing. We do not
70   // have to keep track of multiple chunks.
71   large_objects_total_size_ += size;
72   return SerializerReference::LargeObjectReference(seen_large_objects_index_++);
73 }
74 
AllocateOffHeapBackingStore()75 SerializerReference DefaultSerializerAllocator::AllocateOffHeapBackingStore() {
76   DCHECK_NE(0, seen_backing_stores_index_);
77   return SerializerReference::OffHeapBackingStoreReference(
78       seen_backing_stores_index_++);
79 }
80 
81 #ifdef DEBUG
BackReferenceIsAlreadyAllocated(SerializerReference reference) const82 bool DefaultSerializerAllocator::BackReferenceIsAlreadyAllocated(
83     SerializerReference reference) const {
84   DCHECK(reference.is_back_reference());
85   AllocationSpace space = reference.space();
86   if (space == LO_SPACE) {
87     return reference.large_object_index() < seen_large_objects_index_;
88   } else if (space == MAP_SPACE) {
89     return reference.map_index() < num_maps_;
90   } else if (space == RO_SPACE &&
91              serializer_->isolate()->heap()->deserialization_complete()) {
92     // If not deserializing the isolate itself, then we create BackReferences
93     // for all RO_SPACE objects without ever allocating.
94     return true;
95   } else {
96     size_t chunk_index = reference.chunk_index();
97     if (chunk_index == completed_chunks_[space].size()) {
98       return reference.chunk_offset() < pending_chunk_[space];
99     } else {
100       return chunk_index < completed_chunks_[space].size() &&
101              reference.chunk_offset() < completed_chunks_[space][chunk_index];
102     }
103   }
104 }
105 #endif
106 
107 std::vector<SerializedData::Reservation>
EncodeReservations() const108 DefaultSerializerAllocator::EncodeReservations() const {
109   std::vector<SerializedData::Reservation> out;
110 
111   for (int i = FIRST_SPACE; i < kNumberOfPreallocatedSpaces; i++) {
112     for (size_t j = 0; j < completed_chunks_[i].size(); j++) {
113       out.emplace_back(completed_chunks_[i][j]);
114     }
115 
116     if (pending_chunk_[i] > 0 || completed_chunks_[i].size() == 0) {
117       out.emplace_back(pending_chunk_[i]);
118     }
119     out.back().mark_as_last();
120   }
121 
122   STATIC_ASSERT(MAP_SPACE == kNumberOfPreallocatedSpaces);
123   out.emplace_back(num_maps_ * Map::kSize);
124   out.back().mark_as_last();
125 
126   STATIC_ASSERT(LO_SPACE == MAP_SPACE + 1);
127   out.emplace_back(large_objects_total_size_);
128   out.back().mark_as_last();
129 
130   return out;
131 }
132 
OutputStatistics()133 void DefaultSerializerAllocator::OutputStatistics() {
134   DCHECK(FLAG_serialization_statistics);
135 
136   PrintF("  Spaces (bytes):\n");
137 
138   for (int space = FIRST_SPACE; space < kNumberOfSpaces; space++) {
139     PrintF("%16s", AllocationSpaceName(static_cast<AllocationSpace>(space)));
140   }
141   PrintF("\n");
142 
143   for (int space = FIRST_SPACE; space < kNumberOfPreallocatedSpaces; space++) {
144     size_t s = pending_chunk_[space];
145     for (uint32_t chunk_size : completed_chunks_[space]) s += chunk_size;
146     PrintF("%16" PRIuS, s);
147   }
148 
149   STATIC_ASSERT(MAP_SPACE == kNumberOfPreallocatedSpaces);
150   PrintF("%16d", num_maps_ * Map::kSize);
151 
152   STATIC_ASSERT(LO_SPACE == MAP_SPACE + 1);
153   PrintF("%16d\n", large_objects_total_size_);
154 }
155 
156 }  // namespace internal
157 }  // namespace v8
158