1// Copyright 2006-2008 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// The common functionality when building with or without snapshots. 6 7#include "src/snapshot/snapshot.h" 8 9#include "src/api.h" 10#include "src/base/platform/platform.h" 11#include "src/full-codegen/full-codegen.h" 12#include "src/snapshot/deserializer.h" 13#include "src/snapshot/snapshot-source-sink.h" 14#include "src/version.h" 15 16namespace v8 { 17namespace internal { 18 19#ifdef DEBUG 20bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) { 21 return Snapshot::ExtractNumContexts(snapshot_blob) > 0; 22} 23#endif // DEBUG 24 25 26bool Snapshot::HaveASnapshotToStartFrom(Isolate* isolate) { 27 // Do not use snapshots if the isolate is used to create snapshots. 28 return isolate->snapshot_blob() != NULL && 29 isolate->snapshot_blob()->data != NULL; 30} 31 32 33uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) { 34 DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE); 35 if (!isolate->snapshot_available()) { 36 return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space)); 37 } 38 uint32_t size; 39 int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size; 40 memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size); 41 return size; 42} 43 44 45bool Snapshot::Initialize(Isolate* isolate) { 46 if (!isolate->snapshot_available()) return false; 47 base::ElapsedTimer timer; 48 if (FLAG_profile_deserialization) timer.Start(); 49 50 const v8::StartupData* blob = isolate->snapshot_blob(); 51 Vector<const byte> startup_data = ExtractStartupData(blob); 52 SnapshotData snapshot_data(startup_data); 53 Deserializer deserializer(&snapshot_data); 54 bool success = isolate->Init(&deserializer); 55 if (FLAG_profile_deserialization) { 56 double ms = timer.Elapsed().InMillisecondsF(); 57 int bytes = startup_data.length(); 58 PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms); 59 } 60 return success; 61} 62 63MaybeHandle<Context> Snapshot::NewContextFromSnapshot( 64 Isolate* isolate, Handle<JSGlobalProxy> global_proxy, 65 size_t context_index) { 66 if (!isolate->snapshot_available()) return Handle<Context>(); 67 base::ElapsedTimer timer; 68 if (FLAG_profile_deserialization) timer.Start(); 69 70 const v8::StartupData* blob = isolate->snapshot_blob(); 71 Vector<const byte> context_data = 72 ExtractContextData(blob, static_cast<int>(context_index)); 73 SnapshotData snapshot_data(context_data); 74 Deserializer deserializer(&snapshot_data); 75 76 MaybeHandle<Object> maybe_context = 77 deserializer.DeserializePartial(isolate, global_proxy); 78 Handle<Object> result; 79 if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>(); 80 CHECK(result->IsContext()); 81 if (FLAG_profile_deserialization) { 82 double ms = timer.Elapsed().InMillisecondsF(); 83 int bytes = context_data.length(); 84 PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n", 85 context_index, bytes, ms); 86 } 87 return Handle<Context>::cast(result); 88} 89 90void UpdateMaxRequirementPerPage( 91 uint32_t* requirements, 92 Vector<const SerializedData::Reservation> reservations) { 93 int space = 0; 94 uint32_t current_requirement = 0; 95 for (const auto& reservation : reservations) { 96 current_requirement += reservation.chunk_size(); 97 if (reservation.is_last()) { 98 requirements[space] = std::max(requirements[space], current_requirement); 99 current_requirement = 0; 100 space++; 101 } 102 } 103 DCHECK_EQ(i::Serializer::kNumberOfSpaces, space); 104} 105 106void CalculateFirstPageSizes(const SnapshotData* startup_snapshot, 107 const List<SnapshotData*>* context_snapshots, 108 uint32_t* sizes_out) { 109 if (FLAG_profile_deserialization) { 110 int startup_total = 0; 111 PrintF("Deserialization will reserve:\n"); 112 for (const auto& reservation : startup_snapshot->Reservations()) { 113 startup_total += reservation.chunk_size(); 114 } 115 PrintF("%10d bytes per isolate\n", startup_total); 116 for (int i = 0; i < context_snapshots->length(); i++) { 117 int context_total = 0; 118 for (const auto& reservation : context_snapshots->at(i)->Reservations()) { 119 context_total += reservation.chunk_size(); 120 } 121 PrintF("%10d bytes per context #%d\n", context_total, i); 122 } 123 } 124 125 uint32_t startup_requirements[i::Serializer::kNumberOfSpaces]; 126 uint32_t context_requirements[i::Serializer::kNumberOfSpaces]; 127 for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) { 128 startup_requirements[space] = 0; 129 context_requirements[space] = 0; 130 } 131 132 UpdateMaxRequirementPerPage(startup_requirements, 133 startup_snapshot->Reservations()); 134 for (const auto& context_snapshot : *context_snapshots) { 135 UpdateMaxRequirementPerPage(context_requirements, 136 context_snapshot->Reservations()); 137 } 138 139 for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) { 140 // If the space requirement for a page is less than a page size, we consider 141 // limiting the size of the first page in order to save memory on startup. 142 uint32_t required = startup_requirements[space] + 143 2 * context_requirements[space] + 144 Page::kObjectStartOffset; 145 // Add a small allowance to the code space for small scripts. 146 if (space == CODE_SPACE) required += 32 * KB; 147 148 if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) { 149 uint32_t max_size = 150 MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space)); 151 sizes_out[space - FIRST_PAGED_SPACE] = std::min(required, max_size); 152 } 153 } 154} 155 156v8::StartupData Snapshot::CreateSnapshotBlob( 157 const SnapshotData* startup_snapshot, 158 const List<SnapshotData*>* context_snapshots) { 159 int num_contexts = context_snapshots->length(); 160 int startup_snapshot_offset = StartupSnapshotOffset(num_contexts); 161 int total_length = startup_snapshot_offset; 162 total_length += startup_snapshot->RawData().length(); 163 for (const auto& context_snapshot : *context_snapshots) { 164 total_length += context_snapshot->RawData().length(); 165 } 166 167 uint32_t first_page_sizes[kNumPagedSpaces]; 168 CalculateFirstPageSizes(startup_snapshot, context_snapshots, 169 first_page_sizes); 170 171 char* data = new char[total_length]; 172 memcpy(data + kFirstPageSizesOffset, first_page_sizes, 173 kNumPagedSpaces * kInt32Size); 174 memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size); 175 int payload_offset = StartupSnapshotOffset(num_contexts); 176 int payload_length = startup_snapshot->RawData().length(); 177 memcpy(data + payload_offset, startup_snapshot->RawData().start(), 178 payload_length); 179 if (FLAG_profile_deserialization) { 180 PrintF("Snapshot blob consists of:\n%10d bytes for startup\n", 181 payload_length); 182 } 183 payload_offset += payload_length; 184 for (int i = 0; i < num_contexts; i++) { 185 memcpy(data + ContextSnapshotOffsetOffset(i), &payload_offset, kInt32Size); 186 SnapshotData* context_snapshot = context_snapshots->at(i); 187 payload_length = context_snapshot->RawData().length(); 188 memcpy(data + payload_offset, context_snapshot->RawData().start(), 189 payload_length); 190 if (FLAG_profile_deserialization) { 191 PrintF("%10d bytes for context #%d\n", payload_length, i); 192 } 193 payload_offset += payload_length; 194 } 195 196 v8::StartupData result = {data, total_length}; 197 return result; 198} 199 200int Snapshot::ExtractNumContexts(const v8::StartupData* data) { 201 CHECK_LT(kNumberOfContextsOffset, data->raw_size); 202 int num_contexts; 203 memcpy(&num_contexts, data->data + kNumberOfContextsOffset, kInt32Size); 204 return num_contexts; 205} 206 207Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) { 208 int num_contexts = ExtractNumContexts(data); 209 int startup_offset = StartupSnapshotOffset(num_contexts); 210 CHECK_LT(startup_offset, data->raw_size); 211 int first_context_offset; 212 memcpy(&first_context_offset, data->data + ContextSnapshotOffsetOffset(0), 213 kInt32Size); 214 CHECK_LT(first_context_offset, data->raw_size); 215 int startup_length = first_context_offset - startup_offset; 216 const byte* startup_data = 217 reinterpret_cast<const byte*>(data->data + startup_offset); 218 return Vector<const byte>(startup_data, startup_length); 219} 220 221Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data, 222 int index) { 223 int num_contexts = ExtractNumContexts(data); 224 CHECK_LT(index, num_contexts); 225 226 int context_offset; 227 memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index), 228 kInt32Size); 229 int next_context_offset; 230 if (index == num_contexts - 1) { 231 next_context_offset = data->raw_size; 232 } else { 233 memcpy(&next_context_offset, 234 data->data + ContextSnapshotOffsetOffset(index + 1), kInt32Size); 235 CHECK_LT(next_context_offset, data->raw_size); 236 } 237 238 const byte* context_data = 239 reinterpret_cast<const byte*>(data->data + context_offset); 240 int context_length = next_context_offset - context_offset; 241 return Vector<const byte>(context_data, context_length); 242} 243 244SnapshotData::SnapshotData(const Serializer* serializer) { 245 DisallowHeapAllocation no_gc; 246 List<Reservation> reservations; 247 serializer->EncodeReservations(&reservations); 248 const List<byte>* payload = serializer->sink()->data(); 249 250 // Calculate sizes. 251 int reservation_size = reservations.length() * kInt32Size; 252 int size = kHeaderSize + reservation_size + payload->length(); 253 254 // Allocate backing store and create result data. 255 AllocateData(size); 256 257 // Set header values. 258 SetMagicNumber(serializer->isolate()); 259 SetHeaderValue(kCheckSumOffset, Version::Hash()); 260 SetHeaderValue(kNumReservationsOffset, reservations.length()); 261 SetHeaderValue(kPayloadLengthOffset, payload->length()); 262 263 // Copy reservation chunk sizes. 264 CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()), 265 reservation_size); 266 267 // Copy serialized data. 268 CopyBytes(data_ + kHeaderSize + reservation_size, payload->begin(), 269 static_cast<size_t>(payload->length())); 270} 271 272bool SnapshotData::IsSane() { 273 return GetHeaderValue(kCheckSumOffset) == Version::Hash(); 274} 275 276Vector<const SerializedData::Reservation> SnapshotData::Reservations() const { 277 return Vector<const Reservation>( 278 reinterpret_cast<const Reservation*>(data_ + kHeaderSize), 279 GetHeaderValue(kNumReservationsOffset)); 280} 281 282Vector<const byte> SnapshotData::Payload() const { 283 int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size; 284 const byte* payload = data_ + kHeaderSize + reservations_size; 285 int length = GetHeaderValue(kPayloadLengthOffset); 286 DCHECK_EQ(data_ + size_, payload + length); 287 return Vector<const byte>(payload, length); 288} 289 290} // namespace internal 291} // namespace v8 292