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