serializer-allocator.cc 5.79 KB
Newer Older
1 2 3 4
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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 10 11 12 13 14
#include "src/snapshot/serializer.h"
#include "src/snapshot/snapshot-source-sink.h"

namespace v8 {
namespace internal {

15
SerializerAllocator::SerializerAllocator(Serializer* serializer)
16 17 18 19 20 21
    : serializer_(serializer) {
  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
    pending_chunk_[i] = 0;
  }
}

22
void SerializerAllocator::UseCustomChunkSize(uint32_t chunk_size) {
23 24 25
  custom_chunk_size_ = chunk_size;
}

26
static uint32_t PageSizeOfSpace(SnapshotSpace space) {
27
  return static_cast<uint32_t>(
28 29
      MemoryChunkLayout::AllocatableMemoryInMemoryChunk(
          static_cast<AllocationSpace>(space)));
30 31
}

32
uint32_t SerializerAllocator::TargetChunkSize(SnapshotSpace space) {
33 34 35 36 37
  if (custom_chunk_size_ == 0) return PageSizeOfSpace(space);
  DCHECK_LE(custom_chunk_size_, PageSizeOfSpace(space));
  return custom_chunk_size_;
}

38
SerializerReference SerializerAllocator::Allocate(SnapshotSpace space,
39
                                                  uint32_t size) {
40 41
  const int space_number = static_cast<int>(space);
  DCHECK(IsPreAllocatedSpace(space));
42
  DCHECK(size > 0 && size <= PageSizeOfSpace(space));
43 44

  // Maps are allocated through AllocateMap.
45
  DCHECK_NE(SnapshotSpace::kMap, space);
46

47
  uint32_t old_chunk_size = pending_chunk_[space_number];
48 49 50
  uint32_t new_chunk_size = old_chunk_size + size;
  // Start a new chunk if the new size exceeds the target chunk size.
  // We may exceed the target chunk size if the single object size does.
51
  if (new_chunk_size > TargetChunkSize(space) && old_chunk_size != 0) {
52
    serializer_->PutNextChunk(space);
53 54
    completed_chunks_[space_number].push_back(pending_chunk_[space_number]);
    pending_chunk_[space_number] = 0;
55 56
    new_chunk_size = size;
  }
57 58
  uint32_t offset = pending_chunk_[space_number];
  pending_chunk_[space_number] = new_chunk_size;
59
  return SerializerReference::BackReference(
60 61
      space, static_cast<uint32_t>(completed_chunks_[space_number].size()),
      offset);
62 63
}

64
SerializerReference SerializerAllocator::AllocateMap() {
65 66 67 68
  // Maps are allocated one-by-one when deserializing.
  return SerializerReference::MapReference(num_maps_++);
}

69
SerializerReference SerializerAllocator::AllocateLargeObject(uint32_t size) {
70 71 72 73 74 75
  // Large objects are allocated one-by-one when deserializing. We do not
  // have to keep track of multiple chunks.
  large_objects_total_size_ += size;
  return SerializerReference::LargeObjectReference(seen_large_objects_index_++);
}

76
SerializerReference SerializerAllocator::AllocateOffHeapBackingStore() {
77 78 79 80 81 82
  DCHECK_NE(0, seen_backing_stores_index_);
  return SerializerReference::OffHeapBackingStoreReference(
      seen_backing_stores_index_++);
}

#ifdef DEBUG
83
bool SerializerAllocator::BackReferenceIsAlreadyAllocated(
84 85
    SerializerReference reference) const {
  DCHECK(reference.is_back_reference());
86 87
  SnapshotSpace space = reference.space();
  if (space == SnapshotSpace::kLargeObject) {
88
    return reference.large_object_index() < seen_large_objects_index_;
89
  } else if (space == SnapshotSpace::kMap) {
90
    return reference.map_index() < num_maps_;
91
  } else if (space == SnapshotSpace::kReadOnlyHeap &&
92 93
             serializer_->isolate()->heap()->deserialization_complete()) {
    // If not deserializing the isolate itself, then we create BackReferences
94
    // for all read-only heap objects without ever allocating.
95
    return true;
96
  } else {
97
    const int space_number = static_cast<int>(space);
98
    size_t chunk_index = reference.chunk_index();
99 100
    if (chunk_index == completed_chunks_[space_number].size()) {
      return reference.chunk_offset() < pending_chunk_[space_number];
101
    } else {
102 103 104
      return chunk_index < completed_chunks_[space_number].size() &&
             reference.chunk_offset() <
                 completed_chunks_[space_number][chunk_index];
105 106 107 108 109 110
    }
  }
}
#endif

std::vector<SerializedData::Reservation>
111
SerializerAllocator::EncodeReservations() const {
112 113
  std::vector<SerializedData::Reservation> out;

114
  for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
115 116 117 118 119 120 121 122 123 124
    for (size_t j = 0; j < completed_chunks_[i].size(); j++) {
      out.emplace_back(completed_chunks_[i][j]);
    }

    if (pending_chunk_[i] > 0 || completed_chunks_[i].size() == 0) {
      out.emplace_back(pending_chunk_[i]);
    }
    out.back().mark_as_last();
  }

125 126
  STATIC_ASSERT(SnapshotSpace::kMap ==
                SnapshotSpace::kNumberOfPreallocatedSpaces);
127 128 129
  out.emplace_back(num_maps_ * Map::kSize);
  out.back().mark_as_last();

130 131 132
  STATIC_ASSERT(static_cast<int>(SnapshotSpace::kLargeObject) ==
                static_cast<int>(SnapshotSpace::kNumberOfPreallocatedSpaces) +
                    1);
133 134 135 136 137 138
  out.emplace_back(large_objects_total_size_);
  out.back().mark_as_last();

  return out;
}

139
void SerializerAllocator::OutputStatistics() {
140 141 142 143
  DCHECK(FLAG_serialization_statistics);

  PrintF("  Spaces (bytes):\n");

144
  for (int space = 0; space < kNumberOfSpaces; space++) {
145 146
    PrintF("%16s",
           BaseSpace::GetSpaceName(static_cast<AllocationSpace>(space)));
147 148 149
  }
  PrintF("\n");

150
  for (int space = 0; space < kNumberOfPreallocatedSpaces; space++) {
151 152
    size_t s = pending_chunk_[space];
    for (uint32_t chunk_size : completed_chunks_[space]) s += chunk_size;
153
    PrintF("%16zu", s);
154 155
  }

156 157
  STATIC_ASSERT(SnapshotSpace::kMap ==
                SnapshotSpace::kNumberOfPreallocatedSpaces);
158 159
  PrintF("%16d", num_maps_ * Map::kSize);

160 161 162
  STATIC_ASSERT(static_cast<int>(SnapshotSpace::kLargeObject) ==
                static_cast<int>(SnapshotSpace::kNumberOfPreallocatedSpaces) +
                    1);
163
  PrintF("%16d\n", large_objects_total_size_);
164 165 166 167
}

}  // namespace internal
}  // namespace v8