V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
serializer-allocator.cc
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/serializer-allocator.h"
6 
7 #include "src/heap/heap-inl.h" // crbug.com/v8/8499
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 
15 SerializerAllocator::SerializerAllocator(Serializer* serializer)
16  : serializer_(serializer) {
17  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
18  pending_chunk_[i] = 0;
19  }
20 }
21 
22 void SerializerAllocator::UseCustomChunkSize(uint32_t chunk_size) {
23  custom_chunk_size_ = chunk_size;
24 }
25 
26 static uint32_t PageSizeOfSpace(int space) {
27  return static_cast<uint32_t>(
28  MemoryChunkLayout::AllocatableMemoryInMemoryChunk(
29  static_cast<AllocationSpace>(space)));
30 }
31 
32 uint32_t SerializerAllocator::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 
38 SerializerReference SerializerAllocator::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  // We tenure large object allocations.
46  DCHECK_NE(NEW_LO_SPACE, space);
47 
48  uint32_t old_chunk_size = pending_chunk_[space];
49  uint32_t new_chunk_size = old_chunk_size + size;
50  // Start a new chunk if the new size exceeds the target chunk size.
51  // We may exceed the target chunk size if the single object size does.
52  if (new_chunk_size > TargetChunkSize(space) && old_chunk_size != 0) {
53  serializer_->PutNextChunk(space);
54  completed_chunks_[space].push_back(pending_chunk_[space]);
55  pending_chunk_[space] = 0;
56  new_chunk_size = size;
57  }
58  uint32_t offset = pending_chunk_[space];
59  pending_chunk_[space] = new_chunk_size;
60  return SerializerReference::BackReference(
61  space, static_cast<uint32_t>(completed_chunks_[space].size()), offset);
62 }
63 
64 SerializerReference SerializerAllocator::AllocateMap() {
65  // Maps are allocated one-by-one when deserializing.
66  return SerializerReference::MapReference(num_maps_++);
67 }
68 
69 SerializerReference SerializerAllocator::AllocateLargeObject(uint32_t size) {
70  // Large objects are allocated one-by-one when deserializing. We do not
71  // have to keep track of multiple chunks.
72  large_objects_total_size_ += size;
73  return SerializerReference::LargeObjectReference(seen_large_objects_index_++);
74 }
75 
76 SerializerReference SerializerAllocator::AllocateOffHeapBackingStore() {
77  DCHECK_NE(0, seen_backing_stores_index_);
78  return SerializerReference::OffHeapBackingStoreReference(
79  seen_backing_stores_index_++);
80 }
81 
82 #ifdef DEBUG
83 bool SerializerAllocator::BackReferenceIsAlreadyAllocated(
84  SerializerReference reference) const {
85  DCHECK(reference.is_back_reference());
86  AllocationSpace space = reference.space();
87  if (space == LO_SPACE) {
88  return reference.large_object_index() < seen_large_objects_index_;
89  } else if (space == MAP_SPACE) {
90  return reference.map_index() < num_maps_;
91  } else if (space == RO_SPACE &&
92  serializer_->isolate()->heap()->deserialization_complete()) {
93  // If not deserializing the isolate itself, then we create BackReferences
94  // for all RO_SPACE objects without ever allocating.
95  return true;
96  } else {
97  size_t chunk_index = reference.chunk_index();
98  if (chunk_index == completed_chunks_[space].size()) {
99  return reference.chunk_offset() < pending_chunk_[space];
100  } else {
101  return chunk_index < completed_chunks_[space].size() &&
102  reference.chunk_offset() < completed_chunks_[space][chunk_index];
103  }
104  }
105 }
106 #endif
107 
108 std::vector<SerializedData::Reservation>
109 SerializerAllocator::EncodeReservations() const {
110  std::vector<SerializedData::Reservation> out;
111 
112  for (int i = FIRST_SPACE; i < kNumberOfPreallocatedSpaces; i++) {
113  for (size_t j = 0; j < completed_chunks_[i].size(); j++) {
114  out.emplace_back(completed_chunks_[i][j]);
115  }
116 
117  if (pending_chunk_[i] > 0 || completed_chunks_[i].size() == 0) {
118  out.emplace_back(pending_chunk_[i]);
119  }
120  out.back().mark_as_last();
121  }
122 
123  STATIC_ASSERT(MAP_SPACE == kNumberOfPreallocatedSpaces);
124  out.emplace_back(num_maps_ * Map::kSize);
125  out.back().mark_as_last();
126 
127  STATIC_ASSERT(LO_SPACE == MAP_SPACE + 1);
128  out.emplace_back(large_objects_total_size_);
129  out.back().mark_as_last();
130 
131  return out;
132 }
133 
134 void SerializerAllocator::OutputStatistics() {
135  DCHECK(FLAG_serialization_statistics);
136 
137  PrintF(" Spaces (bytes):\n");
138 
139  for (int space = FIRST_SPACE; space < kNumberOfSpaces; space++) {
140  PrintF("%16s", AllocationSpaceName(static_cast<AllocationSpace>(space)));
141  }
142  PrintF("\n");
143 
144  for (int space = FIRST_SPACE; space < kNumberOfPreallocatedSpaces; space++) {
145  size_t s = pending_chunk_[space];
146  for (uint32_t chunk_size : completed_chunks_[space]) s += chunk_size;
147  PrintF("%16" PRIuS, s);
148  }
149 
150  STATIC_ASSERT(MAP_SPACE == kNumberOfPreallocatedSpaces);
151  PrintF("%16d", num_maps_ * Map::kSize);
152 
153  STATIC_ASSERT(LO_SPACE == MAP_SPACE + 1);
154  PrintF("%16d\n", large_objects_total_size_);
155 }
156 
157 } // namespace internal
158 } // namespace v8
Definition: libplatform.h:13