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/deserializer.h" 6 7#include "src/base/logging.h" 8#include "src/base/platform/wrappers.h" 9#include "src/codegen/assembler-inl.h" 10#include "src/common/assert-scope.h" 11#include "src/common/globals.h" 12#include "src/execution/isolate.h" 13#include "src/heap/heap-inl.h" 14#include "src/heap/heap-write-barrier-inl.h" 15#include "src/heap/heap-write-barrier.h" 16#include "src/heap/heap.h" 17#include "src/heap/local-heap-inl.h" 18#include "src/heap/read-only-heap.h" 19#include "src/interpreter/interpreter.h" 20#include "src/logging/local-logger.h" 21#include "src/logging/log.h" 22#include "src/objects/api-callbacks.h" 23#include "src/objects/backing-store.h" 24#include "src/objects/cell-inl.h" 25#include "src/objects/embedder-data-array-inl.h" 26#include "src/objects/hash-table.h" 27#include "src/objects/js-array-buffer-inl.h" 28#include "src/objects/js-array-inl.h" 29#include "src/objects/maybe-object.h" 30#include "src/objects/objects-body-descriptors-inl.h" 31#include "src/objects/objects.h" 32#include "src/objects/slots.h" 33#include "src/objects/string.h" 34#include "src/roots/roots.h" 35#include "src/sandbox/external-pointer.h" 36#include "src/snapshot/embedded/embedded-data-inl.h" 37#include "src/snapshot/references.h" 38#include "src/snapshot/serializer-deserializer.h" 39#include "src/snapshot/shared-heap-serializer.h" 40#include "src/snapshot/snapshot-data.h" 41#include "src/snapshot/snapshot.h" 42#include "src/tracing/trace-event.h" 43#include "src/tracing/traced-value.h" 44#include "src/utils/memcopy.h" 45 46namespace v8 { 47namespace internal { 48 49// A SlotAccessor for a slot in a HeapObject, which abstracts the slot 50// operations done by the deserializer in a way which is GC-safe. In particular, 51// rather than an absolute slot address, this accessor holds a Handle to the 52// HeapObject, which is updated if the HeapObject moves. 53class SlotAccessorForHeapObject { 54 public: 55 static SlotAccessorForHeapObject ForSlotIndex(Handle<HeapObject> object, 56 int index) { 57 return SlotAccessorForHeapObject(object, index * kTaggedSize); 58 } 59 static SlotAccessorForHeapObject ForSlotOffset(Handle<HeapObject> object, 60 int offset) { 61 return SlotAccessorForHeapObject(object, offset); 62 } 63 64 MaybeObjectSlot slot() const { return object_->RawMaybeWeakField(offset_); } 65 Handle<HeapObject> object() const { return object_; } 66 int offset() const { return offset_; } 67 68 // Writes the given value to this slot, optionally with an offset (e.g. for 69 // repeat writes). Returns the number of slots written (which is one). 70 int Write(MaybeObject value, int slot_offset = 0) { 71 MaybeObjectSlot current_slot = slot() + slot_offset; 72 current_slot.Relaxed_Store(value); 73 WriteBarrier::Marking(*object_, current_slot, value); 74 // No need for a generational write barrier. 75 DCHECK(!Heap::InYoungGeneration(value)); 76 return 1; 77 } 78 int Write(HeapObject value, HeapObjectReferenceType ref_type, 79 int slot_offset = 0) { 80 return Write(HeapObjectReference::From(value, ref_type), slot_offset); 81 } 82 int Write(Handle<HeapObject> value, HeapObjectReferenceType ref_type, 83 int slot_offset = 0) { 84 return Write(*value, ref_type, slot_offset); 85 } 86 87 // Same as Write, but additionally with a generational barrier. 88 int WriteWithGenerationalBarrier(MaybeObject value) { 89 MaybeObjectSlot current_slot = slot(); 90 current_slot.Relaxed_Store(value); 91 WriteBarrier::Marking(*object_, current_slot, value); 92 if (Heap::InYoungGeneration(value)) { 93 GenerationalBarrier(*object_, current_slot, value); 94 } 95 return 1; 96 } 97 int WriteWithGenerationalBarrier(HeapObject value, 98 HeapObjectReferenceType ref_type) { 99 return WriteWithGenerationalBarrier( 100 HeapObjectReference::From(value, ref_type)); 101 } 102 int WriteWithGenerationalBarrier(Handle<HeapObject> value, 103 HeapObjectReferenceType ref_type) { 104 return WriteWithGenerationalBarrier(*value, ref_type); 105 } 106 107 private: 108 SlotAccessorForHeapObject(Handle<HeapObject> object, int offset) 109 : object_(object), offset_(offset) {} 110 111 const Handle<HeapObject> object_; 112 const int offset_; 113}; 114 115// A SlotAccessor for absolute full slot addresses. 116class SlotAccessorForRootSlots { 117 public: 118 explicit SlotAccessorForRootSlots(FullMaybeObjectSlot slot) : slot_(slot) {} 119 120 FullMaybeObjectSlot slot() const { return slot_; } 121 Handle<HeapObject> object() const { UNREACHABLE(); } 122 int offset() const { UNREACHABLE(); } 123 124 // Writes the given value to this slot, optionally with an offset (e.g. for 125 // repeat writes). Returns the number of slots written (which is one). 126 int Write(MaybeObject value, int slot_offset = 0) { 127 FullMaybeObjectSlot current_slot = slot() + slot_offset; 128 current_slot.Relaxed_Store(value); 129 return 1; 130 } 131 int Write(HeapObject value, HeapObjectReferenceType ref_type, 132 int slot_offset = 0) { 133 return Write(HeapObjectReference::From(value, ref_type), slot_offset); 134 } 135 int Write(Handle<HeapObject> value, HeapObjectReferenceType ref_type, 136 int slot_offset = 0) { 137 return Write(*value, ref_type, slot_offset); 138 } 139 140 int WriteWithGenerationalBarrier(MaybeObject value) { return Write(value); } 141 int WriteWithGenerationalBarrier(HeapObject value, 142 HeapObjectReferenceType ref_type) { 143 return WriteWithGenerationalBarrier( 144 HeapObjectReference::From(value, ref_type)); 145 } 146 int WriteWithGenerationalBarrier(Handle<HeapObject> value, 147 HeapObjectReferenceType ref_type) { 148 return WriteWithGenerationalBarrier(*value, ref_type); 149 } 150 151 private: 152 const FullMaybeObjectSlot slot_; 153}; 154 155// A SlotAccessor for creating a Handle, which saves a Handle allocation when 156// a Handle already exists. 157template <typename IsolateT> 158class SlotAccessorForHandle { 159 public: 160 SlotAccessorForHandle(Handle<HeapObject>* handle, IsolateT* isolate) 161 : handle_(handle), isolate_(isolate) {} 162 163 MaybeObjectSlot slot() const { UNREACHABLE(); } 164 Handle<HeapObject> object() const { UNREACHABLE(); } 165 int offset() const { UNREACHABLE(); } 166 167 int Write(MaybeObject value, int slot_offset = 0) { UNREACHABLE(); } 168 int Write(HeapObject value, HeapObjectReferenceType ref_type, 169 int slot_offset = 0) { 170 DCHECK_EQ(slot_offset, 0); 171 DCHECK_EQ(ref_type, HeapObjectReferenceType::STRONG); 172 *handle_ = handle(value, isolate_); 173 return 1; 174 } 175 int Write(Handle<HeapObject> value, HeapObjectReferenceType ref_type, 176 int slot_offset = 0) { 177 DCHECK_EQ(slot_offset, 0); 178 DCHECK_EQ(ref_type, HeapObjectReferenceType::STRONG); 179 *handle_ = value; 180 return 1; 181 } 182 183 int WriteWithGenerationalBarrier(HeapObject value, 184 HeapObjectReferenceType ref_type) { 185 return Write(value, ref_type); 186 } 187 int WriteWithGenerationalBarrier(Handle<HeapObject> value, 188 HeapObjectReferenceType ref_type) { 189 return Write(value, ref_type); 190 } 191 192 private: 193 Handle<HeapObject>* handle_; 194 IsolateT* isolate_; 195}; 196 197template <typename IsolateT> 198template <typename TSlot> 199int Deserializer<IsolateT>::WriteAddress(TSlot dest, Address value) { 200 DCHECK(!next_reference_is_weak_); 201 memcpy(dest.ToVoidPtr(), &value, kSystemPointerSize); 202 STATIC_ASSERT(IsAligned(kSystemPointerSize, TSlot::kSlotDataSize)); 203 return (kSystemPointerSize / TSlot::kSlotDataSize); 204} 205 206template <typename IsolateT> 207template <typename TSlot> 208int Deserializer<IsolateT>::WriteExternalPointer(TSlot dest, Address value, 209 ExternalPointerTag tag) { 210 DCHECK(!next_reference_is_weak_); 211 DCHECK(IsAligned(kExternalPointerSize, TSlot::kSlotDataSize)); 212 InitExternalPointerField(dest.address(), main_thread_isolate(), value, tag); 213 return (kExternalPointerSize / TSlot::kSlotDataSize); 214} 215 216namespace { 217#ifdef DEBUG 218int GetNumApiReferences(Isolate* isolate) { 219 int num_api_references = 0; 220 // The read-only deserializer is run by read-only heap set-up before the 221 // heap is fully set up. External reference table relies on a few parts of 222 // this set-up (like old-space), so it may be uninitialized at this point. 223 if (isolate->isolate_data()->external_reference_table()->is_initialized()) { 224 // Count the number of external references registered through the API. 225 if (isolate->api_external_references() != nullptr) { 226 while (isolate->api_external_references()[num_api_references] != 0) { 227 num_api_references++; 228 } 229 } 230 } 231 return num_api_references; 232} 233int GetNumApiReferences(LocalIsolate* isolate) { return 0; } 234#endif 235} // namespace 236 237template <typename IsolateT> 238Deserializer<IsolateT>::Deserializer(IsolateT* isolate, 239 base::Vector<const byte> payload, 240 uint32_t magic_number, 241 bool deserializing_user_code, 242 bool can_rehash) 243 : isolate_(isolate), 244 source_(payload), 245 magic_number_(magic_number), 246 deserializing_user_code_(deserializing_user_code), 247 should_rehash_((FLAG_rehash_snapshot && can_rehash) || 248 deserializing_user_code) { 249 DCHECK_NOT_NULL(isolate); 250 isolate->RegisterDeserializerStarted(); 251 252 // We start the indices here at 1, so that we can distinguish between an 253 // actual index and an empty backing store (serialized as 254 // kEmptyBackingStoreRefSentinel) in a deserialized object requiring fix-up. 255 STATIC_ASSERT(kEmptyBackingStoreRefSentinel == 0); 256 backing_stores_.push_back({}); 257 258#ifdef DEBUG 259 num_api_references_ = GetNumApiReferences(isolate); 260#endif // DEBUG 261 CHECK_EQ(magic_number_, SerializedData::kMagicNumber); 262} 263 264template <typename IsolateT> 265void Deserializer<IsolateT>::Rehash() { 266 DCHECK(should_rehash()); 267 for (Handle<HeapObject> item : to_rehash_) { 268 item->RehashBasedOnMap(isolate()); 269 } 270} 271 272template <typename IsolateT> 273Deserializer<IsolateT>::~Deserializer() { 274#ifdef DEBUG 275 // Do not perform checks if we aborted deserialization. 276 if (source_.position() == 0) return; 277 // Check that we only have padding bytes remaining. 278 while (source_.HasMore()) DCHECK_EQ(kNop, source_.Get()); 279 // Check that there are no remaining forward refs. 280 DCHECK_EQ(num_unresolved_forward_refs_, 0); 281 DCHECK(unresolved_forward_refs_.empty()); 282#endif // DEBUG 283 isolate_->RegisterDeserializerFinished(); 284} 285 286// This is called on the roots. It is the driver of the deserialization 287// process. It is also called on the body of each function. 288template <typename IsolateT> 289void Deserializer<IsolateT>::VisitRootPointers(Root root, 290 const char* description, 291 FullObjectSlot start, 292 FullObjectSlot end) { 293 ReadData(FullMaybeObjectSlot(start), FullMaybeObjectSlot(end)); 294} 295 296template <typename IsolateT> 297void Deserializer<IsolateT>::Synchronize(VisitorSynchronization::SyncTag tag) { 298 static const byte expected = kSynchronize; 299 CHECK_EQ(expected, source_.Get()); 300} 301 302template <typename IsolateT> 303void Deserializer<IsolateT>::DeserializeDeferredObjects() { 304 for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) { 305 SnapshotSpace space = NewObject::Decode(code); 306 ReadObject(space); 307 } 308} 309 310template <typename IsolateT> 311void Deserializer<IsolateT>::LogNewMapEvents() { 312 if (V8_LIKELY(!FLAG_log_maps)) return; 313 DisallowGarbageCollection no_gc; 314 for (Handle<Map> map : new_maps_) { 315 DCHECK(FLAG_log_maps); 316 LOG(isolate(), MapCreate(*map)); 317 LOG(isolate(), MapDetails(*map)); 318 } 319} 320 321template <typename IsolateT> 322void Deserializer<IsolateT>::WeakenDescriptorArrays() { 323 DisallowGarbageCollection no_gc; 324 Map descriptor_array_map = ReadOnlyRoots(isolate()).descriptor_array_map(); 325 for (Handle<DescriptorArray> descriptor_array : new_descriptor_arrays_) { 326 DescriptorArray raw = *descriptor_array; 327 DCHECK(raw.IsStrongDescriptorArray()); 328 raw.set_map_safe_transition(descriptor_array_map); 329 WriteBarrier::Marking(raw, raw.number_of_descriptors()); 330 } 331} 332 333template <typename IsolateT> 334void Deserializer<IsolateT>::LogScriptEvents(Script script) { 335 DisallowGarbageCollection no_gc; 336 LOG(isolate(), 337 ScriptEvent(Logger::ScriptEventType::kDeserialize, script.id())); 338 LOG(isolate(), ScriptDetails(script)); 339} 340 341namespace { 342template <typename IsolateT> 343uint32_t ComputeRawHashField(IsolateT* isolate, String string) { 344 // Make sure raw_hash_field() is computed. 345 string.EnsureHash(SharedStringAccessGuardIfNeeded(isolate)); 346 return string.raw_hash_field(); 347} 348} // namespace 349 350StringTableInsertionKey::StringTableInsertionKey( 351 Isolate* isolate, Handle<String> string, 352 DeserializingUserCodeOption deserializing_user_code) 353 : StringTableKey(ComputeRawHashField(isolate, *string), string->length()), 354 string_(string) { 355#ifdef DEBUG 356 deserializing_user_code_ = deserializing_user_code; 357#endif 358 DCHECK(string->IsInternalizedString()); 359} 360 361StringTableInsertionKey::StringTableInsertionKey( 362 LocalIsolate* isolate, Handle<String> string, 363 DeserializingUserCodeOption deserializing_user_code) 364 : StringTableKey(ComputeRawHashField(isolate, *string), string->length()), 365 string_(string) { 366#ifdef DEBUG 367 deserializing_user_code_ = deserializing_user_code; 368#endif 369 DCHECK(string->IsInternalizedString()); 370} 371 372template <typename IsolateT> 373bool StringTableInsertionKey::IsMatch(IsolateT* isolate, String string) { 374 // We want to compare the content of two strings here. 375 return string_->SlowEquals(string, SharedStringAccessGuardIfNeeded(isolate)); 376} 377template bool StringTableInsertionKey::IsMatch(Isolate* isolate, String string); 378template bool StringTableInsertionKey::IsMatch(LocalIsolate* isolate, 379 String string); 380 381namespace { 382 383void NoExternalReferencesCallback() { 384 // The following check will trigger if a function or object template 385 // with references to native functions have been deserialized from 386 // snapshot, but no actual external references were provided when the 387 // isolate was created. 388 FATAL("No external references provided via API"); 389} 390 391void PostProcessExternalString(ExternalString string, Isolate* isolate) { 392 DisallowGarbageCollection no_gc; 393 uint32_t index = string.GetResourceRefForDeserialization(); 394 Address address = 395 static_cast<Address>(isolate->api_external_references()[index]); 396 string.AllocateExternalPointerEntries(isolate); 397 string.set_address_as_resource(isolate, address); 398 isolate->heap()->UpdateExternalString(string, 0, 399 string.ExternalPayloadSize()); 400 isolate->heap()->RegisterExternalString(string); 401} 402 403} // namespace 404 405template <typename IsolateT> 406void Deserializer<IsolateT>::PostProcessNewJSReceiver( 407 Map map, Handle<JSReceiver> obj, JSReceiver raw_obj, 408 InstanceType instance_type, SnapshotSpace space) { 409 DisallowGarbageCollection no_gc; 410 DCHECK_EQ(*obj, raw_obj); 411 DCHECK_EQ(raw_obj.map(), map); 412 DCHECK_EQ(map.instance_type(), instance_type); 413 414 if (InstanceTypeChecker::IsJSDataView(instance_type)) { 415 auto data_view = JSDataView::cast(raw_obj); 416 auto buffer = JSArrayBuffer::cast(data_view.buffer()); 417 void* backing_store = EmptyBackingStoreBuffer(); 418 uint32_t store_index = buffer.GetBackingStoreRefForDeserialization(); 419 if (store_index != kEmptyBackingStoreRefSentinel) { 420 // The backing store of the JSArrayBuffer has not been correctly restored 421 // yet, as that may trigger GC. The backing_store field currently contains 422 // a numbered reference to an already deserialized backing store. 423 backing_store = backing_stores_[store_index]->buffer_start(); 424 } 425 data_view.set_data_pointer( 426 main_thread_isolate(), 427 reinterpret_cast<uint8_t*>(backing_store) + data_view.byte_offset()); 428 } else if (InstanceTypeChecker::IsJSTypedArray(instance_type)) { 429 auto typed_array = JSTypedArray::cast(raw_obj); 430 // Note: ByteArray objects must not be deferred s.t. they are 431 // available here for is_on_heap(). See also: CanBeDeferred. 432 // Fixup typed array pointers. 433 if (typed_array.is_on_heap()) { 434 typed_array.AddExternalPointerCompensationForDeserialization( 435 main_thread_isolate()); 436 } else { 437 // Serializer writes backing store ref as a DataPtr() value. 438 uint32_t store_index = 439 typed_array.GetExternalBackingStoreRefForDeserialization(); 440 auto backing_store = backing_stores_[store_index]; 441 void* start = backing_store ? backing_store->buffer_start() 442 : EmptyBackingStoreBuffer(); 443 typed_array.SetOffHeapDataPtr(main_thread_isolate(), start, 444 typed_array.byte_offset()); 445 } 446 } else if (InstanceTypeChecker::IsJSArrayBuffer(instance_type)) { 447 auto buffer = JSArrayBuffer::cast(raw_obj); 448 // Postpone allocation of backing store to avoid triggering the GC. 449 if (buffer.GetBackingStoreRefForDeserialization() != 450 kEmptyBackingStoreRefSentinel) { 451 new_off_heap_array_buffers_.push_back(Handle<JSArrayBuffer>::cast(obj)); 452 } else { 453 buffer.set_backing_store(main_thread_isolate(), 454 EmptyBackingStoreBuffer()); 455 } 456 } 457 458 // Check alignment. 459 DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), 460 HeapObject::RequiredAlignment(map))); 461} 462 463template <typename IsolateT> 464void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map, 465 Handle<HeapObject> obj, 466 SnapshotSpace space) { 467 DisallowGarbageCollection no_gc; 468 Map raw_map = *map; 469 DCHECK_EQ(raw_map, obj->map(isolate_)); 470 InstanceType instance_type = raw_map.instance_type(); 471 472 // Check alignment. 473 DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), 474 HeapObject::RequiredAlignment(raw_map))); 475 HeapObject raw_obj = *obj; 476 DCHECK_IMPLIES(deserializing_user_code(), should_rehash()); 477 if (should_rehash()) { 478 if (InstanceTypeChecker::IsString(instance_type)) { 479 // Uninitialize hash field as we need to recompute the hash. 480 String string = String::cast(raw_obj); 481 string.set_raw_hash_field(String::kEmptyHashField); 482 // Rehash strings before read-only space is sealed. Strings outside 483 // read-only space are rehashed lazily. (e.g. when rehashing dictionaries) 484 if (space == SnapshotSpace::kReadOnlyHeap) { 485 to_rehash_.push_back(obj); 486 } 487 } else if (raw_obj.NeedsRehashing(instance_type)) { 488 to_rehash_.push_back(obj); 489 } 490 491 if (deserializing_user_code()) { 492 if (InstanceTypeChecker::IsInternalizedString(instance_type)) { 493 // Canonicalize the internalized string. If it already exists in the 494 // string table, set the string to point to the existing one and patch 495 // the deserialized string handle to point to the existing one. 496 // TODO(leszeks): This handle patching is ugly, consider adding an 497 // explicit internalized string bytecode. Also, the new thin string 498 // should be dead, try immediately freeing it. 499 Handle<String> string = Handle<String>::cast(obj); 500 501 StringTableInsertionKey key( 502 isolate(), string, 503 DeserializingUserCodeOption::kIsDeserializingUserCode); 504 String result = *isolate()->string_table()->LookupKey(isolate(), &key); 505 506 if (result != raw_obj) { 507 String::cast(raw_obj).MakeThin(isolate(), result); 508 // Mutate the given object handle so that the backreference entry is 509 // also updated. 510 obj.PatchValue(result); 511 } 512 return; 513 } else if (InstanceTypeChecker::IsScript(instance_type)) { 514 new_scripts_.push_back(Handle<Script>::cast(obj)); 515 } else if (InstanceTypeChecker::IsAllocationSite(instance_type)) { 516 // We should link new allocation sites, but we can't do this immediately 517 // because |AllocationSite::HasWeakNext()| internally accesses 518 // |Heap::roots_| that may not have been initialized yet. So defer this 519 // to |ObjectDeserializer::CommitPostProcessedObjects()|. 520 new_allocation_sites_.push_back(Handle<AllocationSite>::cast(obj)); 521 } else { 522 // We dont defer ByteArray because JSTypedArray needs the base_pointer 523 // ByteArray immediately if it's on heap. 524 DCHECK(CanBeDeferred(*obj) || 525 InstanceTypeChecker::IsByteArray(instance_type)); 526 } 527 } 528 } 529 530 if (InstanceTypeChecker::IsCode(instance_type)) { 531 // We flush all code pages after deserializing the startup snapshot. 532 // Hence we only remember each individual code object when deserializing 533 // user code. 534 if (deserializing_user_code()) { 535 new_code_objects_.push_back(Handle<Code>::cast(obj)); 536 } 537 } else if (V8_EXTERNAL_CODE_SPACE_BOOL && 538 InstanceTypeChecker::IsCodeDataContainer(instance_type)) { 539 auto code_data_container = CodeDataContainer::cast(raw_obj); 540 code_data_container.set_code_cage_base(isolate()->code_cage_base()); 541 code_data_container.AllocateExternalPointerEntries(main_thread_isolate()); 542 code_data_container.UpdateCodeEntryPoint(main_thread_isolate(), 543 code_data_container.code()); 544 } else if (InstanceTypeChecker::IsMap(instance_type)) { 545 if (FLAG_log_maps) { 546 // Keep track of all seen Maps to log them later since they might be only 547 // partially initialized at this point. 548 new_maps_.push_back(Handle<Map>::cast(obj)); 549 } 550 } else if (InstanceTypeChecker::IsAccessorInfo(instance_type)) { 551#ifdef USE_SIMULATOR 552 accessor_infos_.push_back(Handle<AccessorInfo>::cast(obj)); 553#endif 554 } else if (InstanceTypeChecker::IsCallHandlerInfo(instance_type)) { 555#ifdef USE_SIMULATOR 556 call_handler_infos_.push_back(Handle<CallHandlerInfo>::cast(obj)); 557#endif 558 } else if (InstanceTypeChecker::IsExternalString(instance_type)) { 559 PostProcessExternalString(ExternalString::cast(raw_obj), 560 main_thread_isolate()); 561 } else if (InstanceTypeChecker::IsJSReceiver(instance_type)) { 562 return PostProcessNewJSReceiver(raw_map, Handle<JSReceiver>::cast(obj), 563 JSReceiver::cast(raw_obj), instance_type, 564 space); 565 } else if (InstanceTypeChecker::IsBytecodeArray(instance_type)) { 566 // TODO(mythria): Remove these once we store the default values for these 567 // fields in the serializer. 568 BytecodeArray::cast(raw_obj).reset_osr_urgency(); 569 } else if (InstanceTypeChecker::IsDescriptorArray(instance_type)) { 570 DCHECK(InstanceTypeChecker::IsStrongDescriptorArray(instance_type)); 571 Handle<DescriptorArray> descriptors = Handle<DescriptorArray>::cast(obj); 572 new_descriptor_arrays_.push_back(descriptors); 573 } else if (InstanceTypeChecker::IsNativeContext(instance_type)) { 574 NativeContext::cast(raw_obj).AllocateExternalPointerEntries( 575 main_thread_isolate()); 576 } else if (InstanceTypeChecker::IsScript(instance_type)) { 577 LogScriptEvents(Script::cast(*obj)); 578 } 579} 580 581template <typename IsolateT> 582HeapObjectReferenceType Deserializer<IsolateT>::GetAndResetNextReferenceType() { 583 HeapObjectReferenceType type = next_reference_is_weak_ 584 ? HeapObjectReferenceType::WEAK 585 : HeapObjectReferenceType::STRONG; 586 next_reference_is_weak_ = false; 587 return type; 588} 589 590template <typename IsolateT> 591Handle<HeapObject> Deserializer<IsolateT>::GetBackReferencedObject() { 592 Handle<HeapObject> obj = back_refs_[source_.GetInt()]; 593 594 // We don't allow ThinStrings in backreferences -- if internalization produces 595 // a thin string, then it should also update the backref handle. 596 DCHECK(!obj->IsThinString(isolate())); 597 598 hot_objects_.Add(obj); 599 DCHECK(!HasWeakHeapObjectTag(*obj)); 600 return obj; 601} 602 603template <typename IsolateT> 604Handle<HeapObject> Deserializer<IsolateT>::ReadObject() { 605 Handle<HeapObject> ret; 606 CHECK_EQ(ReadSingleBytecodeData( 607 source_.Get(), SlotAccessorForHandle<IsolateT>(&ret, isolate())), 608 1); 609 return ret; 610} 611 612namespace { 613AllocationType SpaceToAllocation(SnapshotSpace space) { 614 switch (space) { 615 case SnapshotSpace::kCode: 616 return AllocationType::kCode; 617 case SnapshotSpace::kMap: 618 return AllocationType::kMap; 619 case SnapshotSpace::kOld: 620 return AllocationType::kOld; 621 case SnapshotSpace::kReadOnlyHeap: 622 return AllocationType::kReadOnly; 623 } 624} 625} // namespace 626 627template <typename IsolateT> 628Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) { 629 const int size_in_tagged = source_.GetInt(); 630 const int size_in_bytes = size_in_tagged * kTaggedSize; 631 632 // The map can't be a forward ref. If you want the map to be a forward ref, 633 // then you're probably serializing the meta-map, in which case you want to 634 // use the kNewMetaMap bytecode. 635 DCHECK_NE(source()->Peek(), kRegisterPendingForwardRef); 636 Handle<Map> map = Handle<Map>::cast(ReadObject()); 637 638 AllocationType allocation = SpaceToAllocation(space); 639 640 // When sharing a string table, all in-place internalizable and internalized 641 // strings internalized strings are allocated in the shared heap. 642 // 643 // TODO(12007): When shipping, add a new SharedOld SnapshotSpace. 644 if (FLAG_shared_string_table) { 645 InstanceType instance_type = map->instance_type(); 646 if (InstanceTypeChecker::IsInternalizedString(instance_type) || 647 String::IsInPlaceInternalizable(instance_type)) { 648 allocation = isolate() 649 ->factory() 650 ->RefineAllocationTypeForInPlaceInternalizableString( 651 allocation, *map); 652 } 653 } 654 655 // Filling an object's fields can cause GCs and heap walks, so this object has 656 // to be in a 'sufficiently initialised' state by the time the next allocation 657 // can happen. For this to be the case, the object is carefully deserialized 658 // as follows: 659 // * The space for the object is allocated. 660 // * The map is set on the object so that the GC knows what type the object 661 // has. 662 // * The rest of the object is filled with a fixed Smi value 663 // - This is a Smi so that tagged fields become initialized to a valid 664 // tagged value. 665 // - It's a fixed value, "Smi::uninitialized_deserialization_value()", so 666 // that we can DCHECK for it when reading objects that are assumed to be 667 // partially initialized objects. 668 // * The fields of the object are deserialized in order, under the 669 // assumption that objects are laid out in such a way that any fields 670 // required for object iteration (e.g. length fields) are deserialized 671 // before fields with objects. 672 // - We ensure this is the case by DCHECKing on object allocation that the 673 // previously allocated object has a valid size (see `Allocate`). 674 HeapObject raw_obj = 675 Allocate(allocation, size_in_bytes, HeapObject::RequiredAlignment(*map)); 676 raw_obj.set_map_after_allocation(*map); 677 MemsetTagged(raw_obj.RawField(kTaggedSize), 678 Smi::uninitialized_deserialization_value(), size_in_tagged - 1); 679 680 // Make sure BytecodeArrays have a valid age, so that the marker doesn't 681 // break when making them older. 682 if (raw_obj.IsBytecodeArray(isolate())) { 683 BytecodeArray::cast(raw_obj).set_bytecode_age( 684 BytecodeArray::kFirstBytecodeAge); 685 } 686 687#ifdef DEBUG 688 PtrComprCageBase cage_base(isolate()); 689 // We want to make sure that all embedder pointers are initialized to null. 690 if (raw_obj.IsJSObject(cage_base) && 691 JSObject::cast(raw_obj).MayHaveEmbedderFields()) { 692 JSObject js_obj = JSObject::cast(raw_obj); 693 for (int i = 0; i < js_obj.GetEmbedderFieldCount(); ++i) { 694 void* pointer; 695 CHECK(EmbedderDataSlot(js_obj, i).ToAlignedPointer(main_thread_isolate(), 696 &pointer)); 697 CHECK_NULL(pointer); 698 } 699 } else if (raw_obj.IsEmbedderDataArray(cage_base)) { 700 EmbedderDataArray array = EmbedderDataArray::cast(raw_obj); 701 EmbedderDataSlot start(array, 0); 702 EmbedderDataSlot end(array, array.length()); 703 for (EmbedderDataSlot slot = start; slot < end; ++slot) { 704 void* pointer; 705 CHECK(slot.ToAlignedPointer(main_thread_isolate(), &pointer)); 706 CHECK_NULL(pointer); 707 } 708 } 709#endif 710 711 Handle<HeapObject> obj = handle(raw_obj, isolate()); 712 back_refs_.push_back(obj); 713 714 ReadData(obj, 1, size_in_tagged); 715 PostProcessNewObject(map, obj, space); 716 717#ifdef DEBUG 718 if (obj->IsCode(cage_base)) { 719 DCHECK(space == SnapshotSpace::kCode || 720 space == SnapshotSpace::kReadOnlyHeap); 721 } else { 722 DCHECK_NE(space, SnapshotSpace::kCode); 723 } 724#endif // DEBUG 725 726 return obj; 727} 728 729template <typename IsolateT> 730Handle<HeapObject> Deserializer<IsolateT>::ReadMetaMap() { 731 const SnapshotSpace space = SnapshotSpace::kReadOnlyHeap; 732 const int size_in_bytes = Map::kSize; 733 const int size_in_tagged = size_in_bytes / kTaggedSize; 734 735 HeapObject raw_obj = 736 Allocate(SpaceToAllocation(space), size_in_bytes, kTaggedAligned); 737 raw_obj.set_map_after_allocation(Map::unchecked_cast(raw_obj)); 738 MemsetTagged(raw_obj.RawField(kTaggedSize), 739 Smi::uninitialized_deserialization_value(), size_in_tagged - 1); 740 741 Handle<HeapObject> obj = handle(raw_obj, isolate()); 742 back_refs_.push_back(obj); 743 744 // Set the instance-type manually, to allow backrefs to read it. 745 Map::unchecked_cast(*obj).set_instance_type(MAP_TYPE); 746 747 ReadData(obj, 1, size_in_tagged); 748 PostProcessNewObject(Handle<Map>::cast(obj), obj, space); 749 750 return obj; 751} 752 753class DeserializerRelocInfoVisitor { 754 public: 755 DeserializerRelocInfoVisitor(Deserializer<Isolate>* deserializer, 756 const std::vector<Handle<HeapObject>>* objects) 757 : deserializer_(deserializer), objects_(objects), current_object_(0) {} 758 759 DeserializerRelocInfoVisitor(Deserializer<LocalIsolate>* deserializer, 760 const std::vector<Handle<HeapObject>>* objects) { 761 UNREACHABLE(); 762 } 763 764 ~DeserializerRelocInfoVisitor() { 765 DCHECK_EQ(current_object_, objects_->size()); 766 } 767 768 void VisitCodeTarget(Code host, RelocInfo* rinfo); 769 void VisitEmbeddedPointer(Code host, RelocInfo* rinfo); 770 void VisitRuntimeEntry(Code host, RelocInfo* rinfo); 771 void VisitExternalReference(Code host, RelocInfo* rinfo); 772 void VisitInternalReference(Code host, RelocInfo* rinfo); 773 void VisitOffHeapTarget(Code host, RelocInfo* rinfo); 774 775 private: 776 Isolate* isolate() { return deserializer_->isolate(); } 777 SnapshotByteSource& source() { return deserializer_->source_; } 778 779 Deserializer<Isolate>* deserializer_; 780 const std::vector<Handle<HeapObject>>* objects_; 781 int current_object_; 782}; 783 784void DeserializerRelocInfoVisitor::VisitCodeTarget(Code host, 785 RelocInfo* rinfo) { 786 HeapObject object = *objects_->at(current_object_++); 787 rinfo->set_target_address(Code::cast(object).raw_instruction_start()); 788} 789 790void DeserializerRelocInfoVisitor::VisitEmbeddedPointer(Code host, 791 RelocInfo* rinfo) { 792 HeapObject object = *objects_->at(current_object_++); 793 // Embedded object reference must be a strong one. 794 rinfo->set_target_object(isolate()->heap(), object); 795} 796 797void DeserializerRelocInfoVisitor::VisitRuntimeEntry(Code host, 798 RelocInfo* rinfo) { 799 // We no longer serialize code that contains runtime entries. 800 UNREACHABLE(); 801} 802 803void DeserializerRelocInfoVisitor::VisitExternalReference(Code host, 804 RelocInfo* rinfo) { 805 byte data = source().Get(); 806 CHECK_EQ(data, Deserializer<Isolate>::kExternalReference); 807 808 Address address = deserializer_->ReadExternalReferenceCase(); 809 810 if (rinfo->IsCodedSpecially()) { 811 Address location_of_branch_data = rinfo->pc(); 812 Assembler::deserialization_set_special_target_at(location_of_branch_data, 813 host, address); 814 } else { 815 WriteUnalignedValue(rinfo->target_address_address(), address); 816 } 817} 818 819void DeserializerRelocInfoVisitor::VisitInternalReference(Code host, 820 RelocInfo* rinfo) { 821 byte data = source().Get(); 822 CHECK_EQ(data, Deserializer<Isolate>::kInternalReference); 823 824 // Internal reference target is encoded as an offset from code entry. 825 int target_offset = source().GetInt(); 826 // TODO(jgruber,v8:11036): We are being permissive for this DCHECK, but 827 // consider using raw_instruction_size() instead of raw_body_size() in the 828 // future. 829 STATIC_ASSERT(Code::kOnHeapBodyIsContiguous); 830 DCHECK_LT(static_cast<unsigned>(target_offset), 831 static_cast<unsigned>(host.raw_body_size())); 832 Address target = host.entry() + target_offset; 833 Assembler::deserialization_set_target_internal_reference_at( 834 rinfo->pc(), target, rinfo->rmode()); 835} 836 837void DeserializerRelocInfoVisitor::VisitOffHeapTarget(Code host, 838 RelocInfo* rinfo) { 839 byte data = source().Get(); 840 CHECK_EQ(data, Deserializer<Isolate>::kOffHeapTarget); 841 842 Builtin builtin = Builtins::FromInt(source().GetInt()); 843 844 CHECK_NOT_NULL(isolate()->embedded_blob_code()); 845 EmbeddedData d = EmbeddedData::FromBlob(isolate()); 846 Address address = d.InstructionStartOfBuiltin(builtin); 847 CHECK_NE(kNullAddress, address); 848 849 // TODO(ishell): implement RelocInfo::set_target_off_heap_target() 850 if (RelocInfo::OffHeapTargetIsCodedSpecially()) { 851 Address location_of_branch_data = rinfo->pc(); 852 Assembler::deserialization_set_special_target_at(location_of_branch_data, 853 host, address); 854 } else { 855 WriteUnalignedValue(rinfo->target_address_address(), address); 856 } 857} 858 859template <typename IsolateT> 860template <typename SlotAccessor> 861int Deserializer<IsolateT>::ReadRepeatedObject(SlotAccessor slot_accessor, 862 int repeat_count) { 863 CHECK_LE(2, repeat_count); 864 865 Handle<HeapObject> heap_object = ReadObject(); 866 DCHECK(!Heap::InYoungGeneration(*heap_object)); 867 for (int i = 0; i < repeat_count; i++) { 868 // TODO(leszeks): Use a ranged barrier here. 869 slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG, i); 870 } 871 return repeat_count; 872} 873 874namespace { 875 876// Template used by the below CASE_RANGE macro to statically verify that the 877// given number of cases matches the number of expected cases for that bytecode. 878template <int byte_code_count, int expected> 879constexpr byte VerifyBytecodeCount(byte bytecode) { 880 STATIC_ASSERT(byte_code_count == expected); 881 return bytecode; 882} 883 884} // namespace 885 886// Helper macro (and its implementation detail) for specifying a range of cases. 887// Use as "case CASE_RANGE(byte_code, num_bytecodes):" 888#define CASE_RANGE(byte_code, num_bytecodes) \ 889 CASE_R##num_bytecodes( \ 890 (VerifyBytecodeCount<byte_code##Count, num_bytecodes>(byte_code))) 891#define CASE_R1(byte_code) byte_code 892#define CASE_R2(byte_code) CASE_R1(byte_code) : case CASE_R1(byte_code + 1) 893#define CASE_R3(byte_code) CASE_R2(byte_code) : case CASE_R1(byte_code + 2) 894#define CASE_R4(byte_code) CASE_R2(byte_code) : case CASE_R2(byte_code + 2) 895#define CASE_R8(byte_code) CASE_R4(byte_code) : case CASE_R4(byte_code + 4) 896#define CASE_R16(byte_code) CASE_R8(byte_code) : case CASE_R8(byte_code + 8) 897#define CASE_R32(byte_code) CASE_R16(byte_code) : case CASE_R16(byte_code + 16) 898 899// This generates a case range for all the spaces. 900#define CASE_RANGE_ALL_SPACES(bytecode) \ 901 SpaceEncoder<bytecode>::Encode(SnapshotSpace::kOld) \ 902 : case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kCode) \ 903 : case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kMap) \ 904 : case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kReadOnlyHeap) 905 906template <typename IsolateT> 907void Deserializer<IsolateT>::ReadData(Handle<HeapObject> object, 908 int start_slot_index, 909 int end_slot_index) { 910 int current = start_slot_index; 911 while (current < end_slot_index) { 912 byte data = source_.Get(); 913 current += ReadSingleBytecodeData( 914 data, SlotAccessorForHeapObject::ForSlotIndex(object, current)); 915 } 916 CHECK_EQ(current, end_slot_index); 917} 918 919template <typename IsolateT> 920void Deserializer<IsolateT>::ReadData(FullMaybeObjectSlot start, 921 FullMaybeObjectSlot end) { 922 FullMaybeObjectSlot current = start; 923 while (current < end) { 924 byte data = source_.Get(); 925 current += ReadSingleBytecodeData(data, SlotAccessorForRootSlots(current)); 926 } 927 CHECK_EQ(current, end); 928} 929 930template <typename IsolateT> 931template <typename SlotAccessor> 932int Deserializer<IsolateT>::ReadSingleBytecodeData(byte data, 933 SlotAccessor slot_accessor) { 934 using TSlot = decltype(slot_accessor.slot()); 935 936 switch (data) { 937 // Deserialize a new object and write a pointer to it to the current 938 // object. 939 case CASE_RANGE_ALL_SPACES(kNewObject): { 940 SnapshotSpace space = NewObject::Decode(data); 941 // Save the reference type before recursing down into reading the object. 942 HeapObjectReferenceType ref_type = GetAndResetNextReferenceType(); 943 Handle<HeapObject> heap_object = ReadObject(space); 944 return slot_accessor.Write(heap_object, ref_type); 945 } 946 947 // Find a recently deserialized object using its offset from the current 948 // allocation point and write a pointer to it to the current object. 949 case kBackref: { 950 Handle<HeapObject> heap_object = GetBackReferencedObject(); 951 return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); 952 } 953 954 // Reference an object in the read-only heap. This should be used when an 955 // object is read-only, but is not a root. 956 case kReadOnlyHeapRef: { 957 DCHECK(isolate()->heap()->deserialization_complete()); 958 uint32_t chunk_index = source_.GetInt(); 959 uint32_t chunk_offset = source_.GetInt(); 960 961 ReadOnlySpace* read_only_space = isolate()->heap()->read_only_space(); 962 ReadOnlyPage* page = read_only_space->pages()[chunk_index]; 963 Address address = page->OffsetToAddress(chunk_offset); 964 HeapObject heap_object = HeapObject::FromAddress(address); 965 966 return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); 967 } 968 969 // Find an object in the roots array and write a pointer to it to the 970 // current object. 971 case kRootArray: { 972 int id = source_.GetInt(); 973 RootIndex root_index = static_cast<RootIndex>(id); 974 Handle<HeapObject> heap_object = 975 Handle<HeapObject>::cast(isolate()->root_handle(root_index)); 976 hot_objects_.Add(heap_object); 977 return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); 978 } 979 980 // Find an object in the startup object cache and write a pointer to it to 981 // the current object. 982 case kStartupObjectCache: { 983 int cache_index = source_.GetInt(); 984 // TODO(leszeks): Could we use the address of the startup_object_cache 985 // entry as a Handle backing? 986 HeapObject heap_object = HeapObject::cast( 987 main_thread_isolate()->startup_object_cache()->at(cache_index)); 988 return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); 989 } 990 991 // Find an object in the read-only object cache and write a pointer to it 992 // to the current object. 993 case kReadOnlyObjectCache: { 994 int cache_index = source_.GetInt(); 995 // TODO(leszeks): Could we use the address of the cached_read_only_object 996 // entry as a Handle backing? 997 HeapObject heap_object = HeapObject::cast( 998 isolate()->read_only_heap()->cached_read_only_object(cache_index)); 999 return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); 1000 } 1001 1002 // Find an object in the shared heap object cache and write a pointer to it 1003 // to the current object. 1004 case kSharedHeapObjectCache: { 1005 int cache_index = source_.GetInt(); 1006 // TODO(leszeks): Could we use the address of the 1007 // shared_heap_object_cache entry as a Handle backing? 1008 HeapObject heap_object = HeapObject::cast( 1009 main_thread_isolate()->shared_heap_object_cache()->at(cache_index)); 1010 DCHECK( 1011 SharedHeapSerializer::ShouldBeInSharedHeapObjectCache(heap_object)); 1012 return slot_accessor.Write(heap_object, GetAndResetNextReferenceType()); 1013 } 1014 1015 // Deserialize a new meta-map and write a pointer to it to the current 1016 // object. 1017 case kNewMetaMap: { 1018 Handle<HeapObject> heap_object = ReadMetaMap(); 1019 return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG); 1020 } 1021 1022 // Find an external reference and write a pointer to it to the current 1023 // object. 1024 case kSandboxedExternalReference: 1025 case kExternalReference: { 1026 Address address = ReadExternalReferenceCase(); 1027 if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL && 1028 data == kSandboxedExternalReference) { 1029 ExternalPointerTag tag = ReadExternalPointerTag(); 1030 return WriteExternalPointer(slot_accessor.slot(), address, tag); 1031 } else { 1032 DCHECK(!V8_SANDBOXED_EXTERNAL_POINTERS_BOOL); 1033 return WriteAddress(slot_accessor.slot(), address); 1034 } 1035 } 1036 1037 case kInternalReference: 1038 case kOffHeapTarget: 1039 // These bytecodes are expected only during RelocInfo iteration. 1040 UNREACHABLE(); 1041 1042 // Find an object in the attached references and write a pointer to it to 1043 // the current object. 1044 case kAttachedReference: { 1045 int index = source_.GetInt(); 1046 Handle<HeapObject> heap_object = attached_objects_[index]; 1047 1048 // This is the only case where we might encounter new space objects, so 1049 // maybe emit a generational write barrier. 1050 return slot_accessor.WriteWithGenerationalBarrier( 1051 heap_object, GetAndResetNextReferenceType()); 1052 } 1053 1054 case kNop: 1055 return 0; 1056 1057 case kRegisterPendingForwardRef: { 1058 HeapObjectReferenceType ref_type = GetAndResetNextReferenceType(); 1059 unresolved_forward_refs_.emplace_back(slot_accessor.object(), 1060 slot_accessor.offset(), ref_type); 1061 num_unresolved_forward_refs_++; 1062 return 1; 1063 } 1064 1065 case kResolvePendingForwardRef: { 1066 // Pending forward refs can only be resolved after the heap object's map 1067 // field is deserialized; currently they only appear immediately after 1068 // the map field. 1069 DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize); 1070 Handle<HeapObject> obj = slot_accessor.object(); 1071 int index = source_.GetInt(); 1072 auto& forward_ref = unresolved_forward_refs_[index]; 1073 SlotAccessorForHeapObject::ForSlotOffset(forward_ref.object, 1074 forward_ref.offset) 1075 .Write(*obj, forward_ref.ref_type); 1076 num_unresolved_forward_refs_--; 1077 if (num_unresolved_forward_refs_ == 0) { 1078 // If there's no more pending fields, clear the entire pending field 1079 // vector. 1080 unresolved_forward_refs_.clear(); 1081 } else { 1082 // Otherwise, at least clear the pending field. 1083 forward_ref.object = Handle<HeapObject>(); 1084 } 1085 return 0; 1086 } 1087 1088 case kSynchronize: 1089 // If we get here then that indicates that you have a mismatch between 1090 // the number of GC roots when serializing and deserializing. 1091 UNREACHABLE(); 1092 1093 // Deserialize raw data of variable length. 1094 case kVariableRawData: { 1095 // This operation is only supported for tagged-size slots, else we might 1096 // become misaligned. 1097 DCHECK_EQ(TSlot::kSlotDataSize, kTaggedSize); 1098 int size_in_tagged = source_.GetInt(); 1099 // TODO(leszeks): Only copy slots when there are Smis in the serialized 1100 // data. 1101 source_.CopySlots(slot_accessor.slot().location(), size_in_tagged); 1102 return size_in_tagged; 1103 } 1104 1105 // Deserialize raw code directly into the body of the code object. 1106 case kCodeBody: { 1107 // This operation is only supported for tagged-size slots, else we might 1108 // become misaligned. 1109 DCHECK_EQ(TSlot::kSlotDataSize, kTaggedSize); 1110 // CodeBody can only occur right after the heap object header. 1111 DCHECK_EQ(slot_accessor.offset(), HeapObject::kHeaderSize); 1112 1113 int size_in_tagged = source_.GetInt(); 1114 int size_in_bytes = size_in_tagged * kTaggedSize; 1115 1116 { 1117 DisallowGarbageCollection no_gc; 1118 Code code = Code::cast(*slot_accessor.object()); 1119 1120 // First deserialize the code itself. 1121 source_.CopyRaw( 1122 reinterpret_cast<void*>(code.address() + Code::kDataStart), 1123 size_in_bytes); 1124 } 1125 1126 // Then deserialize the code header 1127 ReadData(slot_accessor.object(), HeapObject::kHeaderSize / kTaggedSize, 1128 Code::kDataStart / kTaggedSize); 1129 1130 // Then deserialize the pre-serialized RelocInfo objects. 1131 std::vector<Handle<HeapObject>> preserialized_objects; 1132 while (source_.Peek() != kSynchronize) { 1133 Handle<HeapObject> obj = ReadObject(); 1134 preserialized_objects.push_back(obj); 1135 } 1136 // Skip the synchronize bytecode. 1137 source_.Advance(1); 1138 1139 // Finally iterate RelocInfos (the same way it was done by the serializer) 1140 // and deserialize respective data into RelocInfos. The RelocIterator 1141 // holds a raw pointer to the code, so we have to disable garbage 1142 // collection here. It's ok though, any objects it would have needed are 1143 // in the preserialized_objects vector. 1144 { 1145 DisallowGarbageCollection no_gc; 1146 1147 Code code = Code::cast(*slot_accessor.object()); 1148 if (V8_EXTERNAL_CODE_SPACE_BOOL) { 1149 code.set_main_cage_base(isolate()->cage_base(), kRelaxedStore); 1150 } 1151 DeserializerRelocInfoVisitor visitor(this, &preserialized_objects); 1152 for (RelocIterator it(code, Code::BodyDescriptor::kRelocModeMask); 1153 !it.done(); it.next()) { 1154 it.rinfo()->Visit(&visitor); 1155 } 1156 } 1157 1158 // Advance to the end of the code object. 1159 return (Code::kDataStart - HeapObject::kHeaderSize) / kTaggedSize + 1160 size_in_tagged; 1161 } 1162 1163 case kVariableRepeat: { 1164 int repeats = VariableRepeatCount::Decode(source_.GetInt()); 1165 return ReadRepeatedObject(slot_accessor, repeats); 1166 } 1167 1168 case kOffHeapBackingStore: 1169 case kOffHeapResizableBackingStore: { 1170 int byte_length = source_.GetInt(); 1171 std::unique_ptr<BackingStore> backing_store; 1172 if (data == kOffHeapBackingStore) { 1173 backing_store = BackingStore::Allocate( 1174 main_thread_isolate(), byte_length, SharedFlag::kNotShared, 1175 InitializedFlag::kUninitialized); 1176 } else { 1177 int max_byte_length = source_.GetInt(); 1178 size_t page_size, initial_pages, max_pages; 1179 Maybe<bool> result = 1180 JSArrayBuffer::GetResizableBackingStorePageConfiguration( 1181 nullptr, byte_length, max_byte_length, kDontThrow, &page_size, 1182 &initial_pages, &max_pages); 1183 DCHECK(result.FromJust()); 1184 USE(result); 1185 constexpr bool kIsWasmMemory = false; 1186 backing_store = BackingStore::TryAllocateAndPartiallyCommitMemory( 1187 main_thread_isolate(), byte_length, max_byte_length, page_size, 1188 initial_pages, max_pages, kIsWasmMemory, SharedFlag::kNotShared); 1189 } 1190 CHECK_NOT_NULL(backing_store); 1191 source_.CopyRaw(backing_store->buffer_start(), byte_length); 1192 backing_stores_.push_back(std::move(backing_store)); 1193 return 0; 1194 } 1195 1196 case kSandboxedApiReference: 1197 case kApiReference: { 1198 uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); 1199 Address address; 1200 if (main_thread_isolate()->api_external_references()) { 1201 DCHECK_WITH_MSG(reference_id < num_api_references_, 1202 "too few external references provided through the API"); 1203 address = static_cast<Address>( 1204 main_thread_isolate()->api_external_references()[reference_id]); 1205 } else { 1206 address = reinterpret_cast<Address>(NoExternalReferencesCallback); 1207 } 1208 if (V8_SANDBOXED_EXTERNAL_POINTERS_BOOL && 1209 data == kSandboxedApiReference) { 1210 ExternalPointerTag tag = ReadExternalPointerTag(); 1211 return WriteExternalPointer(slot_accessor.slot(), address, tag); 1212 } else { 1213 DCHECK(!V8_SANDBOXED_EXTERNAL_POINTERS_BOOL); 1214 return WriteAddress(slot_accessor.slot(), address); 1215 } 1216 } 1217 1218 case kClearedWeakReference: 1219 return slot_accessor.Write(HeapObjectReference::ClearedValue(isolate())); 1220 1221 case kWeakPrefix: { 1222 // We shouldn't have two weak prefixes in a row. 1223 DCHECK(!next_reference_is_weak_); 1224 // We shouldn't have weak refs without a current object. 1225 DCHECK_NE(slot_accessor.object()->address(), kNullAddress); 1226 next_reference_is_weak_ = true; 1227 return 0; 1228 } 1229 1230 case CASE_RANGE(kRootArrayConstants, 32): { 1231 // First kRootArrayConstantsCount roots are guaranteed to be in 1232 // the old space. 1233 STATIC_ASSERT(static_cast<int>(RootIndex::kFirstImmortalImmovableRoot) == 1234 0); 1235 STATIC_ASSERT(kRootArrayConstantsCount <= 1236 static_cast<int>(RootIndex::kLastImmortalImmovableRoot)); 1237 1238 RootIndex root_index = RootArrayConstant::Decode(data); 1239 Handle<HeapObject> heap_object = 1240 Handle<HeapObject>::cast(isolate()->root_handle(root_index)); 1241 return slot_accessor.Write(heap_object, HeapObjectReferenceType::STRONG); 1242 } 1243 1244 case CASE_RANGE(kHotObject, 8): { 1245 int index = HotObject::Decode(data); 1246 Handle<HeapObject> hot_object = hot_objects_.Get(index); 1247 return slot_accessor.Write(hot_object, GetAndResetNextReferenceType()); 1248 } 1249 1250 case CASE_RANGE(kFixedRawData, 32): { 1251 // Deserialize raw data of fixed length from 1 to 32 times kTaggedSize. 1252 int size_in_tagged = FixedRawDataWithSize::Decode(data); 1253 STATIC_ASSERT(TSlot::kSlotDataSize == kTaggedSize || 1254 TSlot::kSlotDataSize == 2 * kTaggedSize); 1255 int size_in_slots = size_in_tagged / (TSlot::kSlotDataSize / kTaggedSize); 1256 // kFixedRawData can have kTaggedSize != TSlot::kSlotDataSize when 1257 // serializing Smi roots in pointer-compressed builds. In this case, the 1258 // size in bytes is unconditionally the (full) slot size. 1259 DCHECK_IMPLIES(kTaggedSize != TSlot::kSlotDataSize, size_in_slots == 1); 1260 // TODO(leszeks): Only copy slots when there are Smis in the serialized 1261 // data. 1262 source_.CopySlots(slot_accessor.slot().location(), size_in_slots); 1263 return size_in_slots; 1264 } 1265 1266 case CASE_RANGE(kFixedRepeat, 16): { 1267 int repeats = FixedRepeatWithCount::Decode(data); 1268 return ReadRepeatedObject(slot_accessor, repeats); 1269 } 1270 1271#ifdef DEBUG 1272#define UNUSED_CASE(byte_code) \ 1273 case byte_code: \ 1274 UNREACHABLE(); 1275 UNUSED_SERIALIZER_BYTE_CODES(UNUSED_CASE) 1276#endif 1277#undef UNUSED_CASE 1278 } 1279 1280 // The above switch, including UNUSED_SERIALIZER_BYTE_CODES, covers all 1281 // possible bytecodes; but, clang doesn't realize this, so we have an explicit 1282 // UNREACHABLE here too. 1283 UNREACHABLE(); 1284} 1285 1286#undef CASE_RANGE_ALL_SPACES 1287#undef CASE_RANGE 1288#undef CASE_R32 1289#undef CASE_R16 1290#undef CASE_R8 1291#undef CASE_R4 1292#undef CASE_R3 1293#undef CASE_R2 1294#undef CASE_R1 1295 1296template <typename IsolateT> 1297Address Deserializer<IsolateT>::ReadExternalReferenceCase() { 1298 uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); 1299 return main_thread_isolate()->external_reference_table()->address( 1300 reference_id); 1301} 1302 1303template <typename IsolateT> 1304ExternalPointerTag Deserializer<IsolateT>::ReadExternalPointerTag() { 1305 uint64_t shifted_tag = static_cast<uint64_t>(source_.GetInt()); 1306 return static_cast<ExternalPointerTag>(shifted_tag 1307 << kExternalPointerTagShift); 1308} 1309 1310template <typename IsolateT> 1311HeapObject Deserializer<IsolateT>::Allocate(AllocationType allocation, int size, 1312 AllocationAlignment alignment) { 1313#ifdef DEBUG 1314 if (!previous_allocation_obj_.is_null()) { 1315 // Make sure that the previous object is initialized sufficiently to 1316 // be iterated over by the GC. 1317 int object_size = previous_allocation_obj_->Size(isolate_); 1318 DCHECK_LE(object_size, previous_allocation_size_); 1319 } 1320#endif 1321 1322 HeapObject obj = HeapObject::FromAddress(isolate()->heap()->AllocateRawOrFail( 1323 size, allocation, AllocationOrigin::kRuntime, alignment)); 1324 1325#ifdef DEBUG 1326 previous_allocation_obj_ = handle(obj, isolate()); 1327 previous_allocation_size_ = size; 1328#endif 1329 1330 return obj; 1331} 1332 1333template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Deserializer<Isolate>; 1334template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 1335 Deserializer<LocalIsolate>; 1336 1337} // namespace internal 1338} // namespace v8 1339