1// Copyright 2016 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/serializer.h" 6 7#include "src/codegen/assembler-inl.h" 8#include "src/common/globals.h" 9#include "src/handles/global-handles-inl.h" 10#include "src/heap/heap-inl.h" // For Space::identity(). 11#include "src/heap/memory-chunk-inl.h" 12#include "src/heap/read-only-heap.h" 13#include "src/interpreter/interpreter.h" 14#include "src/objects/code.h" 15#include "src/objects/js-array-buffer-inl.h" 16#include "src/objects/js-array-inl.h" 17#include "src/objects/map.h" 18#include "src/objects/objects-body-descriptors-inl.h" 19#include "src/objects/slots-inl.h" 20#include "src/objects/smi.h" 21#include "src/snapshot/serializer-deserializer.h" 22#include "src/snapshot/serializer-inl.h" 23 24namespace v8 { 25namespace internal { 26 27Serializer::Serializer(Isolate* isolate, Snapshot::SerializerFlags flags) 28 : isolate_(isolate), 29#if V8_COMPRESS_POINTERS 30 cage_base_(isolate), 31#endif // V8_COMPRESS_POINTERS 32 hot_objects_(isolate->heap()), 33 reference_map_(isolate), 34 external_reference_encoder_(isolate), 35 root_index_map_(isolate), 36 deferred_objects_(isolate->heap()), 37 forward_refs_per_pending_object_(isolate->heap()), 38 flags_(flags) 39#ifdef DEBUG 40 , 41 back_refs_(isolate->heap()), 42 stack_(isolate->heap()) 43#endif 44{ 45#ifdef OBJECT_PRINT 46 if (FLAG_serialization_statistics) { 47 for (int space = 0; space < kNumberOfSnapshotSpaces; ++space) { 48 // Value-initialized to 0. 49 instance_type_count_[space] = std::make_unique<int[]>(kInstanceTypes); 50 instance_type_size_[space] = std::make_unique<size_t[]>(kInstanceTypes); 51 } 52 } 53#endif // OBJECT_PRINT 54} 55 56#ifdef DEBUG 57void Serializer::PopStack() { stack_.Pop(); } 58#endif 59 60void Serializer::CountAllocation(Map map, int size, SnapshotSpace space) { 61 DCHECK(FLAG_serialization_statistics); 62 63 const int space_number = static_cast<int>(space); 64 allocation_size_[space_number] += size; 65#ifdef OBJECT_PRINT 66 int instance_type = map.instance_type(); 67 instance_type_count_[space_number][instance_type]++; 68 instance_type_size_[space_number][instance_type] += size; 69#endif // OBJECT_PRINT 70} 71 72int Serializer::TotalAllocationSize() const { 73 int sum = 0; 74 for (int space = 0; space < kNumberOfSnapshotSpaces; space++) { 75 sum += allocation_size_[space]; 76 } 77 return sum; 78} 79 80void Serializer::OutputStatistics(const char* name) { 81 if (!FLAG_serialization_statistics) return; 82 83 PrintF("%s:\n", name); 84 85 PrintF(" Spaces (bytes):\n"); 86 87 for (int space = 0; space < kNumberOfSnapshotSpaces; space++) { 88 PrintF("%16s", 89 BaseSpace::GetSpaceName(static_cast<AllocationSpace>(space))); 90 } 91 PrintF("\n"); 92 93 for (int space = 0; space < kNumberOfSnapshotSpaces; space++) { 94 PrintF("%16zu", allocation_size_[space]); 95 } 96 97#ifdef OBJECT_PRINT 98 PrintF(" Instance types (count and bytes):\n"); 99#define PRINT_INSTANCE_TYPE(Name) \ 100 for (int space = 0; space < kNumberOfSnapshotSpaces; ++space) { \ 101 if (instance_type_count_[space][Name]) { \ 102 PrintF("%10d %10zu %-10s %s\n", instance_type_count_[space][Name], \ 103 instance_type_size_[space][Name], \ 104 BaseSpace::GetSpaceName(static_cast<AllocationSpace>(space)), \ 105 #Name); \ 106 } \ 107 } 108 INSTANCE_TYPE_LIST(PRINT_INSTANCE_TYPE) 109#undef PRINT_INSTANCE_TYPE 110#endif // OBJECT_PRINT 111 112 PrintF("\n"); 113} 114 115void Serializer::SerializeDeferredObjects() { 116 if (FLAG_trace_serializer) { 117 PrintF("Serializing deferred objects\n"); 118 } 119 WHILE_WITH_HANDLE_SCOPE(isolate(), !deferred_objects_.empty(), { 120 Handle<HeapObject> obj = handle(deferred_objects_.Pop(), isolate()); 121 122 ObjectSerializer obj_serializer(this, obj, &sink_); 123 obj_serializer.SerializeDeferred(); 124 }); 125 sink_.Put(kSynchronize, "Finished with deferred objects"); 126} 127 128void Serializer::SerializeObject(Handle<HeapObject> obj) { 129 // ThinStrings are just an indirection to an internalized string, so elide the 130 // indirection and serialize the actual string directly. 131 if (obj->IsThinString(isolate())) { 132 obj = handle(ThinString::cast(*obj).actual(isolate()), isolate()); 133 } else if (obj->IsCodeT(isolate())) { 134 Code code = FromCodeT(CodeT::cast(*obj)); 135 if (code.kind() == CodeKind::BASELINE) { 136 // For now just serialize the BytecodeArray instead of baseline code. 137 // TODO(v8:11429,pthier): Handle Baseline code in cases we want to 138 // serialize it. 139 obj = handle(code.bytecode_or_interpreter_data(isolate()), isolate()); 140 } 141 } 142 SerializeObjectImpl(obj); 143} 144 145bool Serializer::MustBeDeferred(HeapObject object) { return false; } 146 147void Serializer::VisitRootPointers(Root root, const char* description, 148 FullObjectSlot start, FullObjectSlot end) { 149 for (FullObjectSlot current = start; current < end; ++current) { 150 SerializeRootObject(current); 151 } 152} 153 154void Serializer::SerializeRootObject(FullObjectSlot slot) { 155 Object o = *slot; 156 if (o.IsSmi()) { 157 PutSmiRoot(slot); 158 } else { 159 SerializeObject(Handle<HeapObject>(slot.location())); 160 } 161} 162 163#ifdef DEBUG 164void Serializer::PrintStack() { PrintStack(std::cout); } 165 166void Serializer::PrintStack(std::ostream& out) { 167 for (const auto o : stack_) { 168 o->Print(out); 169 out << "\n"; 170 } 171} 172#endif // DEBUG 173 174bool Serializer::SerializeRoot(HeapObject obj) { 175 RootIndex root_index; 176 // Derived serializers are responsible for determining if the root has 177 // actually been serialized before calling this. 178 if (root_index_map()->Lookup(obj, &root_index)) { 179 PutRoot(root_index); 180 return true; 181 } 182 return false; 183} 184 185bool Serializer::SerializeHotObject(HeapObject obj) { 186 DisallowGarbageCollection no_gc; 187 // Encode a reference to a hot object by its index in the working set. 188 int index = hot_objects_.Find(obj); 189 if (index == HotObjectsList::kNotFound) return false; 190 DCHECK(index >= 0 && index < kHotObjectCount); 191 if (FLAG_trace_serializer) { 192 PrintF(" Encoding hot object %d:", index); 193 obj.ShortPrint(); 194 PrintF("\n"); 195 } 196 sink_.Put(HotObject::Encode(index), "HotObject"); 197 return true; 198} 199 200bool Serializer::SerializeBackReference(HeapObject obj) { 201 DisallowGarbageCollection no_gc; 202 const SerializerReference* reference = reference_map_.LookupReference(obj); 203 if (reference == nullptr) return false; 204 // Encode the location of an already deserialized object in order to write 205 // its location into a later object. We can encode the location as an 206 // offset fromthe start of the deserialized objects or as an offset 207 // backwards from thecurrent allocation pointer. 208 if (reference->is_attached_reference()) { 209 if (FLAG_trace_serializer) { 210 PrintF(" Encoding attached reference %d\n", 211 reference->attached_reference_index()); 212 } 213 PutAttachedReference(*reference); 214 } else { 215 DCHECK(reference->is_back_reference()); 216 if (FLAG_trace_serializer) { 217 PrintF(" Encoding back reference to: "); 218 obj.ShortPrint(); 219 PrintF("\n"); 220 } 221 222 sink_.Put(kBackref, "Backref"); 223 PutBackReference(obj, *reference); 224 } 225 return true; 226} 227 228bool Serializer::SerializePendingObject(HeapObject obj) { 229 PendingObjectReferences* refs_to_object = 230 forward_refs_per_pending_object_.Find(obj); 231 if (refs_to_object == nullptr) { 232 return false; 233 } 234 PutPendingForwardReference(*refs_to_object); 235 return true; 236} 237 238bool Serializer::ObjectIsBytecodeHandler(HeapObject obj) const { 239 if (!obj.IsCode()) return false; 240 return (Code::cast(obj).kind() == CodeKind::BYTECODE_HANDLER); 241} 242 243void Serializer::PutRoot(RootIndex root) { 244 DisallowGarbageCollection no_gc; 245 int root_index = static_cast<int>(root); 246 HeapObject object = HeapObject::cast(isolate()->root(root)); 247 if (FLAG_trace_serializer) { 248 PrintF(" Encoding root %d:", root_index); 249 object.ShortPrint(); 250 PrintF("\n"); 251 } 252 253 // Assert that the first 32 root array items are a conscious choice. They are 254 // chosen so that the most common ones can be encoded more efficiently. 255 STATIC_ASSERT(static_cast<int>(RootIndex::kArgumentsMarker) == 256 kRootArrayConstantsCount - 1); 257 258 // TODO(ulan): Check that it works with young large objects. 259 if (root_index < kRootArrayConstantsCount && 260 !Heap::InYoungGeneration(object)) { 261 sink_.Put(RootArrayConstant::Encode(root), "RootConstant"); 262 } else { 263 sink_.Put(kRootArray, "RootSerialization"); 264 sink_.PutInt(root_index, "root_index"); 265 hot_objects_.Add(object); 266 } 267} 268 269void Serializer::PutSmiRoot(FullObjectSlot slot) { 270 // Serializing a smi root in compressed pointer builds will serialize the 271 // full object slot (of kSystemPointerSize) to avoid complications during 272 // deserialization (endianness or smi sequences). 273 STATIC_ASSERT(decltype(slot)::kSlotDataSize == sizeof(Address)); 274 STATIC_ASSERT(decltype(slot)::kSlotDataSize == kSystemPointerSize); 275 static constexpr int bytes_to_output = decltype(slot)::kSlotDataSize; 276 static constexpr int size_in_tagged = bytes_to_output >> kTaggedSizeLog2; 277 sink_.Put(FixedRawDataWithSize::Encode(size_in_tagged), "Smi"); 278 279 Address raw_value = Smi::cast(*slot).ptr(); 280 const byte* raw_value_as_bytes = reinterpret_cast<const byte*>(&raw_value); 281 sink_.PutRaw(raw_value_as_bytes, bytes_to_output, "Bytes"); 282} 283 284void Serializer::PutBackReference(HeapObject object, 285 SerializerReference reference) { 286 DCHECK_EQ(object, *back_refs_[reference.back_ref_index()]); 287 sink_.PutInt(reference.back_ref_index(), "BackRefIndex"); 288 hot_objects_.Add(object); 289} 290 291void Serializer::PutAttachedReference(SerializerReference reference) { 292 DCHECK(reference.is_attached_reference()); 293 sink_.Put(kAttachedReference, "AttachedRef"); 294 sink_.PutInt(reference.attached_reference_index(), "AttachedRefIndex"); 295} 296 297void Serializer::PutRepeat(int repeat_count) { 298 if (repeat_count <= kLastEncodableFixedRepeatCount) { 299 sink_.Put(FixedRepeatWithCount::Encode(repeat_count), "FixedRepeat"); 300 } else { 301 sink_.Put(kVariableRepeat, "VariableRepeat"); 302 sink_.PutInt(VariableRepeatCount::Encode(repeat_count), "repeat count"); 303 } 304} 305 306void Serializer::PutPendingForwardReference(PendingObjectReferences& refs) { 307 sink_.Put(kRegisterPendingForwardRef, "RegisterPendingForwardRef"); 308 unresolved_forward_refs_++; 309 // Register the current slot with the pending object. 310 int forward_ref_id = next_forward_ref_id_++; 311 if (refs == nullptr) { 312 // The IdentityMap holding the pending object reference vectors does not 313 // support non-trivial types; in particular it doesn't support destructors 314 // on values. So, we manually allocate a vector with new, and delete it when 315 // resolving the pending object. 316 refs = new std::vector<int>(); 317 } 318 refs->push_back(forward_ref_id); 319} 320 321void Serializer::ResolvePendingForwardReference(int forward_reference_id) { 322 sink_.Put(kResolvePendingForwardRef, "ResolvePendingForwardRef"); 323 sink_.PutInt(forward_reference_id, "with this index"); 324 unresolved_forward_refs_--; 325 326 // If there are no more unresolved forward refs, reset the forward ref id to 327 // zero so that future forward refs compress better. 328 if (unresolved_forward_refs_ == 0) { 329 next_forward_ref_id_ = 0; 330 } 331} 332 333ExternalReferenceEncoder::Value Serializer::EncodeExternalReference( 334 Address addr) { 335 Maybe<ExternalReferenceEncoder::Value> result = 336 external_reference_encoder_.TryEncode(addr); 337 if (result.IsNothing()) { 338#ifdef DEBUG 339 PrintStack(std::cerr); 340#endif 341 void* addr_ptr = reinterpret_cast<void*>(addr); 342 v8::base::OS::PrintError("Unknown external reference %p.\n", addr_ptr); 343 v8::base::OS::PrintError("%s\n", 344 ExternalReferenceTable::ResolveSymbol(addr_ptr)); 345 v8::base::OS::Abort(); 346 } 347 return result.FromJust(); 348} 349 350void Serializer::RegisterObjectIsPending(HeapObject obj) { 351 DisallowGarbageCollection no_gc; 352 if (IsNotMappedSymbol(obj)) return; 353 354 // Add the given object to the pending objects -> forward refs map. 355 auto find_result = forward_refs_per_pending_object_.FindOrInsert(obj); 356 USE(find_result); 357 358 // If the above emplace didn't actually add the object, then the object must 359 // already have been registered pending by deferring. It might not be in the 360 // deferred objects queue though, since it may be the very object we just 361 // popped off that queue, so just check that it can be deferred. 362 DCHECK_IMPLIES(find_result.already_exists, *find_result.entry != nullptr); 363 DCHECK_IMPLIES(find_result.already_exists, CanBeDeferred(obj)); 364} 365 366void Serializer::ResolvePendingObject(HeapObject obj) { 367 DisallowGarbageCollection no_gc; 368 if (IsNotMappedSymbol(obj)) return; 369 370 std::vector<int>* refs; 371 CHECK(forward_refs_per_pending_object_.Delete(obj, &refs)); 372 if (refs) { 373 for (int index : *refs) { 374 ResolvePendingForwardReference(index); 375 } 376 // See PutPendingForwardReference -- we have to manually manage the memory 377 // of non-trivial IdentityMap values. 378 delete refs; 379 } 380} 381 382void Serializer::Pad(int padding_offset) { 383 // The non-branching GetInt will read up to 3 bytes too far, so we need 384 // to pad the snapshot to make sure we don't read over the end. 385 for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) { 386 sink_.Put(kNop, "Padding"); 387 } 388 // Pad up to pointer size for checksum. 389 while (!IsAligned(sink_.Position() + padding_offset, kPointerAlignment)) { 390 sink_.Put(kNop, "Padding"); 391 } 392} 393 394void Serializer::InitializeCodeAddressMap() { 395 isolate_->InitializeLoggingAndCounters(); 396 code_address_map_ = std::make_unique<CodeAddressMap>(isolate_); 397} 398 399Code Serializer::CopyCode(Code code) { 400 code_buffer_.clear(); // Clear buffer without deleting backing store. 401 int size = code.CodeSize(); 402 code_buffer_.insert(code_buffer_.end(), 403 reinterpret_cast<byte*>(code.address()), 404 reinterpret_cast<byte*>(code.address() + size)); 405 // When pointer compression is enabled the checked cast will try to 406 // decompress map field of off-heap Code object. 407 return Code::unchecked_cast(HeapObject::FromAddress( 408 reinterpret_cast<Address>(&code_buffer_.front()))); 409} 410 411void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space, 412 int size, Map map) { 413 if (serializer_->code_address_map_) { 414 const char* code_name = 415 serializer_->code_address_map_->Lookup(object_->address()); 416 LOG(serializer_->isolate_, 417 CodeNameEvent(object_->address(), sink_->Position(), code_name)); 418 } 419 420 if (map == *object_) { 421 DCHECK_EQ(*object_, ReadOnlyRoots(isolate()).meta_map()); 422 DCHECK_EQ(space, SnapshotSpace::kReadOnlyHeap); 423 sink_->Put(kNewMetaMap, "NewMetaMap"); 424 425 DCHECK_EQ(size, Map::kSize); 426 } else { 427 sink_->Put(NewObject::Encode(space), "NewObject"); 428 429 // TODO(leszeks): Skip this when the map has a fixed size. 430 sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords"); 431 432 // Until the space for the object is allocated, it is considered "pending". 433 serializer_->RegisterObjectIsPending(*object_); 434 435 // Serialize map (first word of the object) before anything else, so that 436 // the deserializer can access it when allocating. Make sure that the map 437 // isn't a pending object. 438 DCHECK_NULL(serializer_->forward_refs_per_pending_object_.Find(map)); 439 DCHECK(map.IsMap()); 440 serializer_->SerializeObject(handle(map, isolate())); 441 442 // Make sure the map serialization didn't accidentally recursively serialize 443 // this object. 444 DCHECK_IMPLIES( 445 !serializer_->IsNotMappedSymbol(*object_), 446 serializer_->reference_map()->LookupReference(object_) == nullptr); 447 448 // Now that the object is allocated, we can resolve pending references to 449 // it. 450 serializer_->ResolvePendingObject(*object_); 451 } 452 453 if (FLAG_serialization_statistics) { 454 serializer_->CountAllocation(object_->map(), size, space); 455 } 456 457 // Mark this object as already serialized, and add it to the reference map so 458 // that it can be accessed by backreference by future objects. 459 serializer_->num_back_refs_++; 460#ifdef DEBUG 461 serializer_->back_refs_.Push(*object_); 462 DCHECK_EQ(serializer_->back_refs_.size(), serializer_->num_back_refs_); 463#endif 464 if (!serializer_->IsNotMappedSymbol(*object_)) { 465 // Only add the object to the map if it's not not_mapped_symbol, else 466 // the reference IdentityMap has issues. We don't expect to have back 467 // references to the not_mapped_symbol anyway, so it's fine. 468 SerializerReference back_reference = 469 SerializerReference::BackReference(serializer_->num_back_refs_ - 1); 470 serializer_->reference_map()->Add(*object_, back_reference); 471 DCHECK_EQ(*object_, 472 *serializer_->back_refs_[back_reference.back_ref_index()]); 473 DCHECK_EQ(back_reference.back_ref_index(), serializer_->reference_map() 474 ->LookupReference(object_) 475 ->back_ref_index()); 476 } 477} 478 479uint32_t Serializer::ObjectSerializer::SerializeBackingStore( 480 void* backing_store, int32_t byte_length, Maybe<int32_t> max_byte_length) { 481 DisallowGarbageCollection no_gc; 482 const SerializerReference* reference_ptr = 483 serializer_->reference_map()->LookupBackingStore(backing_store); 484 485 // Serialize the off-heap backing store. 486 if (reference_ptr) { 487 return reference_ptr->off_heap_backing_store_index(); 488 } 489 if (max_byte_length.IsJust()) { 490 sink_->Put(kOffHeapResizableBackingStore, 491 "Off-heap resizable backing store"); 492 } else { 493 sink_->Put(kOffHeapBackingStore, "Off-heap backing store"); 494 } 495 sink_->PutInt(byte_length, "length"); 496 if (max_byte_length.IsJust()) { 497 sink_->PutInt(max_byte_length.FromJust(), "max length"); 498 } 499 sink_->PutRaw(static_cast<byte*>(backing_store), byte_length, "BackingStore"); 500 DCHECK_NE(0, serializer_->seen_backing_stores_index_); 501 SerializerReference reference = 502 SerializerReference::OffHeapBackingStoreReference( 503 serializer_->seen_backing_stores_index_++); 504 // Mark this backing store as already serialized. 505 serializer_->reference_map()->AddBackingStore(backing_store, reference); 506 return reference.off_heap_backing_store_index(); 507} 508 509void Serializer::ObjectSerializer::SerializeJSTypedArray() { 510 { 511 DisallowGarbageCollection no_gc; 512 JSTypedArray typed_array = JSTypedArray::cast(*object_); 513 if (typed_array.is_on_heap()) { 514 typed_array.RemoveExternalPointerCompensationForSerialization(isolate()); 515 } else { 516 if (!typed_array.WasDetached()) { 517 // Explicitly serialize the backing store now. 518 JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array.buffer()); 519 // We cannot store byte_length or max_byte_length larger than int32 520 // range in the snapshot. 521 CHECK_LE(buffer.byte_length(), std::numeric_limits<int32_t>::max()); 522 int32_t byte_length = static_cast<int32_t>(buffer.byte_length()); 523 Maybe<int32_t> max_byte_length = Nothing<int32_t>(); 524 if (buffer.is_resizable()) { 525 CHECK_LE(buffer.max_byte_length(), 526 std::numeric_limits<int32_t>::max()); 527 max_byte_length = 528 Just(static_cast<int32_t>(buffer.max_byte_length())); 529 } 530 size_t byte_offset = typed_array.byte_offset(); 531 532 // We need to calculate the backing store from the data pointer 533 // because the ArrayBuffer may already have been serialized. 534 void* backing_store = reinterpret_cast<void*>( 535 reinterpret_cast<Address>(typed_array.DataPtr()) - byte_offset); 536 537 uint32_t ref = 538 SerializeBackingStore(backing_store, byte_length, max_byte_length); 539 typed_array.SetExternalBackingStoreRefForSerialization(ref); 540 } else { 541 typed_array.SetExternalBackingStoreRefForSerialization(0); 542 } 543 } 544 } 545 SerializeObject(); 546} 547 548void Serializer::ObjectSerializer::SerializeJSArrayBuffer() { 549 ArrayBufferExtension* extension; 550 void* backing_store; 551 { 552 DisallowGarbageCollection no_gc; 553 JSArrayBuffer buffer = JSArrayBuffer::cast(*object_); 554 backing_store = buffer.backing_store(); 555 // We cannot store byte_length or max_byte_length larger than int32 range in 556 // the snapshot. 557 CHECK_LE(buffer.byte_length(), std::numeric_limits<int32_t>::max()); 558 int32_t byte_length = static_cast<int32_t>(buffer.byte_length()); 559 Maybe<int32_t> max_byte_length = Nothing<int32_t>(); 560 if (buffer.is_resizable()) { 561 CHECK_LE(buffer.max_byte_length(), std::numeric_limits<int32_t>::max()); 562 max_byte_length = Just(static_cast<int32_t>(buffer.max_byte_length())); 563 } 564 extension = buffer.extension(); 565 566 // Only serialize non-empty backing stores. 567 if (buffer.IsEmpty()) { 568 buffer.SetBackingStoreRefForSerialization(kEmptyBackingStoreRefSentinel); 569 } else { 570 uint32_t ref = 571 SerializeBackingStore(backing_store, byte_length, max_byte_length); 572 buffer.SetBackingStoreRefForSerialization(ref); 573 574 // Ensure deterministic output by setting extension to null during 575 // serialization. 576 buffer.set_extension(nullptr); 577 } 578 } 579 SerializeObject(); 580 { 581 JSArrayBuffer buffer = JSArrayBuffer::cast(*object_); 582 buffer.set_backing_store(isolate(), backing_store); 583 buffer.set_extension(extension); 584 } 585} 586 587void Serializer::ObjectSerializer::SerializeExternalString() { 588 // For external strings with known resources, we replace the resource field 589 // with the encoded external reference, which we restore upon deserialize. 590 // For the rest we serialize them to look like ordinary sequential strings. 591 Handle<ExternalString> string = Handle<ExternalString>::cast(object_); 592 Address resource = string->resource_as_address(); 593 ExternalReferenceEncoder::Value reference; 594 if (serializer_->external_reference_encoder_.TryEncode(resource).To( 595 &reference)) { 596 DCHECK(reference.is_from_api()); 597#ifdef V8_SANDBOXED_EXTERNAL_POINTERS 598 uint32_t external_pointer_entry = 599 string->GetResourceRefForDeserialization(); 600#endif 601 string->SetResourceRefForSerialization(reference.index()); 602 SerializeObject(); 603#ifdef V8_SANDBOXED_EXTERNAL_POINTERS 604 string->SetResourceRefForSerialization(external_pointer_entry); 605#else 606 string->set_address_as_resource(isolate(), resource); 607#endif 608 } else { 609 SerializeExternalStringAsSequentialString(); 610 } 611} 612 613void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() { 614 // Instead of serializing this as an external string, we serialize 615 // an imaginary sequential string with the same content. 616 ReadOnlyRoots roots(isolate()); 617 PtrComprCageBase cage_base(isolate()); 618 DCHECK(object_->IsExternalString(cage_base)); 619 Handle<ExternalString> string = Handle<ExternalString>::cast(object_); 620 int length = string->length(); 621 Map map; 622 int content_size; 623 int allocation_size; 624 const byte* resource; 625 // Find the map and size for the imaginary sequential string. 626 bool internalized = object_->IsInternalizedString(cage_base); 627 if (object_->IsExternalOneByteString(cage_base)) { 628 map = internalized ? roots.one_byte_internalized_string_map() 629 : roots.one_byte_string_map(); 630 allocation_size = SeqOneByteString::SizeFor(length); 631 content_size = length * kCharSize; 632 resource = reinterpret_cast<const byte*>( 633 Handle<ExternalOneByteString>::cast(string)->resource()->data()); 634 } else { 635 map = internalized ? roots.internalized_string_map() : roots.string_map(); 636 allocation_size = SeqTwoByteString::SizeFor(length); 637 content_size = length * kShortSize; 638 resource = reinterpret_cast<const byte*>( 639 Handle<ExternalTwoByteString>::cast(string)->resource()->data()); 640 } 641 642 SnapshotSpace space = SnapshotSpace::kOld; 643 SerializePrologue(space, allocation_size, map); 644 645 // Output the rest of the imaginary string. 646 int bytes_to_output = allocation_size - HeapObject::kHeaderSize; 647 DCHECK(IsAligned(bytes_to_output, kTaggedSize)); 648 int slots_to_output = bytes_to_output >> kTaggedSizeLog2; 649 650 // Output raw data header. Do not bother with common raw length cases here. 651 sink_->Put(kVariableRawData, "RawDataForString"); 652 sink_->PutInt(slots_to_output, "length"); 653 654 // Serialize string header (except for map). 655 byte* string_start = reinterpret_cast<byte*>(string->address()); 656 for (int i = HeapObject::kHeaderSize; i < SeqString::kHeaderSize; i++) { 657 sink_->Put(string_start[i], "StringHeader"); 658 } 659 660 // Serialize string content. 661 sink_->PutRaw(resource, content_size, "StringContent"); 662 663 // Since the allocation size is rounded up to object alignment, there 664 // maybe left-over bytes that need to be padded. 665 int padding_size = allocation_size - SeqString::kHeaderSize - content_size; 666 DCHECK(0 <= padding_size && padding_size < kObjectAlignment); 667 for (int i = 0; i < padding_size; i++) { 668 sink_->Put(static_cast<byte>(0), "StringPadding"); 669 } 670} 671 672// Clear and later restore the next link in the weak cell or allocation site. 673// TODO(all): replace this with proper iteration of weak slots in serializer. 674class V8_NODISCARD UnlinkWeakNextScope { 675 public: 676 explicit UnlinkWeakNextScope(Heap* heap, HeapObject object) { 677 Isolate* isolate = heap->isolate(); 678 if (object.IsAllocationSite(isolate) && 679 AllocationSite::cast(object).HasWeakNext()) { 680 object_ = object; 681 next_ = AllocationSite::cast(object).weak_next(); 682 AllocationSite::cast(object).set_weak_next( 683 ReadOnlyRoots(isolate).undefined_value()); 684 } 685 } 686 687 ~UnlinkWeakNextScope() { 688 if (next_ == Smi::zero()) return; 689 AllocationSite::cast(object_).set_weak_next(next_, 690 UPDATE_WEAK_WRITE_BARRIER); 691 } 692 693 private: 694 HeapObject object_; 695 Object next_ = Smi::zero(); 696 DISALLOW_GARBAGE_COLLECTION(no_gc_) 697}; 698 699void Serializer::ObjectSerializer::Serialize() { 700 RecursionScope recursion(serializer_); 701 702 { 703 DisallowGarbageCollection no_gc; 704 HeapObject raw = *object_; 705 // Defer objects as "pending" if they cannot be serialized now, or if we 706 // exceed a certain recursion depth. Some objects cannot be deferred. 707 if ((recursion.ExceedsMaximum() && CanBeDeferred(raw)) || 708 serializer_->MustBeDeferred(raw)) { 709 DCHECK(CanBeDeferred(raw)); 710 if (FLAG_trace_serializer) { 711 PrintF(" Deferring heap object: "); 712 object_->ShortPrint(); 713 PrintF("\n"); 714 } 715 // Deferred objects are considered "pending". 716 serializer_->RegisterObjectIsPending(raw); 717 serializer_->PutPendingForwardReference( 718 *serializer_->forward_refs_per_pending_object_.Find(raw)); 719 serializer_->QueueDeferredObject(raw); 720 return; 721 } 722 723 if (FLAG_trace_serializer) { 724 PrintF(" Encoding heap object: "); 725 object_->ShortPrint(); 726 PrintF("\n"); 727 } 728 } 729 730 PtrComprCageBase cage_base(isolate()); 731 InstanceType instance_type = object_->map(cage_base).instance_type(); 732 if (InstanceTypeChecker::IsExternalString(instance_type)) { 733 SerializeExternalString(); 734 return; 735 } else if (!ReadOnlyHeap::Contains(*object_)) { 736 // Only clear padding for strings outside the read-only heap. Read-only heap 737 // should have been cleared elsewhere. 738 if (object_->IsSeqOneByteString(cage_base)) { 739 // Clear padding bytes at the end. Done here to avoid having to do this 740 // at allocation sites in generated code. 741 Handle<SeqOneByteString>::cast(object_)->clear_padding(); 742 } else if (object_->IsSeqTwoByteString(cage_base)) { 743 Handle<SeqTwoByteString>::cast(object_)->clear_padding(); 744 } 745 } 746 if (InstanceTypeChecker::IsJSTypedArray(instance_type)) { 747 SerializeJSTypedArray(); 748 return; 749 } else if (InstanceTypeChecker::IsJSArrayBuffer(instance_type)) { 750 SerializeJSArrayBuffer(); 751 return; 752 } else if (InstanceTypeChecker::IsScript(instance_type)) { 753 // Clear cached line ends. 754 Oddball undefined = ReadOnlyRoots(isolate()).undefined_value(); 755 Handle<Script>::cast(object_)->set_line_ends(undefined); 756 } 757 758 // We don't expect fillers. 759 DCHECK(!object_->IsFreeSpaceOrFiller(cage_base)); 760 761 SerializeObject(); 762} 763 764namespace { 765SnapshotSpace GetSnapshotSpace(HeapObject object) { 766 if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) { 767 if (object.IsCode()) { 768 return SnapshotSpace::kCode; 769 } else if (ReadOnlyHeap::Contains(object)) { 770 return SnapshotSpace::kReadOnlyHeap; 771 } else if (object.IsMap()) { 772 return SnapshotSpace::kMap; 773 } else { 774 return SnapshotSpace::kOld; 775 } 776 } else if (ReadOnlyHeap::Contains(object)) { 777 return SnapshotSpace::kReadOnlyHeap; 778 } else { 779 AllocationSpace heap_space = 780 MemoryChunk::FromHeapObject(object)->owner_identity(); 781 // Large code objects are not supported and cannot be expressed by 782 // SnapshotSpace. 783 DCHECK_NE(heap_space, CODE_LO_SPACE); 784 switch (heap_space) { 785 case OLD_SPACE: 786 // Young generation objects are tenured, as objects that have survived 787 // until snapshot building probably deserve to be considered 'old'. 788 case NEW_SPACE: 789 // Large objects (young and old) are encoded as simply 'old' snapshot 790 // obects, as "normal" objects vs large objects is a heap implementation 791 // detail and isn't relevant to the snapshot. 792 case NEW_LO_SPACE: 793 case LO_SPACE: 794 return SnapshotSpace::kOld; 795 case CODE_SPACE: 796 return SnapshotSpace::kCode; 797 case MAP_SPACE: 798 return SnapshotSpace::kMap; 799 case CODE_LO_SPACE: 800 case RO_SPACE: 801 UNREACHABLE(); 802 } 803 } 804} 805} // namespace 806 807void Serializer::ObjectSerializer::SerializeObject() { 808 Map map = object_->map(serializer_->cage_base()); 809 int size = object_->SizeFromMap(map); 810 811 // Descriptor arrays have complex element weakness, that is dependent on the 812 // maps pointing to them. During deserialization, this can cause them to get 813 // prematurely trimmed one of their owners isn't deserialized yet. We work 814 // around this by forcing all descriptor arrays to be serialized as "strong", 815 // i.e. no custom weakness, and "re-weaken" them in the deserializer once 816 // deserialization completes. 817 // 818 // See also `Deserializer::WeakenDescriptorArrays`. 819 if (map == ReadOnlyRoots(isolate()).descriptor_array_map()) { 820 map = ReadOnlyRoots(isolate()).strong_descriptor_array_map(); 821 } 822 SnapshotSpace space = GetSnapshotSpace(*object_); 823 SerializePrologue(space, size, map); 824 825 // Serialize the rest of the object. 826 CHECK_EQ(0, bytes_processed_so_far_); 827 bytes_processed_so_far_ = kTaggedSize; 828 829 SerializeContent(map, size); 830} 831 832void Serializer::ObjectSerializer::SerializeDeferred() { 833 const SerializerReference* back_reference = 834 serializer_->reference_map()->LookupReference(object_); 835 836 if (back_reference != nullptr) { 837 if (FLAG_trace_serializer) { 838 PrintF(" Deferred heap object "); 839 object_->ShortPrint(); 840 PrintF(" was already serialized\n"); 841 } 842 return; 843 } 844 845 if (FLAG_trace_serializer) { 846 PrintF(" Encoding deferred heap object\n"); 847 } 848 Serialize(); 849} 850 851void Serializer::ObjectSerializer::SerializeContent(Map map, int size) { 852 HeapObject raw = *object_; 853 UnlinkWeakNextScope unlink_weak_next(isolate()->heap(), raw); 854 if (raw.IsCode()) { 855 // For code objects, perform a custom serialization. 856 SerializeCode(map, size); 857 } else { 858 // For other objects, iterate references first. 859 raw.IterateBody(map, size, this); 860 // Then output data payload, if any. 861 OutputRawData(raw.address() + size); 862 } 863} 864 865void Serializer::ObjectSerializer::VisitPointers(HeapObject host, 866 ObjectSlot start, 867 ObjectSlot end) { 868 VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end)); 869} 870 871void Serializer::ObjectSerializer::VisitPointers(HeapObject host, 872 MaybeObjectSlot start, 873 MaybeObjectSlot end) { 874 HandleScope scope(isolate()); 875 PtrComprCageBase cage_base(isolate()); 876 DisallowGarbageCollection no_gc; 877 878 MaybeObjectSlot current = start; 879 while (current < end) { 880 while (current < end && current.load(cage_base).IsSmi()) { 881 ++current; 882 } 883 if (current < end) { 884 OutputRawData(current.address()); 885 } 886 // TODO(ishell): Revisit this change once we stick to 32-bit compressed 887 // tagged values. 888 while (current < end && current.load(cage_base).IsCleared()) { 889 sink_->Put(kClearedWeakReference, "ClearedWeakReference"); 890 bytes_processed_so_far_ += kTaggedSize; 891 ++current; 892 } 893 HeapObject current_contents; 894 HeapObjectReferenceType reference_type; 895 while (current < end && current.load(cage_base).GetHeapObject( 896 ¤t_contents, &reference_type)) { 897 // Write a weak prefix if we need it. This has to be done before the 898 // potential pending object serialization. 899 if (reference_type == HeapObjectReferenceType::WEAK) { 900 sink_->Put(kWeakPrefix, "WeakReference"); 901 } 902 903 Handle<HeapObject> obj = handle(current_contents, isolate()); 904 if (serializer_->SerializePendingObject(*obj)) { 905 bytes_processed_so_far_ += kTaggedSize; 906 ++current; 907 continue; 908 } 909 910 RootIndex root_index; 911 // Compute repeat count and write repeat prefix if applicable. 912 // Repeats are not subject to the write barrier so we can only use 913 // immortal immovable root members. 914 MaybeObjectSlot repeat_end = current + 1; 915 if (repeat_end < end && 916 serializer_->root_index_map()->Lookup(*obj, &root_index) && 917 RootsTable::IsImmortalImmovable(root_index) && 918 *current == *repeat_end) { 919 DCHECK_EQ(reference_type, HeapObjectReferenceType::STRONG); 920 DCHECK(!Heap::InYoungGeneration(*obj)); 921 while (repeat_end < end && *repeat_end == *current) { 922 repeat_end++; 923 } 924 int repeat_count = static_cast<int>(repeat_end - current); 925 current = repeat_end; 926 bytes_processed_so_far_ += repeat_count * kTaggedSize; 927 serializer_->PutRepeat(repeat_count); 928 } else { 929 bytes_processed_so_far_ += kTaggedSize; 930 ++current; 931 } 932 // Now write the object itself. 933 serializer_->SerializeObject(obj); 934 } 935 } 936} 937 938void Serializer::ObjectSerializer::VisitCodePointer(HeapObject host, 939 CodeObjectSlot slot) { 940 CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); 941 // A version of VisitPointers() customized for CodeObjectSlot. 942 HandleScope scope(isolate()); 943 DisallowGarbageCollection no_gc; 944 945#ifdef V8_EXTERNAL_CODE_SPACE 946 PtrComprCageBase code_cage_base(isolate()->code_cage_base()); 947#else 948 PtrComprCageBase code_cage_base(isolate()); 949#endif 950 Object contents = slot.load(code_cage_base); 951 DCHECK(HAS_STRONG_HEAP_OBJECT_TAG(contents.ptr())); 952 DCHECK(contents.IsCode()); 953 954 Handle<HeapObject> obj = handle(HeapObject::cast(contents), isolate()); 955 if (!serializer_->SerializePendingObject(*obj)) { 956 serializer_->SerializeObject(obj); 957 } 958 bytes_processed_so_far_ += kTaggedSize; 959} 960 961void Serializer::ObjectSerializer::OutputExternalReference( 962 Address target, int target_size, bool sandboxify, ExternalPointerTag tag) { 963 DCHECK_LE(target_size, sizeof(target)); // Must fit in Address. 964 DCHECK_IMPLIES(sandboxify, tag != kExternalPointerNullTag); 965 ExternalReferenceEncoder::Value encoded_reference; 966 bool encoded_successfully; 967 968 if (serializer_->allow_unknown_external_references_for_testing()) { 969 encoded_successfully = 970 serializer_->TryEncodeExternalReference(target).To(&encoded_reference); 971 } else { 972 encoded_reference = serializer_->EncodeExternalReference(target); 973 encoded_successfully = true; 974 } 975 976 if (!encoded_successfully) { 977 // In this case the serialized snapshot will not be used in a different 978 // Isolate and thus the target address will not change between 979 // serialization and deserialization. We can serialize seen external 980 // references verbatim. 981 CHECK(serializer_->allow_unknown_external_references_for_testing()); 982 CHECK(IsAligned(target_size, kTaggedSize)); 983 CHECK_LE(target_size, kFixedRawDataCount * kTaggedSize); 984 int size_in_tagged = target_size >> kTaggedSizeLog2; 985 sink_->Put(FixedRawDataWithSize::Encode(size_in_tagged), "FixedRawData"); 986 sink_->PutRaw(reinterpret_cast<byte*>(&target), target_size, "Bytes"); 987 } else if (encoded_reference.is_from_api()) { 988 if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL && sandboxify) { 989 sink_->Put(kSandboxedApiReference, "SandboxedApiRef"); 990 } else { 991 sink_->Put(kApiReference, "ApiRef"); 992 } 993 sink_->PutInt(encoded_reference.index(), "reference index"); 994 } else { 995 if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL && sandboxify) { 996 sink_->Put(kSandboxedExternalReference, "SandboxedExternalRef"); 997 } else { 998 sink_->Put(kExternalReference, "ExternalRef"); 999 } 1000 sink_->PutInt(encoded_reference.index(), "reference index"); 1001 } 1002 if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL && sandboxify) { 1003 sink_->PutInt(static_cast<uint32_t>(tag >> kExternalPointerTagShift), 1004 "external pointer tag"); 1005 } 1006} 1007 1008void Serializer::ObjectSerializer::VisitExternalReference(Foreign host, 1009 Address* p) { 1010 // "Sandboxify" external reference. 1011 OutputExternalReference(host.foreign_address(), kSystemPointerSize, true, 1012 kForeignForeignAddressTag); 1013 bytes_processed_so_far_ += kExternalPointerSize; 1014} 1015 1016class Serializer::ObjectSerializer::RelocInfoObjectPreSerializer { 1017 public: 1018 explicit RelocInfoObjectPreSerializer(Serializer* serializer) 1019 : serializer_(serializer) {} 1020 1021 void VisitEmbeddedPointer(Code host, RelocInfo* target) { 1022 HeapObject object = target->target_object(isolate()); 1023 serializer_->SerializeObject(handle(object, isolate())); 1024 num_serialized_objects_++; 1025 } 1026 void VisitCodeTarget(Code host, RelocInfo* target) { 1027#ifdef V8_TARGET_ARCH_ARM 1028 DCHECK(!RelocInfo::IsRelativeCodeTarget(target->rmode())); 1029#endif 1030 Code object = Code::GetCodeFromTargetAddress(target->target_address()); 1031 serializer_->SerializeObject(handle(object, isolate())); 1032 num_serialized_objects_++; 1033 } 1034 1035 void VisitExternalReference(Code host, RelocInfo* rinfo) {} 1036 void VisitInternalReference(Code host, RelocInfo* rinfo) {} 1037 void VisitRuntimeEntry(Code host, RelocInfo* reloc) { UNREACHABLE(); } 1038 void VisitOffHeapTarget(Code host, RelocInfo* target) {} 1039 1040 int num_serialized_objects() const { return num_serialized_objects_; } 1041 1042 Isolate* isolate() { return serializer_->isolate(); } 1043 1044 private: 1045 Serializer* serializer_; 1046 int num_serialized_objects_ = 0; 1047}; 1048 1049void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host, 1050 RelocInfo* rinfo) { 1051 // Target object should be pre-serialized by RelocInfoObjectPreSerializer, so 1052 // just track the pointer's existence as kTaggedSize in 1053 // bytes_processed_so_far_. 1054 // TODO(leszeks): DCHECK that RelocInfoObjectPreSerializer serialized this 1055 // specific object already. 1056 bytes_processed_so_far_ += kTaggedSize; 1057} 1058 1059void Serializer::ObjectSerializer::VisitExternalReference(Code host, 1060 RelocInfo* rinfo) { 1061 Address target = rinfo->target_external_reference(); 1062 DCHECK_NE(target, kNullAddress); // Code does not reference null. 1063 DCHECK_IMPLIES(serializer_->EncodeExternalReference(target).is_from_api(), 1064 !rinfo->IsCodedSpecially()); 1065 // Don't "sandboxify" external references embedded in the code. 1066 OutputExternalReference(target, rinfo->target_address_size(), false, 1067 kExternalPointerNullTag); 1068} 1069 1070void Serializer::ObjectSerializer::VisitExternalPointer(HeapObject host, 1071 ExternalPointer_t ptr) { 1072 // TODO(v8:12700) handle other external references here as well. This should 1073 // allow removing some of the other Visit* methods, should unify the sandbox 1074 // vs no-sandbox implementation, and should allow removing various 1075 // XYZForSerialization methods throughout the codebase. 1076 if (host.IsJSExternalObject()) { 1077#ifdef V8_SANDBOXED_EXTERNAL_POINTERS 1078 // TODO(saelo) maybe add a helper method for this conversion if also needed 1079 // in other places? This might require a ExternalPointerTable::Get variant 1080 // that drops the pointer tag completely. 1081 uint32_t index = ptr >> kExternalPointerIndexShift; 1082 Address value = 1083 isolate()->external_pointer_table().Get(index, kExternalObjectValueTag); 1084#else 1085 Address value = ptr; 1086#endif 1087 // TODO(v8:12700) should we specify here whether we expect the references to 1088 // be internal or external (or either)? 1089 OutputExternalReference(value, kSystemPointerSize, true, 1090 kExternalObjectValueTag); 1091 bytes_processed_so_far_ += kExternalPointerSize; 1092 } 1093} 1094 1095void Serializer::ObjectSerializer::VisitInternalReference(Code host, 1096 RelocInfo* rinfo) { 1097 Address entry = Handle<Code>::cast(object_)->entry(); 1098 DCHECK_GE(rinfo->target_internal_reference(), entry); 1099 uintptr_t target_offset = rinfo->target_internal_reference() - entry; 1100 // TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but 1101 // consider using raw_instruction_size() instead of raw_body_size() in the 1102 // future. 1103 STATIC_ASSERT(Code::kOnHeapBodyIsContiguous); 1104 DCHECK_LE(target_offset, Handle<Code>::cast(object_)->raw_body_size()); 1105 sink_->Put(kInternalReference, "InternalRef"); 1106 sink_->PutInt(target_offset, "internal ref value"); 1107} 1108 1109void Serializer::ObjectSerializer::VisitRuntimeEntry(Code host, 1110 RelocInfo* rinfo) { 1111 // We no longer serialize code that contains runtime entries. 1112 UNREACHABLE(); 1113} 1114 1115void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host, 1116 RelocInfo* rinfo) { 1117 STATIC_ASSERT(EmbeddedData::kTableSize == Builtins::kBuiltinCount); 1118 1119 Address addr = rinfo->target_off_heap_target(); 1120 CHECK_NE(kNullAddress, addr); 1121 1122 Builtin builtin = OffHeapInstructionStream::TryLookupCode(isolate(), addr); 1123 CHECK(Builtins::IsBuiltinId(builtin)); 1124 CHECK(Builtins::IsIsolateIndependent(builtin)); 1125 1126 sink_->Put(kOffHeapTarget, "OffHeapTarget"); 1127 sink_->PutInt(static_cast<int>(builtin), "builtin index"); 1128} 1129 1130void Serializer::ObjectSerializer::VisitCodeTarget(Code host, 1131 RelocInfo* rinfo) { 1132 // Target object should be pre-serialized by RelocInfoObjectPreSerializer, so 1133 // just track the pointer's existence as kTaggedSize in 1134 // bytes_processed_so_far_. 1135 // TODO(leszeks): DCHECK that RelocInfoObjectPreSerializer serialized this 1136 // specific object already. 1137 bytes_processed_so_far_ += kTaggedSize; 1138} 1139 1140namespace { 1141 1142// Similar to OutputRawData, but substitutes the given field with the given 1143// value instead of reading it from the object. 1144void OutputRawWithCustomField(SnapshotByteSink* sink, Address object_start, 1145 int written_so_far, int bytes_to_write, 1146 int field_offset, int field_size, 1147 const byte* field_value) { 1148 int offset = field_offset - written_so_far; 1149 if (0 <= offset && offset < bytes_to_write) { 1150 DCHECK_GE(bytes_to_write, offset + field_size); 1151 sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far), offset, 1152 "Bytes"); 1153 sink->PutRaw(field_value, field_size, "Bytes"); 1154 written_so_far += offset + field_size; 1155 bytes_to_write -= offset + field_size; 1156 sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far), 1157 bytes_to_write, "Bytes"); 1158 } else { 1159 sink->PutRaw(reinterpret_cast<byte*>(object_start + written_so_far), 1160 bytes_to_write, "Bytes"); 1161 } 1162} 1163} // anonymous namespace 1164 1165void Serializer::ObjectSerializer::OutputRawData(Address up_to) { 1166 Address object_start = object_->address(); 1167 int base = bytes_processed_so_far_; 1168 int up_to_offset = static_cast<int>(up_to - object_start); 1169 int to_skip = up_to_offset - bytes_processed_so_far_; 1170 int bytes_to_output = to_skip; 1171 DCHECK(IsAligned(bytes_to_output, kTaggedSize)); 1172 int tagged_to_output = bytes_to_output / kTaggedSize; 1173 bytes_processed_so_far_ += to_skip; 1174 DCHECK_GE(to_skip, 0); 1175 if (bytes_to_output != 0) { 1176 DCHECK(to_skip == bytes_to_output); 1177 if (tagged_to_output <= kFixedRawDataCount) { 1178 sink_->Put(FixedRawDataWithSize::Encode(tagged_to_output), 1179 "FixedRawData"); 1180 } else { 1181 sink_->Put(kVariableRawData, "VariableRawData"); 1182 sink_->PutInt(tagged_to_output, "length"); 1183 } 1184#ifdef MEMORY_SANITIZER 1185 // Check that we do not serialize uninitialized memory. 1186 __msan_check_mem_is_initialized( 1187 reinterpret_cast<void*>(object_start + base), bytes_to_output); 1188#endif // MEMORY_SANITIZER 1189 PtrComprCageBase cage_base(isolate_); 1190 if (object_->IsBytecodeArray(cage_base)) { 1191 // The bytecode age field can be changed by GC concurrently. 1192 static_assert(BytecodeArray::kBytecodeAgeSize == kUInt16Size); 1193 uint16_t field_value = BytecodeArray::kNoAgeBytecodeAge; 1194 OutputRawWithCustomField(sink_, object_start, base, bytes_to_output, 1195 BytecodeArray::kBytecodeAgeOffset, 1196 sizeof(field_value), 1197 reinterpret_cast<byte*>(&field_value)); 1198 } else if (object_->IsDescriptorArray(cage_base)) { 1199 // The number of marked descriptors field can be changed by GC 1200 // concurrently. 1201 static byte field_value[2] = {0}; 1202 OutputRawWithCustomField( 1203 sink_, object_start, base, bytes_to_output, 1204 DescriptorArray::kRawNumberOfMarkedDescriptorsOffset, 1205 sizeof(field_value), field_value); 1206 } else if (V8_EXTERNAL_CODE_SPACE_BOOL && 1207 object_->IsCodeDataContainer(cage_base)) { 1208 // code_cage_base and code_entry_point fields contain raw values that 1209 // will be recomputed after deserialization, so write zeros to keep the 1210 // snapshot deterministic. 1211 CHECK_EQ(CodeDataContainer::kCodeCageBaseUpper32BitsOffset + kTaggedSize, 1212 CodeDataContainer::kCodeEntryPointOffset); 1213 static byte field_value[kTaggedSize + kExternalPointerSize] = {0}; 1214 OutputRawWithCustomField( 1215 sink_, object_start, base, bytes_to_output, 1216 CodeDataContainer::kCodeCageBaseUpper32BitsOffset, 1217 sizeof(field_value), field_value); 1218 } else { 1219 sink_->PutRaw(reinterpret_cast<byte*>(object_start + base), 1220 bytes_to_output, "Bytes"); 1221 } 1222 } 1223} 1224 1225void Serializer::ObjectSerializer::SerializeCode(Map map, int size) { 1226 static const int kWipeOutModeMask = 1227 RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | 1228 RelocInfo::ModeMask(RelocInfo::FULL_EMBEDDED_OBJECT) | 1229 RelocInfo::ModeMask(RelocInfo::COMPRESSED_EMBEDDED_OBJECT) | 1230 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | 1231 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 1232 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | 1233 RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) | 1234 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY); 1235 1236 DCHECK_EQ(HeapObject::kHeaderSize, bytes_processed_so_far_); 1237 Handle<Code> on_heap_code = Handle<Code>::cast(object_); 1238 1239 // With enabled pointer compression normal accessors no longer work for 1240 // off-heap objects, so we have to get the relocation info data via the 1241 // on-heap code object. 1242 ByteArray relocation_info = on_heap_code->unchecked_relocation_info(); 1243 1244 // To make snapshots reproducible, we make a copy of the code object 1245 // and wipe all pointers in the copy, which we then serialize. 1246 Code off_heap_code = serializer_->CopyCode(*on_heap_code); 1247 for (RelocIterator it(off_heap_code, relocation_info, kWipeOutModeMask); 1248 !it.done(); it.next()) { 1249 RelocInfo* rinfo = it.rinfo(); 1250 rinfo->WipeOut(); 1251 } 1252 // We need to wipe out the header fields *after* wiping out the 1253 // relocations, because some of these fields are needed for the latter. 1254 off_heap_code.WipeOutHeader(); 1255 1256 // Initially skip serializing the code header. We'll serialize it after the 1257 // Code body, so that the various fields the Code needs for iteration are 1258 // already valid. 1259 sink_->Put(kCodeBody, "kCodeBody"); 1260 1261 // Now serialize the wiped off-heap Code, as length + data. 1262 Address start = off_heap_code.address() + Code::kDataStart; 1263 int bytes_to_output = size - Code::kDataStart; 1264 DCHECK(IsAligned(bytes_to_output, kTaggedSize)); 1265 int tagged_to_output = bytes_to_output / kTaggedSize; 1266 1267 sink_->PutInt(tagged_to_output, "length"); 1268 1269#ifdef MEMORY_SANITIZER 1270 // Check that we do not serialize uninitialized memory. 1271 __msan_check_mem_is_initialized(reinterpret_cast<void*>(start), 1272 bytes_to_output); 1273#endif // MEMORY_SANITIZER 1274 sink_->PutRaw(reinterpret_cast<byte*>(start), bytes_to_output, "Code"); 1275 1276 // Manually serialize the code header. We don't use Code::BodyDescriptor 1277 // here as we don't yet want to walk the RelocInfos. 1278 DCHECK_EQ(HeapObject::kHeaderSize, bytes_processed_so_far_); 1279 VisitPointers(*on_heap_code, on_heap_code->RawField(HeapObject::kHeaderSize), 1280 on_heap_code->RawField(Code::kDataStart)); 1281 DCHECK_EQ(bytes_processed_so_far_, Code::kDataStart); 1282 1283 // Now serialize RelocInfos. We can't allocate during a RelocInfo walk during 1284 // deserualization, so we have two passes for RelocInfo serialization: 1285 // 1. A pre-serializer which serializes all allocatable objects in the 1286 // RelocInfo, followed by a kSynchronize bytecode, and 1287 // 2. A walk the RelocInfo with this serializer, serializing any objects 1288 // implicitly as offsets into the pre-serializer's object array. 1289 // This way, the deserializer can deserialize the allocatable objects first, 1290 // without walking RelocInfo, re-build the pre-serializer's object array, and 1291 // only then walk the RelocInfo itself. 1292 // TODO(leszeks): We only really need to pre-serialize objects which need 1293 // serialization, i.e. no backrefs or roots. 1294 RelocInfoObjectPreSerializer pre_serializer(serializer_); 1295 for (RelocIterator it(*on_heap_code, relocation_info, 1296 Code::BodyDescriptor::kRelocModeMask); 1297 !it.done(); it.next()) { 1298 it.rinfo()->Visit(&pre_serializer); 1299 } 1300 // Mark that the pre-serialization finished with a kSynchronize bytecode. 1301 sink_->Put(kSynchronize, "PreSerializationFinished"); 1302 1303 // Finally serialize all RelocInfo objects in the on-heap Code, knowing that 1304 // we will not do a recursive serialization. 1305 // TODO(leszeks): Add a scope that DCHECKs this. 1306 for (RelocIterator it(*on_heap_code, relocation_info, 1307 Code::BodyDescriptor::kRelocModeMask); 1308 !it.done(); it.next()) { 1309 it.rinfo()->Visit(this); 1310 } 1311 1312 // We record a kTaggedSize for every object encountered during the 1313 // serialization, so DCHECK that bytes_processed_so_far_ matches the expected 1314 // number of bytes (i.e. the code header + a tagged size per pre-serialized 1315 // object). 1316 DCHECK_EQ( 1317 bytes_processed_so_far_, 1318 Code::kDataStart + kTaggedSize * pre_serializer.num_serialized_objects()); 1319} 1320 1321Serializer::HotObjectsList::HotObjectsList(Heap* heap) : heap_(heap) { 1322 strong_roots_entry_ = heap->RegisterStrongRoots( 1323 "Serializer::HotObjectsList", FullObjectSlot(&circular_queue_[0]), 1324 FullObjectSlot(&circular_queue_[kSize])); 1325} 1326Serializer::HotObjectsList::~HotObjectsList() { 1327 heap_->UnregisterStrongRoots(strong_roots_entry_); 1328} 1329 1330Handle<FixedArray> ObjectCacheIndexMap::Values(Isolate* isolate) { 1331 if (size() == 0) { 1332 return isolate->factory()->empty_fixed_array(); 1333 } 1334 Handle<FixedArray> externals = isolate->factory()->NewFixedArray(size()); 1335 DisallowGarbageCollection no_gc; 1336 FixedArray raw = *externals; 1337 IdentityMap<int, base::DefaultAllocationPolicy>::IteratableScope it_scope( 1338 &map_); 1339 for (auto it = it_scope.begin(); it != it_scope.end(); ++it) { 1340 raw.set(*it.entry(), it.key()); 1341 } 1342 1343 return externals; 1344} 1345 1346} // namespace internal 1347} // namespace v8 1348