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/assembler-inl.h" 10 #include "src/base/platform/platform.h" 11 #include "src/callable.h" 12 #include "src/interface-descriptors.h" 13 #include "src/objects-inl.h" 14 #include "src/snapshot/builtin-deserializer.h" 15 #include "src/snapshot/builtin-serializer.h" 16 #include "src/snapshot/partial-deserializer.h" 17 #include "src/snapshot/snapshot-source-sink.h" 18 #include "src/snapshot/startup-deserializer.h" 19 #include "src/utils.h" 20 #include "src/version.h" 21 22 namespace v8 { 23 namespace internal { 24 25 #ifdef DEBUG 26 bool Snapshot::SnapshotIsValid(const v8::StartupData* snapshot_blob) { 27 return Snapshot::ExtractNumContexts(snapshot_blob) > 0; 28 } 29 #endif // DEBUG 30 31 bool Snapshot::HasContextSnapshot(Isolate* isolate, size_t index) { 32 // Do not use snapshots if the isolate is used to create snapshots. 33 const v8::StartupData* blob = isolate->snapshot_blob(); 34 if (blob == nullptr) return false; 35 if (blob->data == nullptr) return false; 36 size_t num_contexts = static_cast<size_t>(ExtractNumContexts(blob)); 37 return index < num_contexts; 38 } 39 40 bool Snapshot::Initialize(Isolate* isolate) { 41 if (!isolate->snapshot_available()) return false; 42 base::ElapsedTimer timer; 43 if (FLAG_profile_deserialization) timer.Start(); 44 45 const v8::StartupData* blob = isolate->snapshot_blob(); 46 CheckVersion(blob); 47 Vector<const byte> startup_data = ExtractStartupData(blob); 48 SnapshotData startup_snapshot_data(startup_data); 49 Vector<const byte> builtin_data = ExtractBuiltinData(blob); 50 BuiltinSnapshotData builtin_snapshot_data(builtin_data); 51 StartupDeserializer deserializer(&startup_snapshot_data, 52 &builtin_snapshot_data); 53 deserializer.SetRehashability(ExtractRehashability(blob)); 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 63 MaybeHandle<Context> Snapshot::NewContextFromSnapshot( 64 Isolate* isolate, Handle<JSGlobalProxy> global_proxy, size_t context_index, 65 v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) { 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 bool can_rehash = ExtractRehashability(blob); 72 Vector<const byte> context_data = 73 ExtractContextData(blob, static_cast<uint32_t>(context_index)); 74 SnapshotData snapshot_data(context_data); 75 76 MaybeHandle<Context> maybe_result = PartialDeserializer::DeserializeContext( 77 isolate, &snapshot_data, can_rehash, global_proxy, 78 embedder_fields_deserializer); 79 80 Handle<Context> result; 81 if (!maybe_result.ToHandle(&result)) return MaybeHandle<Context>(); 82 83 if (FLAG_profile_deserialization) { 84 double ms = timer.Elapsed().InMillisecondsF(); 85 int bytes = context_data.length(); 86 PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n", 87 context_index, bytes, ms); 88 } 89 return result; 90 } 91 92 // static 93 Code* Snapshot::DeserializeBuiltin(Isolate* isolate, int builtin_id) { 94 if (FLAG_trace_lazy_deserialization) { 95 PrintF("Lazy-deserializing builtin %s\n", Builtins::name(builtin_id)); 96 } 97 98 base::ElapsedTimer timer; 99 if (FLAG_profile_deserialization) timer.Start(); 100 101 const v8::StartupData* blob = isolate->snapshot_blob(); 102 Vector<const byte> builtin_data = Snapshot::ExtractBuiltinData(blob); 103 BuiltinSnapshotData builtin_snapshot_data(builtin_data); 104 105 CodeSpaceMemoryModificationScope code_allocation(isolate->heap()); 106 BuiltinDeserializer builtin_deserializer(isolate, &builtin_snapshot_data); 107 Code* code = builtin_deserializer.DeserializeBuiltin(builtin_id); 108 DCHECK_EQ(code, isolate->builtins()->builtin(builtin_id)); 109 110 if (FLAG_profile_deserialization) { 111 double ms = timer.Elapsed().InMillisecondsF(); 112 int bytes = code->Size(); 113 PrintF("[Deserializing builtin %s (%d bytes) took %0.3f ms]\n", 114 Builtins::name(builtin_id), bytes, ms); 115 } 116 117 if (isolate->logger()->is_listening_to_code_events() || 118 isolate->is_profiling()) { 119 isolate->logger()->LogCodeObject(code); 120 } 121 122 return code; 123 } 124 125 // static 126 void Snapshot::EnsureAllBuiltinsAreDeserialized(Isolate* isolate) { 127 if (!FLAG_lazy_deserialization) return; 128 129 if (FLAG_trace_lazy_deserialization) { 130 PrintF("Forcing eager builtin deserialization\n"); 131 } 132 133 Builtins* builtins = isolate->builtins(); 134 for (int i = 0; i < Builtins::builtin_count; i++) { 135 if (!Builtins::IsLazy(i)) continue; 136 137 DCHECK_NE(Builtins::kDeserializeLazy, i); 138 Code* code = builtins->builtin(i); 139 if (code->builtin_index() == Builtins::kDeserializeLazy) { 140 code = Snapshot::DeserializeBuiltin(isolate, i); 141 } 142 143 DCHECK_EQ(i, code->builtin_index()); 144 DCHECK_EQ(code, builtins->builtin(i)); 145 } 146 } 147 148 // static 149 Code* Snapshot::EnsureBuiltinIsDeserialized(Isolate* isolate, 150 Handle<SharedFunctionInfo> shared) { 151 DCHECK(FLAG_lazy_deserialization); 152 153 int builtin_id = shared->builtin_id(); 154 155 // We should never lazily deserialize DeserializeLazy. 156 DCHECK_NE(Builtins::kDeserializeLazy, builtin_id); 157 158 // Look up code from builtins list. 159 Code* code = isolate->builtins()->builtin(builtin_id); 160 161 // Deserialize if builtin is not on the list. 162 if (code->builtin_index() != builtin_id) { 163 DCHECK_EQ(code->builtin_index(), Builtins::kDeserializeLazy); 164 code = Snapshot::DeserializeBuiltin(isolate, builtin_id); 165 DCHECK_EQ(builtin_id, code->builtin_index()); 166 DCHECK_EQ(code, isolate->builtins()->builtin(builtin_id)); 167 } 168 return code; 169 } 170 171 // static 172 Code* Snapshot::DeserializeHandler(Isolate* isolate, 173 interpreter::Bytecode bytecode, 174 interpreter::OperandScale operand_scale) { 175 if (FLAG_trace_lazy_deserialization) { 176 PrintF("Lazy-deserializing handler %s\n", 177 interpreter::Bytecodes::ToString(bytecode, operand_scale).c_str()); 178 } 179 180 base::ElapsedTimer timer; 181 if (FLAG_profile_deserialization) timer.Start(); 182 183 const v8::StartupData* blob = isolate->snapshot_blob(); 184 Vector<const byte> builtin_data = Snapshot::ExtractBuiltinData(blob); 185 BuiltinSnapshotData builtin_snapshot_data(builtin_data); 186 187 CodeSpaceMemoryModificationScope code_allocation(isolate->heap()); 188 BuiltinDeserializer builtin_deserializer(isolate, &builtin_snapshot_data); 189 Code* code = builtin_deserializer.DeserializeHandler(bytecode, operand_scale); 190 191 if (FLAG_profile_deserialization) { 192 double ms = timer.Elapsed().InMillisecondsF(); 193 int bytes = code->Size(); 194 PrintF("[Deserializing handler %s (%d bytes) took %0.3f ms]\n", 195 interpreter::Bytecodes::ToString(bytecode, operand_scale).c_str(), 196 bytes, ms); 197 } 198 199 if (isolate->logger()->is_listening_to_code_events() || 200 isolate->is_profiling()) { 201 isolate->logger()->LogBytecodeHandler(bytecode, operand_scale, code); 202 } 203 204 return code; 205 } 206 207 void ProfileDeserialization( 208 const SnapshotData* startup_snapshot, const SnapshotData* builtin_snapshot, 209 const std::vector<SnapshotData*>& context_snapshots) { 210 if (FLAG_profile_deserialization) { 211 int startup_total = 0; 212 PrintF("Deserialization will reserve:\n"); 213 for (const auto& reservation : startup_snapshot->Reservations()) { 214 startup_total += reservation.chunk_size(); 215 } 216 for (const auto& reservation : builtin_snapshot->Reservations()) { 217 startup_total += reservation.chunk_size(); 218 } 219 PrintF("%10d bytes per isolate\n", startup_total); 220 for (size_t i = 0; i < context_snapshots.size(); i++) { 221 int context_total = 0; 222 for (const auto& reservation : context_snapshots[i]->Reservations()) { 223 context_total += reservation.chunk_size(); 224 } 225 PrintF("%10d bytes per context #%zu\n", context_total, i); 226 } 227 } 228 } 229 230 v8::StartupData Snapshot::CreateSnapshotBlob( 231 const SnapshotData* startup_snapshot, 232 const BuiltinSnapshotData* builtin_snapshot, 233 const std::vector<SnapshotData*>& context_snapshots, bool can_be_rehashed) { 234 uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size()); 235 uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts); 236 uint32_t total_length = startup_snapshot_offset; 237 total_length += static_cast<uint32_t>(startup_snapshot->RawData().length()); 238 total_length += static_cast<uint32_t>(builtin_snapshot->RawData().length()); 239 for (const auto context_snapshot : context_snapshots) { 240 total_length += static_cast<uint32_t>(context_snapshot->RawData().length()); 241 } 242 243 ProfileDeserialization(startup_snapshot, builtin_snapshot, context_snapshots); 244 245 char* data = new char[total_length]; 246 SetHeaderValue(data, kNumberOfContextsOffset, num_contexts); 247 SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0); 248 249 // Write version string into snapshot data. 250 memset(data + kVersionStringOffset, 0, kVersionStringLength); 251 Version::GetString( 252 Vector<char>(data + kVersionStringOffset, kVersionStringLength)); 253 254 // Startup snapshot (isolate-specific data). 255 uint32_t payload_offset = startup_snapshot_offset; 256 uint32_t payload_length = 257 static_cast<uint32_t>(startup_snapshot->RawData().length()); 258 CopyBytes(data + payload_offset, 259 reinterpret_cast<const char*>(startup_snapshot->RawData().start()), 260 payload_length); 261 if (FLAG_profile_deserialization) { 262 PrintF("Snapshot blob consists of:\n%10d bytes in %d chunks for startup\n", 263 payload_length, 264 static_cast<uint32_t>(startup_snapshot->Reservations().size())); 265 } 266 payload_offset += payload_length; 267 268 // Builtins. 269 SetHeaderValue(data, kBuiltinOffsetOffset, payload_offset); 270 payload_length = builtin_snapshot->RawData().length(); 271 CopyBytes(data + payload_offset, 272 reinterpret_cast<const char*>(builtin_snapshot->RawData().start()), 273 payload_length); 274 if (FLAG_profile_deserialization) { 275 PrintF("%10d bytes for builtins\n", payload_length); 276 } 277 payload_offset += payload_length; 278 279 // Partial snapshots (context-specific data). 280 for (uint32_t i = 0; i < num_contexts; i++) { 281 SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset); 282 SnapshotData* context_snapshot = context_snapshots[i]; 283 payload_length = context_snapshot->RawData().length(); 284 CopyBytes( 285 data + payload_offset, 286 reinterpret_cast<const char*>(context_snapshot->RawData().start()), 287 payload_length); 288 if (FLAG_profile_deserialization) { 289 PrintF("%10d bytes in %d chunks for context #%d\n", payload_length, 290 static_cast<uint32_t>(context_snapshot->Reservations().size()), i); 291 } 292 payload_offset += payload_length; 293 } 294 295 v8::StartupData result = {data, static_cast<int>(total_length)}; 296 DCHECK_EQ(total_length, payload_offset); 297 return result; 298 } 299 300 namespace { 301 bool BuiltinAliasesOffHeapTrampolineRegister(Isolate* isolate, Code* code) { 302 DCHECK(Builtins::IsIsolateIndependent(code->builtin_index())); 303 switch (Builtins::KindOf(code->builtin_index())) { 304 case Builtins::CPP: 305 case Builtins::TFC: 306 case Builtins::TFH: 307 case Builtins::TFJ: 308 case Builtins::TFS: 309 break; 310 311 // Bytecode handlers will only ever be used by the interpreter and so there 312 // will never be a need to use trampolines with them. 313 case Builtins::BCH: 314 case Builtins::API: 315 case Builtins::ASM: 316 // TODO(jgruber): Extend checks to remaining kinds. 317 return false; 318 } 319 320 Callable callable = Builtins::CallableFor( 321 isolate, static_cast<Builtins::Name>(code->builtin_index())); 322 CallInterfaceDescriptor descriptor = callable.descriptor(); 323 324 if (descriptor.ContextRegister() == kOffHeapTrampolineRegister) { 325 return true; 326 } 327 328 for (int i = 0; i < descriptor.GetRegisterParameterCount(); i++) { 329 Register reg = descriptor.GetRegisterParameter(i); 330 if (reg == kOffHeapTrampolineRegister) return true; 331 } 332 333 return false; 334 } 335 336 void FinalizeEmbeddedCodeTargets(Isolate* isolate, EmbeddedData* blob) { 337 static const int kRelocMask = 338 RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 339 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET); 340 341 for (int i = 0; i < Builtins::builtin_count; i++) { 342 if (!Builtins::IsIsolateIndependent(i)) continue; 343 344 Code* code = isolate->builtins()->builtin(i); 345 RelocIterator on_heap_it(code, kRelocMask); 346 RelocIterator off_heap_it(blob, code, kRelocMask); 347 348 #if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \ 349 defined(V8_TARGET_ARCH_ARM) 350 // On X64, ARM, ARM64 we emit relative builtin-to-builtin jumps for isolate 351 // independent builtins in the snapshot. This fixes up the relative jumps 352 // to the right offsets in the snapshot. 353 // See also: Code::IsIsolateIndependent. 354 while (!on_heap_it.done()) { 355 DCHECK(!off_heap_it.done()); 356 357 RelocInfo* rinfo = on_heap_it.rinfo(); 358 DCHECK_EQ(rinfo->rmode(), off_heap_it.rinfo()->rmode()); 359 Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 360 CHECK(Builtins::IsIsolateIndependentBuiltin(target)); 361 362 // Do not emit write-barrier for off-heap writes. 363 off_heap_it.rinfo()->set_target_address( 364 blob->InstructionStartOfBuiltin(target->builtin_index()), 365 SKIP_WRITE_BARRIER); 366 367 on_heap_it.next(); 368 off_heap_it.next(); 369 } 370 DCHECK(off_heap_it.done()); 371 #else 372 // Architectures other than x64 and arm/arm64 do not use pc-relative calls 373 // and thus must not contain embedded code targets. Instead, we use an 374 // indirection through the root register. 375 CHECK(on_heap_it.done()); 376 CHECK(off_heap_it.done()); 377 #endif // defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) 378 } 379 } 380 } // namespace 381 382 // static 383 EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) { 384 Builtins* builtins = isolate->builtins(); 385 386 // Store instruction stream lengths and offsets. 387 std::vector<struct Metadata> metadata(kTableSize); 388 389 bool saw_unsafe_builtin = false; 390 uint32_t raw_data_size = 0; 391 for (int i = 0; i < Builtins::builtin_count; i++) { 392 Code* code = builtins->builtin(i); 393 394 if (Builtins::IsIsolateIndependent(i)) { 395 DCHECK(!Builtins::IsLazy(i)); 396 397 // Sanity-check that the given builtin is isolate-independent and does not 398 // use the trampoline register in its calling convention. 399 if (!code->IsIsolateIndependent(isolate)) { 400 saw_unsafe_builtin = true; 401 fprintf(stderr, "%s is not isolate-independent.\n", Builtins::name(i)); 402 } 403 if (Builtins::IsWasmRuntimeStub(i) && 404 RelocInfo::RequiresRelocation(code)) { 405 // Wasm additionally requires that its runtime stubs must be 406 // individually PIC (i.e. we must be able to copy each stub outside the 407 // embedded area without relocations). In particular, that means 408 // pc-relative calls to other builtins are disallowed. 409 saw_unsafe_builtin = true; 410 fprintf(stderr, "%s is a wasm runtime stub but needs relocation.\n", 411 Builtins::name(i)); 412 } 413 if (BuiltinAliasesOffHeapTrampolineRegister(isolate, code)) { 414 saw_unsafe_builtin = true; 415 fprintf(stderr, "%s aliases the off-heap trampoline register.\n", 416 Builtins::name(i)); 417 } 418 419 uint32_t length = static_cast<uint32_t>(code->raw_instruction_size()); 420 421 DCHECK_EQ(0, raw_data_size % kCodeAlignment); 422 metadata[i].instructions_offset = raw_data_size; 423 metadata[i].instructions_length = length; 424 425 // Align the start of each instruction stream. 426 raw_data_size += PadAndAlign(length); 427 } else { 428 metadata[i].instructions_offset = raw_data_size; 429 } 430 } 431 CHECK_WITH_MSG( 432 !saw_unsafe_builtin, 433 "One or more builtins marked as isolate-independent either contains " 434 "isolate-dependent code or aliases the off-heap trampoline register. " 435 "If in doubt, ask jgruber@"); 436 437 const uint32_t blob_size = RawDataOffset() + raw_data_size; 438 uint8_t* const blob = new uint8_t[blob_size]; 439 uint8_t* const raw_data_start = blob + RawDataOffset(); 440 441 // Initially zap the entire blob, effectively padding the alignment area 442 // between two builtins with int3's (on x64/ia32). 443 ZapCode(reinterpret_cast<Address>(blob), blob_size); 444 445 // Write the metadata tables. 446 DCHECK_EQ(MetadataSize(), sizeof(metadata[0]) * metadata.size()); 447 std::memcpy(blob + MetadataOffset(), metadata.data(), MetadataSize()); 448 449 // Write the raw data section. 450 for (int i = 0; i < Builtins::builtin_count; i++) { 451 if (!Builtins::IsIsolateIndependent(i)) continue; 452 Code* code = builtins->builtin(i); 453 uint32_t offset = metadata[i].instructions_offset; 454 uint8_t* dst = raw_data_start + offset; 455 DCHECK_LE(RawDataOffset() + offset + code->raw_instruction_size(), 456 blob_size); 457 std::memcpy(dst, reinterpret_cast<uint8_t*>(code->raw_instruction_start()), 458 code->raw_instruction_size()); 459 } 460 461 EmbeddedData d(blob, blob_size); 462 463 // Fix up call targets that point to other embedded builtins. 464 FinalizeEmbeddedCodeTargets(isolate, &d); 465 466 // Hash the blob and store the result. 467 STATIC_ASSERT(HashSize() == kSizetSize); 468 const size_t hash = d.CreateHash(); 469 std::memcpy(blob + HashOffset(), &hash, HashSize()); 470 471 DCHECK_EQ(hash, d.CreateHash()); 472 DCHECK_EQ(hash, d.Hash()); 473 474 if (FLAG_serialization_statistics) d.PrintStatistics(); 475 476 return d; 477 } 478 479 EmbeddedData EmbeddedData::FromBlob() { 480 const uint8_t* data = Isolate::CurrentEmbeddedBlob(); 481 uint32_t size = Isolate::CurrentEmbeddedBlobSize(); 482 DCHECK_NOT_NULL(data); 483 DCHECK_LT(0, size); 484 return {data, size}; 485 } 486 487 Address EmbeddedData::InstructionStartOfBuiltin(int i) const { 488 DCHECK(Builtins::IsBuiltinId(i)); 489 const struct Metadata* metadata = Metadata(); 490 const uint8_t* result = RawData() + metadata[i].instructions_offset; 491 DCHECK_LE(result, data_ + size_); 492 DCHECK_IMPLIES(result == data_ + size_, InstructionSizeOfBuiltin(i) == 0); 493 return reinterpret_cast<Address>(result); 494 } 495 496 uint32_t EmbeddedData::InstructionSizeOfBuiltin(int i) const { 497 DCHECK(Builtins::IsBuiltinId(i)); 498 const struct Metadata* metadata = Metadata(); 499 return metadata[i].instructions_length; 500 } 501 502 size_t EmbeddedData::CreateHash() const { 503 STATIC_ASSERT(HashOffset() == 0); 504 STATIC_ASSERT(HashSize() == kSizetSize); 505 return base::hash_range(data_ + HashSize(), data_ + size_); 506 } 507 508 uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) { 509 CHECK_LT(kNumberOfContextsOffset, data->raw_size); 510 uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset); 511 return num_contexts; 512 } 513 514 void EmbeddedData::PrintStatistics() const { 515 DCHECK(FLAG_serialization_statistics); 516 517 constexpr int kCount = Builtins::builtin_count; 518 519 int embedded_count = 0; 520 int instruction_size = 0; 521 int sizes[kCount]; 522 for (int i = 0; i < kCount; i++) { 523 if (!Builtins::IsIsolateIndependent(i)) continue; 524 const int size = InstructionSizeOfBuiltin(i); 525 instruction_size += size; 526 sizes[embedded_count] = size; 527 embedded_count++; 528 } 529 530 // Sort for percentiles. 531 std::sort(&sizes[0], &sizes[embedded_count]); 532 533 const int k50th = embedded_count * 0.5; 534 const int k75th = embedded_count * 0.75; 535 const int k90th = embedded_count * 0.90; 536 const int k99th = embedded_count * 0.99; 537 538 const int metadata_size = static_cast<int>(HashSize() + MetadataSize()); 539 540 PrintF("EmbeddedData:\n"); 541 PrintF(" Total size: %d\n", 542 static_cast<int>(size())); 543 PrintF(" Metadata size: %d\n", metadata_size); 544 PrintF(" Instruction size: %d\n", instruction_size); 545 PrintF(" Padding: %d\n", 546 static_cast<int>(size() - metadata_size - instruction_size)); 547 PrintF(" Embedded builtin count: %d\n", embedded_count); 548 PrintF(" Instruction size (50th percentile): %d\n", sizes[k50th]); 549 PrintF(" Instruction size (75th percentile): %d\n", sizes[k75th]); 550 PrintF(" Instruction size (90th percentile): %d\n", sizes[k90th]); 551 PrintF(" Instruction size (99th percentile): %d\n", sizes[k99th]); 552 PrintF("\n"); 553 } 554 555 uint32_t Snapshot::ExtractContextOffset(const v8::StartupData* data, 556 uint32_t index) { 557 // Extract the offset of the context at a given index from the StartupData, 558 // and check that it is within bounds. 559 uint32_t context_offset = 560 GetHeaderValue(data, ContextSnapshotOffsetOffset(index)); 561 CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size)); 562 return context_offset; 563 } 564 565 bool Snapshot::ExtractRehashability(const v8::StartupData* data) { 566 CHECK_LT(kRehashabilityOffset, static_cast<uint32_t>(data->raw_size)); 567 return GetHeaderValue(data, kRehashabilityOffset) != 0; 568 } 569 570 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) { 571 uint32_t num_contexts = ExtractNumContexts(data); 572 uint32_t startup_offset = StartupSnapshotOffset(num_contexts); 573 CHECK_LT(startup_offset, data->raw_size); 574 uint32_t builtin_offset = GetHeaderValue(data, kBuiltinOffsetOffset); 575 CHECK_LT(builtin_offset, data->raw_size); 576 CHECK_GT(builtin_offset, startup_offset); 577 uint32_t startup_length = builtin_offset - startup_offset; 578 const byte* startup_data = 579 reinterpret_cast<const byte*>(data->data + startup_offset); 580 return Vector<const byte>(startup_data, startup_length); 581 } 582 583 Vector<const byte> Snapshot::ExtractBuiltinData(const v8::StartupData* data) { 584 DCHECK(SnapshotIsValid(data)); 585 586 uint32_t from_offset = GetHeaderValue(data, kBuiltinOffsetOffset); 587 CHECK_LT(from_offset, data->raw_size); 588 589 uint32_t to_offset = GetHeaderValue(data, ContextSnapshotOffsetOffset(0)); 590 CHECK_LT(to_offset, data->raw_size); 591 592 CHECK_GT(to_offset, from_offset); 593 uint32_t length = to_offset - from_offset; 594 const byte* builtin_data = 595 reinterpret_cast<const byte*>(data->data + from_offset); 596 return Vector<const byte>(builtin_data, length); 597 } 598 599 Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data, 600 uint32_t index) { 601 uint32_t num_contexts = ExtractNumContexts(data); 602 CHECK_LT(index, num_contexts); 603 604 uint32_t context_offset = ExtractContextOffset(data, index); 605 uint32_t next_context_offset; 606 if (index == num_contexts - 1) { 607 next_context_offset = data->raw_size; 608 } else { 609 next_context_offset = ExtractContextOffset(data, index + 1); 610 CHECK_LT(next_context_offset, data->raw_size); 611 } 612 613 const byte* context_data = 614 reinterpret_cast<const byte*>(data->data + context_offset); 615 uint32_t context_length = next_context_offset - context_offset; 616 return Vector<const byte>(context_data, context_length); 617 } 618 619 void Snapshot::CheckVersion(const v8::StartupData* data) { 620 char version[kVersionStringLength]; 621 memset(version, 0, kVersionStringLength); 622 CHECK_LT(kVersionStringOffset + kVersionStringLength, 623 static_cast<uint32_t>(data->raw_size)); 624 Version::GetString(Vector<char>(version, kVersionStringLength)); 625 if (strncmp(version, data->data + kVersionStringOffset, 626 kVersionStringLength) != 0) { 627 FATAL( 628 "Version mismatch between V8 binary and snapshot.\n" 629 "# V8 binary version: %.*s\n" 630 "# Snapshot version: %.*s\n" 631 "# The snapshot consists of %d bytes and contains %d context(s).", 632 kVersionStringLength, version, kVersionStringLength, 633 data->data + kVersionStringOffset, data->raw_size, 634 ExtractNumContexts(data)); 635 } 636 } 637 638 template <class AllocatorT> 639 SnapshotData::SnapshotData(const Serializer<AllocatorT>* serializer) { 640 DisallowHeapAllocation no_gc; 641 std::vector<Reservation> reservations = serializer->EncodeReservations(); 642 const std::vector<byte>* payload = serializer->Payload(); 643 644 // Calculate sizes. 645 uint32_t reservation_size = 646 static_cast<uint32_t>(reservations.size()) * kUInt32Size; 647 uint32_t size = 648 kHeaderSize + reservation_size + static_cast<uint32_t>(payload->size()); 649 650 // Allocate backing store and create result data. 651 AllocateData(size); 652 653 // Set header values. 654 SetMagicNumber(serializer->isolate()); 655 SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size())); 656 SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size())); 657 658 // Copy reservation chunk sizes. 659 CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()), 660 reservation_size); 661 662 // Copy serialized data. 663 CopyBytes(data_ + kHeaderSize + reservation_size, payload->data(), 664 static_cast<size_t>(payload->size())); 665 } 666 667 // Explicit instantiation. 668 template SnapshotData::SnapshotData( 669 const Serializer<DefaultSerializerAllocator>* serializer); 670 671 std::vector<SerializedData::Reservation> SnapshotData::Reservations() const { 672 uint32_t size = GetHeaderValue(kNumReservationsOffset); 673 std::vector<SerializedData::Reservation> reservations(size); 674 memcpy(reservations.data(), data_ + kHeaderSize, 675 size * sizeof(SerializedData::Reservation)); 676 return reservations; 677 } 678 679 Vector<const byte> SnapshotData::Payload() const { 680 uint32_t reservations_size = 681 GetHeaderValue(kNumReservationsOffset) * kUInt32Size; 682 const byte* payload = data_ + kHeaderSize + reservations_size; 683 uint32_t length = GetHeaderValue(kPayloadLengthOffset); 684 DCHECK_EQ(data_ + size_, payload + length); 685 return Vector<const byte>(payload, length); 686 } 687 688 BuiltinSnapshotData::BuiltinSnapshotData(const BuiltinSerializer* serializer) 689 : SnapshotData(serializer) {} 690 691 Vector<const byte> BuiltinSnapshotData::Payload() const { 692 uint32_t reservations_size = 693 GetHeaderValue(kNumReservationsOffset) * kUInt32Size; 694 const byte* payload = data_ + kHeaderSize + reservations_size; 695 const int builtin_offsets_size = 696 BuiltinSnapshotUtils::kNumberOfCodeObjects * kUInt32Size; 697 uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset); 698 DCHECK_EQ(data_ + size_, payload + payload_length); 699 DCHECK_GT(payload_length, builtin_offsets_size); 700 return Vector<const byte>(payload, payload_length - builtin_offsets_size); 701 } 702 703 Vector<const uint32_t> BuiltinSnapshotData::BuiltinOffsets() const { 704 uint32_t reservations_size = 705 GetHeaderValue(kNumReservationsOffset) * kUInt32Size; 706 const byte* payload = data_ + kHeaderSize + reservations_size; 707 const int builtin_offsets_size = 708 BuiltinSnapshotUtils::kNumberOfCodeObjects * kUInt32Size; 709 uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset); 710 DCHECK_EQ(data_ + size_, payload + payload_length); 711 DCHECK_GT(payload_length, builtin_offsets_size); 712 const uint32_t* data = reinterpret_cast<const uint32_t*>( 713 payload + payload_length - builtin_offsets_size); 714 return Vector<const uint32_t>(data, 715 BuiltinSnapshotUtils::kNumberOfCodeObjects); 716 } 717 718 } // namespace internal 719 } // namespace v8 720