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/assembler-inl.h" 8 #include "src/heap/heap-write-barrier-inl.h" 9 #include "src/isolate.h" 10 #include "src/objects/api-callbacks.h" 11 #include "src/objects/hash-table.h" 12 #include "src/objects/js-array-buffer-inl.h" 13 #include "src/objects/js-array-inl.h" 14 #include "src/objects/maybe-object.h" 15 #include "src/objects/string.h" 16 #include "src/snapshot/builtin-deserializer-allocator.h" 17 #include "src/snapshot/natives.h" 18 #include "src/snapshot/snapshot.h" 19 20 namespace v8 { 21 namespace internal { 22 23 template <class AllocatorT> 24 void Deserializer<AllocatorT>::Initialize(Isolate* isolate) { 25 DCHECK_NULL(isolate_); 26 DCHECK_NOT_NULL(isolate); 27 isolate_ = isolate; 28 DCHECK_NULL(external_reference_table_); 29 external_reference_table_ = isolate->heap()->external_reference_table(); 30 #ifdef DEBUG 31 // Count the number of external references registered through the API. 32 num_api_references_ = 0; 33 if (isolate_->api_external_references() != nullptr) { 34 while (isolate_->api_external_references()[num_api_references_] != 0) { 35 num_api_references_++; 36 } 37 } 38 #endif // DEBUG 39 CHECK_EQ(magic_number_, 40 SerializedData::ComputeMagicNumber(external_reference_table_)); 41 } 42 43 template <class AllocatorT> 44 bool Deserializer<AllocatorT>::IsLazyDeserializationEnabled() const { 45 return FLAG_lazy_deserialization && !isolate()->serializer_enabled(); 46 } 47 48 template <class AllocatorT> 49 void Deserializer<AllocatorT>::Rehash() { 50 DCHECK(can_rehash() || deserializing_user_code()); 51 for (const auto& item : to_rehash_) item->RehashBasedOnMap(isolate()); 52 } 53 54 template <class AllocatorT> 55 Deserializer<AllocatorT>::~Deserializer() { 56 #ifdef DEBUG 57 // Do not perform checks if we aborted deserialization. 58 if (source_.position() == 0) return; 59 // Check that we only have padding bytes remaining. 60 while (source_.HasMore()) DCHECK_EQ(kNop, source_.Get()); 61 // Check that we've fully used all reserved space. 62 DCHECK(allocator()->ReservationsAreFullyUsed()); 63 #endif // DEBUG 64 } 65 66 // This is called on the roots. It is the driver of the deserialization 67 // process. It is also called on the body of each function. 68 template <class AllocatorT> 69 void Deserializer<AllocatorT>::VisitRootPointers(Root root, 70 const char* description, 71 Object** start, Object** end) { 72 // Builtins and bytecode handlers are deserialized in a separate pass by the 73 // BuiltinDeserializer. 74 if (root == Root::kBuiltins || root == Root::kDispatchTable) return; 75 76 // The space must be new space. Any other space would cause ReadChunk to try 77 // to update the remembered using nullptr as the address. 78 ReadData(reinterpret_cast<MaybeObject**>(start), 79 reinterpret_cast<MaybeObject**>(end), NEW_SPACE, kNullAddress); 80 } 81 82 template <class AllocatorT> 83 void Deserializer<AllocatorT>::Synchronize( 84 VisitorSynchronization::SyncTag tag) { 85 static const byte expected = kSynchronize; 86 CHECK_EQ(expected, source_.Get()); 87 } 88 89 template <class AllocatorT> 90 void Deserializer<AllocatorT>::DeserializeDeferredObjects() { 91 for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) { 92 switch (code) { 93 case kAlignmentPrefix: 94 case kAlignmentPrefix + 1: 95 case kAlignmentPrefix + 2: { 96 int alignment = code - (SerializerDeserializer::kAlignmentPrefix - 1); 97 allocator()->SetAlignment(static_cast<AllocationAlignment>(alignment)); 98 break; 99 } 100 default: { 101 int space = code & kSpaceMask; 102 DCHECK_LE(space, kNumberOfSpaces); 103 DCHECK_EQ(code - space, kNewObject); 104 HeapObject* object = GetBackReferencedObject(space); 105 int size = source_.GetInt() << kPointerSizeLog2; 106 Address obj_address = object->address(); 107 MaybeObject** start = 108 reinterpret_cast<MaybeObject**>(obj_address + kPointerSize); 109 MaybeObject** end = reinterpret_cast<MaybeObject**>(obj_address + size); 110 bool filled = ReadData(start, end, space, obj_address); 111 CHECK(filled); 112 DCHECK(CanBeDeferred(object)); 113 PostProcessNewObject(object, space); 114 } 115 } 116 } 117 } 118 119 StringTableInsertionKey::StringTableInsertionKey(String* string) 120 : StringTableKey(ComputeHashField(string)), string_(string) { 121 DCHECK(string->IsInternalizedString()); 122 } 123 124 bool StringTableInsertionKey::IsMatch(Object* string) { 125 // We know that all entries in a hash table had their hash keys created. 126 // Use that knowledge to have fast failure. 127 if (Hash() != String::cast(string)->Hash()) return false; 128 // We want to compare the content of two internalized strings here. 129 return string_->SlowEquals(String::cast(string)); 130 } 131 132 Handle<String> StringTableInsertionKey::AsHandle(Isolate* isolate) { 133 return handle(string_, isolate); 134 } 135 136 uint32_t StringTableInsertionKey::ComputeHashField(String* string) { 137 // Make sure hash_field() is computed. 138 string->Hash(); 139 return string->hash_field(); 140 } 141 142 template <class AllocatorT> 143 HeapObject* Deserializer<AllocatorT>::PostProcessNewObject(HeapObject* obj, 144 int space) { 145 if ((FLAG_rehash_snapshot && can_rehash_) || deserializing_user_code()) { 146 if (obj->IsString()) { 147 // Uninitialize hash field as we need to recompute the hash. 148 String* string = String::cast(obj); 149 string->set_hash_field(String::kEmptyHashField); 150 } else if (obj->NeedsRehashing()) { 151 to_rehash_.push_back(obj); 152 } 153 } 154 155 if (deserializing_user_code()) { 156 if (obj->IsString()) { 157 String* string = String::cast(obj); 158 if (string->IsInternalizedString()) { 159 // Canonicalize the internalized string. If it already exists in the 160 // string table, set it to forward to the existing one. 161 StringTableInsertionKey key(string); 162 String* canonical = 163 StringTable::ForwardStringIfExists(isolate_, &key, string); 164 165 if (canonical != nullptr) return canonical; 166 167 new_internalized_strings_.push_back(handle(string, isolate_)); 168 return string; 169 } 170 } else if (obj->IsScript()) { 171 new_scripts_.push_back(handle(Script::cast(obj), isolate_)); 172 } else { 173 DCHECK(CanBeDeferred(obj)); 174 } 175 } else if (obj->IsScript()) { 176 LOG(isolate_, ScriptEvent(Logger::ScriptEventType::kDeserialize, 177 Script::cast(obj)->id())); 178 LOG(isolate_, ScriptDetails(Script::cast(obj))); 179 } 180 181 if (obj->IsAllocationSite()) { 182 // Allocation sites are present in the snapshot, and must be linked into 183 // a list at deserialization time. 184 AllocationSite* site = AllocationSite::cast(obj); 185 // TODO(mvstanton): consider treating the heap()->allocation_sites_list() 186 // as a (weak) root. If this root is relocated correctly, this becomes 187 // unnecessary. 188 if (isolate_->heap()->allocation_sites_list() == Smi::kZero) { 189 site->set_weak_next(ReadOnlyRoots(isolate_).undefined_value()); 190 } else { 191 site->set_weak_next(isolate_->heap()->allocation_sites_list()); 192 } 193 isolate_->heap()->set_allocation_sites_list(site); 194 } else if (obj->IsCode()) { 195 // We flush all code pages after deserializing the startup snapshot. In that 196 // case, we only need to remember code objects in the large object space. 197 // When deserializing user code, remember each individual code object. 198 if (deserializing_user_code() || space == LO_SPACE) { 199 new_code_objects_.push_back(Code::cast(obj)); 200 } 201 } else if (obj->IsAccessorInfo()) { 202 #ifdef USE_SIMULATOR 203 accessor_infos_.push_back(AccessorInfo::cast(obj)); 204 #endif 205 } else if (obj->IsCallHandlerInfo()) { 206 #ifdef USE_SIMULATOR 207 call_handler_infos_.push_back(CallHandlerInfo::cast(obj)); 208 #endif 209 } else if (obj->IsExternalString()) { 210 if (obj->map() == ReadOnlyRoots(isolate_).native_source_string_map()) { 211 ExternalOneByteString* string = ExternalOneByteString::cast(obj); 212 DCHECK(string->is_short()); 213 string->SetResource( 214 isolate_, NativesExternalStringResource::DecodeForDeserialization( 215 string->resource())); 216 } else { 217 ExternalString* string = ExternalString::cast(obj); 218 uint32_t index = string->resource_as_uint32(); 219 Address address = 220 static_cast<Address>(isolate_->api_external_references()[index]); 221 string->set_address_as_resource(address); 222 isolate_->heap()->UpdateExternalString(string, 0, 223 string->ExternalPayloadSize()); 224 } 225 isolate_->heap()->RegisterExternalString(String::cast(obj)); 226 } else if (obj->IsJSTypedArray()) { 227 JSTypedArray* typed_array = JSTypedArray::cast(obj); 228 CHECK(typed_array->byte_offset()->IsSmi()); 229 int32_t byte_offset = NumberToInt32(typed_array->byte_offset()); 230 if (byte_offset > 0) { 231 FixedTypedArrayBase* elements = 232 FixedTypedArrayBase::cast(typed_array->elements()); 233 // Must be off-heap layout. 234 DCHECK(!typed_array->is_on_heap()); 235 236 void* pointer_with_offset = reinterpret_cast<void*>( 237 reinterpret_cast<intptr_t>(elements->external_pointer()) + 238 byte_offset); 239 elements->set_external_pointer(pointer_with_offset); 240 } 241 } else if (obj->IsJSArrayBuffer()) { 242 JSArrayBuffer* buffer = JSArrayBuffer::cast(obj); 243 // Only fixup for the off-heap case. 244 if (buffer->backing_store() != nullptr) { 245 Smi* store_index = reinterpret_cast<Smi*>(buffer->backing_store()); 246 void* backing_store = off_heap_backing_stores_[store_index->value()]; 247 248 buffer->set_backing_store(backing_store); 249 isolate_->heap()->RegisterNewArrayBuffer(buffer); 250 } 251 } else if (obj->IsFixedTypedArrayBase()) { 252 FixedTypedArrayBase* fta = FixedTypedArrayBase::cast(obj); 253 // Only fixup for the off-heap case. 254 if (fta->base_pointer() == nullptr) { 255 Smi* store_index = reinterpret_cast<Smi*>(fta->external_pointer()); 256 void* backing_store = off_heap_backing_stores_[store_index->value()]; 257 fta->set_external_pointer(backing_store); 258 } 259 } else if (obj->IsBytecodeArray()) { 260 // TODO(mythria): Remove these once we store the default values for these 261 // fields in the serializer. 262 BytecodeArray* bytecode_array = BytecodeArray::cast(obj); 263 bytecode_array->set_interrupt_budget( 264 interpreter::Interpreter::InterruptBudget()); 265 bytecode_array->set_osr_loop_nesting_level(0); 266 } 267 268 // Check alignment. 269 DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), 270 HeapObject::RequiredAlignment(obj->map()))); 271 return obj; 272 } 273 274 template <class AllocatorT> 275 int Deserializer<AllocatorT>::MaybeReplaceWithDeserializeLazy(int builtin_id) { 276 DCHECK(Builtins::IsBuiltinId(builtin_id)); 277 return IsLazyDeserializationEnabled() && Builtins::IsLazy(builtin_id) 278 ? Builtins::kDeserializeLazy 279 : builtin_id; 280 } 281 282 template <class AllocatorT> 283 HeapObject* Deserializer<AllocatorT>::GetBackReferencedObject(int space) { 284 HeapObject* obj; 285 switch (space) { 286 case LO_SPACE: 287 obj = allocator()->GetLargeObject(source_.GetInt()); 288 break; 289 case MAP_SPACE: 290 obj = allocator()->GetMap(source_.GetInt()); 291 break; 292 case RO_SPACE: { 293 uint32_t chunk_index = source_.GetInt(); 294 uint32_t chunk_offset = source_.GetInt(); 295 if (isolate()->heap()->deserialization_complete()) { 296 PagedSpace* read_only_space = isolate()->heap()->read_only_space(); 297 Page* page = read_only_space->first_page(); 298 for (uint32_t i = 0; i < chunk_index; ++i) { 299 page = page->next_page(); 300 } 301 Address address = page->OffsetToAddress(chunk_offset); 302 obj = HeapObject::FromAddress(address); 303 } else { 304 obj = allocator()->GetObject(static_cast<AllocationSpace>(space), 305 chunk_index, chunk_offset); 306 } 307 break; 308 } 309 default: { 310 uint32_t chunk_index = source_.GetInt(); 311 uint32_t chunk_offset = source_.GetInt(); 312 obj = allocator()->GetObject(static_cast<AllocationSpace>(space), 313 chunk_index, chunk_offset); 314 break; 315 } 316 } 317 318 if (deserializing_user_code() && obj->IsThinString()) { 319 obj = ThinString::cast(obj)->actual(); 320 } 321 322 hot_objects_.Add(obj); 323 DCHECK(!HasWeakHeapObjectTag(obj)); 324 return obj; 325 } 326 327 // This routine writes the new object into the pointer provided. 328 // The reason for this strange interface is that otherwise the object is 329 // written very late, which means the FreeSpace map is not set up by the 330 // time we need to use it to mark the space at the end of a page free. 331 template <class AllocatorT> 332 void Deserializer<AllocatorT>::ReadObject( 333 int space_number, MaybeObject** write_back, 334 HeapObjectReferenceType reference_type) { 335 const int size = source_.GetInt() << kObjectAlignmentBits; 336 337 Address address = 338 allocator()->Allocate(static_cast<AllocationSpace>(space_number), size); 339 HeapObject* obj = HeapObject::FromAddress(address); 340 341 isolate_->heap()->OnAllocationEvent(obj, size); 342 MaybeObject** current = reinterpret_cast<MaybeObject**>(address); 343 MaybeObject** limit = current + (size >> kPointerSizeLog2); 344 345 if (ReadData(current, limit, space_number, address)) { 346 // Only post process if object content has not been deferred. 347 obj = PostProcessNewObject(obj, space_number); 348 } 349 350 MaybeObject* write_back_obj = 351 reference_type == HeapObjectReferenceType::STRONG 352 ? HeapObjectReference::Strong(obj) 353 : HeapObjectReference::Weak(obj); 354 UnalignedCopy(write_back, &write_back_obj); 355 #ifdef DEBUG 356 if (obj->IsCode()) { 357 DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE); 358 } else { 359 DCHECK(space_number != CODE_SPACE); 360 } 361 #endif // DEBUG 362 } 363 364 template <class AllocatorT> 365 Object* Deserializer<AllocatorT>::ReadDataSingle() { 366 MaybeObject* o; 367 MaybeObject** start = &o; 368 MaybeObject** end = start + 1; 369 int source_space = NEW_SPACE; 370 Address current_object = kNullAddress; 371 372 CHECK(ReadData(start, end, source_space, current_object)); 373 HeapObject* heap_object; 374 bool success = o->ToStrongHeapObject(&heap_object); 375 DCHECK(success); 376 USE(success); 377 return heap_object; 378 } 379 380 static void NoExternalReferencesCallback() { 381 // The following check will trigger if a function or object template 382 // with references to native functions have been deserialized from 383 // snapshot, but no actual external references were provided when the 384 // isolate was created. 385 CHECK_WITH_MSG(false, "No external references provided via API"); 386 } 387 388 template <class AllocatorT> 389 bool Deserializer<AllocatorT>::ReadData(MaybeObject** current, 390 MaybeObject** limit, int source_space, 391 Address current_object_address) { 392 Isolate* const isolate = isolate_; 393 // Write barrier support costs around 1% in startup time. In fact there 394 // are no new space objects in current boot snapshots, so it's not needed, 395 // but that may change. 396 bool write_barrier_needed = 397 (current_object_address != kNullAddress && source_space != NEW_SPACE && 398 source_space != CODE_SPACE); 399 while (current < limit) { 400 byte data = source_.Get(); 401 switch (data) { 402 #define CASE_STATEMENT(where, how, within, space_number) \ 403 case where + how + within + space_number: \ 404 STATIC_ASSERT((where & ~kWhereMask) == 0); \ 405 STATIC_ASSERT((how & ~kHowToCodeMask) == 0); \ 406 STATIC_ASSERT((within & ~kWhereToPointMask) == 0); \ 407 STATIC_ASSERT((space_number & ~kSpaceMask) == 0); 408 409 #define CASE_BODY(where, how, within, space_number_if_any) \ 410 current = ReadDataCase<where, how, within, space_number_if_any>( \ 411 isolate, current, current_object_address, data, write_barrier_needed); \ 412 break; 413 414 // This generates a case and a body for the new space (which has to do extra 415 // write barrier handling) and handles the other spaces with fall-through cases 416 // and one body. 417 #define ALL_SPACES(where, how, within) \ 418 CASE_STATEMENT(where, how, within, NEW_SPACE) \ 419 CASE_BODY(where, how, within, NEW_SPACE) \ 420 CASE_STATEMENT(where, how, within, OLD_SPACE) \ 421 V8_FALLTHROUGH; \ 422 CASE_STATEMENT(where, how, within, CODE_SPACE) \ 423 V8_FALLTHROUGH; \ 424 CASE_STATEMENT(where, how, within, MAP_SPACE) \ 425 V8_FALLTHROUGH; \ 426 CASE_STATEMENT(where, how, within, LO_SPACE) \ 427 V8_FALLTHROUGH; \ 428 CASE_STATEMENT(where, how, within, RO_SPACE) \ 429 CASE_BODY(where, how, within, kAnyOldSpace) 430 431 #define FOUR_CASES(byte_code) \ 432 case byte_code: \ 433 case byte_code + 1: \ 434 case byte_code + 2: \ 435 case byte_code + 3: 436 437 #define SIXTEEN_CASES(byte_code) \ 438 FOUR_CASES(byte_code) \ 439 FOUR_CASES(byte_code + 4) \ 440 FOUR_CASES(byte_code + 8) \ 441 FOUR_CASES(byte_code + 12) 442 443 #define SINGLE_CASE(where, how, within, space) \ 444 CASE_STATEMENT(where, how, within, space) \ 445 CASE_BODY(where, how, within, space) 446 447 // Deserialize a new object and write a pointer to it to the current 448 // object. 449 ALL_SPACES(kNewObject, kPlain, kStartOfObject) 450 // Deserialize a new code object and write a pointer to its first 451 // instruction to the current code object. 452 ALL_SPACES(kNewObject, kFromCode, kInnerPointer) 453 // Find a recently deserialized object using its offset from the current 454 // allocation point and write a pointer to it to the current object. 455 ALL_SPACES(kBackref, kPlain, kStartOfObject) 456 ALL_SPACES(kBackrefWithSkip, kPlain, kStartOfObject) 457 #if V8_CODE_EMBEDS_OBJECT_POINTER 458 // Deserialize a new object from pointer found in code and write 459 // a pointer to it to the current object. Required only for MIPS, PPC, ARM 460 // or S390 with embedded constant pool, and omitted on the other 461 // architectures because it is fully unrolled and would cause bloat. 462 ALL_SPACES(kNewObject, kFromCode, kStartOfObject) 463 // Find a recently deserialized code object using its offset from the 464 // current allocation point and write a pointer to it to the current 465 // object. Required only for MIPS, PPC, ARM or S390 with embedded 466 // constant pool. 467 ALL_SPACES(kBackref, kFromCode, kStartOfObject) 468 ALL_SPACES(kBackrefWithSkip, kFromCode, kStartOfObject) 469 #endif 470 // Find a recently deserialized code object using its offset from the 471 // current allocation point and write a pointer to its first instruction 472 // to the current code object or the instruction pointer in a function 473 // object. 474 ALL_SPACES(kBackref, kFromCode, kInnerPointer) 475 ALL_SPACES(kBackrefWithSkip, kFromCode, kInnerPointer) 476 // Find an object in the roots array and write a pointer to it to the 477 // current object. 478 SINGLE_CASE(kRootArray, kPlain, kStartOfObject, 0) 479 #if V8_CODE_EMBEDS_OBJECT_POINTER 480 // Find an object in the roots array and write a pointer to it to in code. 481 SINGLE_CASE(kRootArray, kFromCode, kStartOfObject, 0) 482 #endif 483 // Find an object in the partial snapshots cache and write a pointer to it 484 // to the current object. 485 SINGLE_CASE(kPartialSnapshotCache, kPlain, kStartOfObject, 0) 486 SINGLE_CASE(kPartialSnapshotCache, kFromCode, kStartOfObject, 0) 487 SINGLE_CASE(kPartialSnapshotCache, kFromCode, kInnerPointer, 0) 488 // Find an object in the attached references and write a pointer to it to 489 // the current object. 490 SINGLE_CASE(kAttachedReference, kPlain, kStartOfObject, 0) 491 SINGLE_CASE(kAttachedReference, kFromCode, kStartOfObject, 0) 492 SINGLE_CASE(kAttachedReference, kFromCode, kInnerPointer, 0) 493 // Find a builtin and write a pointer to it to the current object. 494 SINGLE_CASE(kBuiltin, kPlain, kStartOfObject, 0) 495 SINGLE_CASE(kBuiltin, kFromCode, kStartOfObject, 0) 496 SINGLE_CASE(kBuiltin, kFromCode, kInnerPointer, 0) 497 498 #undef CASE_STATEMENT 499 #undef CASE_BODY 500 #undef ALL_SPACES 501 502 case kSkip: { 503 int size = source_.GetInt(); 504 current = reinterpret_cast<MaybeObject**>( 505 reinterpret_cast<Address>(current) + size); 506 break; 507 } 508 509 // Find an external reference and write a pointer to it to the current 510 // object. 511 case kExternalReference + kPlain + kStartOfObject: 512 current = reinterpret_cast<MaybeObject**>(ReadExternalReferenceCase( 513 kPlain, reinterpret_cast<void**>(current), current_object_address)); 514 break; 515 // Find an external reference and write a pointer to it in the current 516 // code object. 517 case kExternalReference + kFromCode + kStartOfObject: 518 current = reinterpret_cast<MaybeObject**>(ReadExternalReferenceCase( 519 kFromCode, reinterpret_cast<void**>(current), 520 current_object_address)); 521 break; 522 523 case kInternalReferenceEncoded: 524 case kInternalReference: { 525 // Internal reference address is not encoded via skip, but by offset 526 // from code entry. 527 int pc_offset = source_.GetInt(); 528 int target_offset = source_.GetInt(); 529 Code* code = 530 Code::cast(HeapObject::FromAddress(current_object_address)); 531 DCHECK(0 <= pc_offset && pc_offset <= code->raw_instruction_size()); 532 DCHECK(0 <= target_offset && 533 target_offset <= code->raw_instruction_size()); 534 Address pc = code->entry() + pc_offset; 535 Address target = code->entry() + target_offset; 536 Assembler::deserialization_set_target_internal_reference_at( 537 pc, target, 538 data == kInternalReference ? RelocInfo::INTERNAL_REFERENCE 539 : RelocInfo::INTERNAL_REFERENCE_ENCODED); 540 break; 541 } 542 543 case kOffHeapTarget: { 544 DCHECK(FLAG_embedded_builtins); 545 int skip = source_.GetInt(); 546 int builtin_index = source_.GetInt(); 547 DCHECK(Builtins::IsBuiltinId(builtin_index)); 548 549 current = reinterpret_cast<MaybeObject**>( 550 reinterpret_cast<Address>(current) + skip); 551 552 CHECK_NOT_NULL(isolate->embedded_blob()); 553 EmbeddedData d = EmbeddedData::FromBlob(); 554 Address address = d.InstructionStartOfBuiltin(builtin_index); 555 CHECK_NE(kNullAddress, address); 556 557 if (RelocInfo::OffHeapTargetIsCodedSpecially()) { 558 Address location_of_branch_data = reinterpret_cast<Address>(current); 559 int skip = Assembler::deserialization_special_target_size( 560 location_of_branch_data); 561 Assembler::deserialization_set_special_target_at( 562 location_of_branch_data, 563 Code::cast(HeapObject::FromAddress(current_object_address)), 564 address); 565 location_of_branch_data += skip; 566 current = reinterpret_cast<MaybeObject**>(location_of_branch_data); 567 } else { 568 MaybeObject* o = reinterpret_cast<MaybeObject*>(address); 569 UnalignedCopy(current, &o); 570 current++; 571 } 572 break; 573 } 574 575 case kNop: 576 break; 577 578 case kNextChunk: { 579 int space = source_.Get(); 580 allocator()->MoveToNextChunk(static_cast<AllocationSpace>(space)); 581 break; 582 } 583 584 case kDeferred: { 585 // Deferred can only occur right after the heap object header. 586 DCHECK_EQ(current, reinterpret_cast<MaybeObject**>( 587 current_object_address + kPointerSize)); 588 HeapObject* obj = HeapObject::FromAddress(current_object_address); 589 // If the deferred object is a map, its instance type may be used 590 // during deserialization. Initialize it with a temporary value. 591 if (obj->IsMap()) Map::cast(obj)->set_instance_type(FILLER_TYPE); 592 current = limit; 593 return false; 594 } 595 596 case kSynchronize: 597 // If we get here then that indicates that you have a mismatch between 598 // the number of GC roots when serializing and deserializing. 599 UNREACHABLE(); 600 601 // Deserialize raw data of variable length. 602 case kVariableRawData: { 603 int size_in_bytes = source_.GetInt(); 604 byte* raw_data_out = reinterpret_cast<byte*>(current); 605 source_.CopyRaw(raw_data_out, size_in_bytes); 606 current = reinterpret_cast<MaybeObject**>( 607 reinterpret_cast<intptr_t>(current) + size_in_bytes); 608 break; 609 } 610 611 // Deserialize raw code directly into the body of the code object. 612 // Do not move current. 613 case kVariableRawCode: { 614 int size_in_bytes = source_.GetInt(); 615 source_.CopyRaw( 616 reinterpret_cast<byte*>(current_object_address + Code::kDataStart), 617 size_in_bytes); 618 break; 619 } 620 621 case kVariableRepeat: { 622 int repeats = source_.GetInt(); 623 MaybeObject* object = current[-1]; 624 DCHECK(!Heap::InNewSpace(object)); 625 DCHECK(!allocator()->next_reference_is_weak()); 626 for (int i = 0; i < repeats; i++) UnalignedCopy(current++, &object); 627 break; 628 } 629 630 case kOffHeapBackingStore: { 631 int byte_length = source_.GetInt(); 632 byte* backing_store = static_cast<byte*>( 633 isolate->array_buffer_allocator()->AllocateUninitialized( 634 byte_length)); 635 CHECK_NOT_NULL(backing_store); 636 source_.CopyRaw(backing_store, byte_length); 637 off_heap_backing_stores_.push_back(backing_store); 638 break; 639 } 640 641 case kApiReference: { 642 int skip = source_.GetInt(); 643 current = reinterpret_cast<MaybeObject**>( 644 reinterpret_cast<Address>(current) + skip); 645 uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); 646 Address address; 647 if (isolate->api_external_references()) { 648 DCHECK_WITH_MSG( 649 reference_id < num_api_references_, 650 "too few external references provided through the API"); 651 address = static_cast<Address>( 652 isolate->api_external_references()[reference_id]); 653 } else { 654 address = reinterpret_cast<Address>(NoExternalReferencesCallback); 655 } 656 memcpy(current, &address, kPointerSize); 657 current++; 658 break; 659 } 660 661 case kWeakPrefix: 662 DCHECK(!allocator()->next_reference_is_weak()); 663 allocator()->set_next_reference_is_weak(true); 664 break; 665 666 case kAlignmentPrefix: 667 case kAlignmentPrefix + 1: 668 case kAlignmentPrefix + 2: { 669 int alignment = data - (SerializerDeserializer::kAlignmentPrefix - 1); 670 allocator()->SetAlignment(static_cast<AllocationAlignment>(alignment)); 671 break; 672 } 673 674 STATIC_ASSERT(kNumberOfRootArrayConstants == Heap::kOldSpaceRoots); 675 STATIC_ASSERT(kNumberOfRootArrayConstants == 32); 676 SIXTEEN_CASES(kRootArrayConstantsWithSkip) 677 SIXTEEN_CASES(kRootArrayConstantsWithSkip + 16) { 678 int skip = source_.GetInt(); 679 current = reinterpret_cast<MaybeObject**>( 680 reinterpret_cast<intptr_t>(current) + skip); 681 V8_FALLTHROUGH; 682 } 683 684 SIXTEEN_CASES(kRootArrayConstants) 685 SIXTEEN_CASES(kRootArrayConstants + 16) { 686 int id = data & kRootArrayConstantsMask; 687 Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(id); 688 MaybeObject* object = 689 MaybeObject::FromObject(isolate->heap()->root(root_index)); 690 DCHECK(!Heap::InNewSpace(object)); 691 DCHECK(!allocator()->next_reference_is_weak()); 692 UnalignedCopy(current++, &object); 693 break; 694 } 695 696 STATIC_ASSERT(kNumberOfHotObjects == 8); 697 FOUR_CASES(kHotObjectWithSkip) 698 FOUR_CASES(kHotObjectWithSkip + 4) { 699 int skip = source_.GetInt(); 700 current = reinterpret_cast<MaybeObject**>( 701 reinterpret_cast<Address>(current) + skip); 702 V8_FALLTHROUGH; 703 } 704 705 FOUR_CASES(kHotObject) 706 FOUR_CASES(kHotObject + 4) { 707 int index = data & kHotObjectMask; 708 Object* hot_object = hot_objects_.Get(index); 709 MaybeObject* hot_maybe_object = MaybeObject::FromObject(hot_object); 710 if (allocator()->GetAndClearNextReferenceIsWeak()) { 711 hot_maybe_object = MaybeObject::MakeWeak(hot_maybe_object); 712 } 713 714 UnalignedCopy(current, &hot_maybe_object); 715 if (write_barrier_needed && Heap::InNewSpace(hot_object)) { 716 Address current_address = reinterpret_cast<Address>(current); 717 GenerationalBarrier(HeapObject::FromAddress(current_object_address), 718 reinterpret_cast<MaybeObject**>(current_address), 719 hot_maybe_object); 720 } 721 current++; 722 break; 723 } 724 725 // Deserialize raw data of fixed length from 1 to 32 words. 726 STATIC_ASSERT(kNumberOfFixedRawData == 32); 727 SIXTEEN_CASES(kFixedRawData) 728 SIXTEEN_CASES(kFixedRawData + 16) { 729 byte* raw_data_out = reinterpret_cast<byte*>(current); 730 int size_in_bytes = (data - kFixedRawDataStart) << kPointerSizeLog2; 731 source_.CopyRaw(raw_data_out, size_in_bytes); 732 current = reinterpret_cast<MaybeObject**>(raw_data_out + size_in_bytes); 733 break; 734 } 735 736 STATIC_ASSERT(kNumberOfFixedRepeat == 16); 737 SIXTEEN_CASES(kFixedRepeat) { 738 int repeats = data - kFixedRepeatStart; 739 MaybeObject* object; 740 DCHECK(!allocator()->next_reference_is_weak()); 741 UnalignedCopy(&object, current - 1); 742 DCHECK(!Heap::InNewSpace(object)); 743 for (int i = 0; i < repeats; i++) UnalignedCopy(current++, &object); 744 break; 745 } 746 747 #ifdef DEBUG 748 #define UNUSED_CASE(byte_code) \ 749 case byte_code: \ 750 UNREACHABLE(); 751 UNUSED_SERIALIZER_BYTE_CODES(UNUSED_CASE) 752 #endif 753 #undef UNUSED_CASE 754 755 #undef SIXTEEN_CASES 756 #undef FOUR_CASES 757 #undef SINGLE_CASE 758 } 759 } 760 CHECK_EQ(limit, current); 761 return true; 762 } 763 764 template <class AllocatorT> 765 void** Deserializer<AllocatorT>::ReadExternalReferenceCase( 766 HowToCode how, void** current, Address current_object_address) { 767 int skip = source_.GetInt(); 768 current = reinterpret_cast<void**>(reinterpret_cast<Address>(current) + skip); 769 uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); 770 Address address = external_reference_table_->address(reference_id); 771 772 if (how == kFromCode) { 773 Address location_of_branch_data = reinterpret_cast<Address>(current); 774 int skip = 775 Assembler::deserialization_special_target_size(location_of_branch_data); 776 Assembler::deserialization_set_special_target_at( 777 location_of_branch_data, 778 Code::cast(HeapObject::FromAddress(current_object_address)), address); 779 location_of_branch_data += skip; 780 current = reinterpret_cast<void**>(location_of_branch_data); 781 } else { 782 void* new_current = reinterpret_cast<void**>(address); 783 UnalignedCopy(current, &new_current); 784 ++current; 785 } 786 return current; 787 } 788 789 template <class AllocatorT> 790 template <int where, int how, int within, int space_number_if_any> 791 MaybeObject** Deserializer<AllocatorT>::ReadDataCase( 792 Isolate* isolate, MaybeObject** current, Address current_object_address, 793 byte data, bool write_barrier_needed) { 794 bool emit_write_barrier = false; 795 bool current_was_incremented = false; 796 int space_number = space_number_if_any == kAnyOldSpace ? (data & kSpaceMask) 797 : space_number_if_any; 798 HeapObjectReferenceType reference_type = HeapObjectReferenceType::STRONG; 799 if (where == kNewObject && how == kPlain && within == kStartOfObject) { 800 if (allocator()->GetAndClearNextReferenceIsWeak()) { 801 reference_type = HeapObjectReferenceType::WEAK; 802 } 803 ReadObject(space_number, current, reference_type); 804 emit_write_barrier = (space_number == NEW_SPACE); 805 } else { 806 Object* new_object = nullptr; /* May not be a real Object pointer. */ 807 if (where == kNewObject) { 808 ReadObject(space_number, reinterpret_cast<MaybeObject**>(&new_object), 809 HeapObjectReferenceType::STRONG); 810 } else if (where == kBackref) { 811 emit_write_barrier = (space_number == NEW_SPACE); 812 new_object = GetBackReferencedObject(data & kSpaceMask); 813 } else if (where == kBackrefWithSkip) { 814 int skip = source_.GetInt(); 815 current = reinterpret_cast<MaybeObject**>( 816 reinterpret_cast<Address>(current) + skip); 817 emit_write_barrier = (space_number == NEW_SPACE); 818 new_object = GetBackReferencedObject(data & kSpaceMask); 819 } else if (where == kRootArray) { 820 int id = source_.GetInt(); 821 Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(id); 822 new_object = isolate->heap()->root(root_index); 823 emit_write_barrier = Heap::InNewSpace(new_object); 824 hot_objects_.Add(HeapObject::cast(new_object)); 825 } else if (where == kPartialSnapshotCache) { 826 int cache_index = source_.GetInt(); 827 new_object = isolate->partial_snapshot_cache()->at(cache_index); 828 emit_write_barrier = Heap::InNewSpace(new_object); 829 } else if (where == kAttachedReference) { 830 int index = source_.GetInt(); 831 new_object = *attached_objects_[index]; 832 emit_write_barrier = Heap::InNewSpace(new_object); 833 } else { 834 DCHECK_EQ(where, kBuiltin); 835 int builtin_id = MaybeReplaceWithDeserializeLazy(source_.GetInt()); 836 new_object = isolate->builtins()->builtin(builtin_id); 837 emit_write_barrier = false; 838 } 839 if (within == kInnerPointer) { 840 DCHECK_EQ(how, kFromCode); 841 if (where == kBuiltin) { 842 // At this point, new_object may still be uninitialized, thus the 843 // unchecked Code cast. 844 new_object = reinterpret_cast<Object*>( 845 reinterpret_cast<Code*>(new_object)->raw_instruction_start()); 846 } else if (new_object->IsCode()) { 847 new_object = reinterpret_cast<Object*>( 848 Code::cast(new_object)->raw_instruction_start()); 849 } else { 850 Cell* cell = Cell::cast(new_object); 851 new_object = reinterpret_cast<Object*>(cell->ValueAddress()); 852 } 853 } 854 if (how == kFromCode) { 855 DCHECK(!allocator()->next_reference_is_weak()); 856 Address location_of_branch_data = reinterpret_cast<Address>(current); 857 int skip = Assembler::deserialization_special_target_size( 858 location_of_branch_data); 859 Assembler::deserialization_set_special_target_at( 860 location_of_branch_data, 861 Code::cast(HeapObject::FromAddress(current_object_address)), 862 reinterpret_cast<Address>(new_object)); 863 location_of_branch_data += skip; 864 current = reinterpret_cast<MaybeObject**>(location_of_branch_data); 865 current_was_incremented = true; 866 } else { 867 MaybeObject* new_maybe_object = MaybeObject::FromObject(new_object); 868 if (allocator()->GetAndClearNextReferenceIsWeak()) { 869 new_maybe_object = MaybeObject::MakeWeak(new_maybe_object); 870 } 871 UnalignedCopy(current, &new_maybe_object); 872 } 873 } 874 if (emit_write_barrier && write_barrier_needed) { 875 Address current_address = reinterpret_cast<Address>(current); 876 SLOW_DCHECK(isolate->heap()->ContainsSlow(current_object_address)); 877 GenerationalBarrier(HeapObject::FromAddress(current_object_address), 878 reinterpret_cast<MaybeObject**>(current_address), 879 *reinterpret_cast<MaybeObject**>(current_address)); 880 } 881 if (!current_was_incremented) { 882 current++; 883 } 884 885 return current; 886 } 887 888 // Explicit instantiation. 889 template class Deserializer<BuiltinDeserializerAllocator>; 890 template class Deserializer<DefaultDeserializerAllocator>; 891 892 } // namespace internal 893 } // namespace v8 894