Home | History | Annotate | Download | only in snapshot
      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