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 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 23 void DefaultSerializerAllocator::UseCustomChunkSize(uint32_t chunk_size) { 24 custom_chunk_size_ = chunk_size; 25 } 26 27 static uint32_t PageSizeOfSpace(int space) { 28 return static_cast<uint32_t>( 29 MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space))); 30 } 31 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 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 62 SerializerReference DefaultSerializerAllocator::AllocateMap() { 63 // Maps are allocated one-by-one when deserializing. 64 return SerializerReference::MapReference(num_maps_++); 65 } 66 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 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 82 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> 108 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 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