1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_SERIALIZE_H_ 29 #define V8_SERIALIZE_H_ 30 31 #include "hashmap.h" 32 33 namespace v8 { 34 namespace internal { 35 36 // A TypeCode is used to distinguish different kinds of external reference. 37 // It is a single bit to make testing for types easy. 38 enum TypeCode { 39 UNCLASSIFIED, // One-of-a-kind references. 40 BUILTIN, 41 RUNTIME_FUNCTION, 42 IC_UTILITY, 43 DEBUG_ADDRESS, 44 STATS_COUNTER, 45 TOP_ADDRESS, 46 C_BUILTIN, 47 EXTENSION, 48 ACCESSOR, 49 RUNTIME_ENTRY, 50 STUB_CACHE_TABLE 51 }; 52 53 const int kTypeCodeCount = STUB_CACHE_TABLE + 1; 54 const int kFirstTypeCode = UNCLASSIFIED; 55 56 const int kReferenceIdBits = 16; 57 const int kReferenceIdMask = (1 << kReferenceIdBits) - 1; 58 const int kReferenceTypeShift = kReferenceIdBits; 59 const int kDebugRegisterBits = 4; 60 const int kDebugIdShift = kDebugRegisterBits; 61 62 63 // ExternalReferenceTable is a helper class that defines the relationship 64 // between external references and their encodings. It is used to build 65 // hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder. 66 class ExternalReferenceTable { 67 public: 68 static ExternalReferenceTable* instance(Isolate* isolate); 69 70 ~ExternalReferenceTable() { } 71 72 int size() const { return refs_.length(); } 73 74 Address address(int i) { return refs_[i].address; } 75 76 uint32_t code(int i) { return refs_[i].code; } 77 78 const char* name(int i) { return refs_[i].name; } 79 80 int max_id(int code) { return max_id_[code]; } 81 82 private: 83 explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) { 84 PopulateTable(isolate); 85 } 86 87 struct ExternalReferenceEntry { 88 Address address; 89 uint32_t code; 90 const char* name; 91 }; 92 93 void PopulateTable(Isolate* isolate); 94 95 // For a few types of references, we can get their address from their id. 96 void AddFromId(TypeCode type, 97 uint16_t id, 98 const char* name, 99 Isolate* isolate); 100 101 // For other types of references, the caller will figure out the address. 102 void Add(Address address, TypeCode type, uint16_t id, const char* name); 103 104 List<ExternalReferenceEntry> refs_; 105 int max_id_[kTypeCodeCount]; 106 }; 107 108 109 class ExternalReferenceEncoder { 110 public: 111 ExternalReferenceEncoder(); 112 113 uint32_t Encode(Address key) const; 114 115 const char* NameOfAddress(Address key) const; 116 117 private: 118 HashMap encodings_; 119 static uint32_t Hash(Address key) { 120 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2); 121 } 122 123 int IndexOf(Address key) const; 124 125 static bool Match(void* key1, void* key2) { return key1 == key2; } 126 127 void Put(Address key, int index); 128 129 Isolate* isolate_; 130 }; 131 132 133 class ExternalReferenceDecoder { 134 public: 135 ExternalReferenceDecoder(); 136 ~ExternalReferenceDecoder(); 137 138 Address Decode(uint32_t key) const { 139 if (key == 0) return NULL; 140 return *Lookup(key); 141 } 142 143 private: 144 Address** encodings_; 145 146 Address* Lookup(uint32_t key) const { 147 int type = key >> kReferenceTypeShift; 148 ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount); 149 int id = key & kReferenceIdMask; 150 return &encodings_[type][id]; 151 } 152 153 void Put(uint32_t key, Address value) { 154 *Lookup(key) = value; 155 } 156 157 Isolate* isolate_; 158 }; 159 160 161 class SnapshotByteSource { 162 public: 163 SnapshotByteSource(const byte* array, int length) 164 : data_(array), length_(length), position_(0) { } 165 166 bool HasMore() { return position_ < length_; } 167 168 int Get() { 169 ASSERT(position_ < length_); 170 return data_[position_++]; 171 } 172 173 inline void CopyRaw(byte* to, int number_of_bytes); 174 175 inline int GetInt(); 176 177 bool AtEOF() { 178 return position_ == length_; 179 } 180 181 int position() { return position_; } 182 183 private: 184 const byte* data_; 185 int length_; 186 int position_; 187 }; 188 189 190 #define COMMON_RAW_LENGTHS(f) \ 191 f(1, 1) \ 192 f(2, 2) \ 193 f(3, 3) \ 194 f(4, 4) \ 195 f(5, 5) \ 196 f(6, 6) \ 197 f(7, 7) \ 198 f(8, 8) \ 199 f(9, 12) \ 200 f(10, 16) \ 201 f(11, 20) \ 202 f(12, 24) \ 203 f(13, 28) \ 204 f(14, 32) \ 205 f(15, 36) 206 207 // The Serializer/Deserializer class is a common superclass for Serializer and 208 // Deserializer which is used to store common constants and methods used by 209 // both. 210 class SerializerDeserializer: public ObjectVisitor { 211 public: 212 static void Iterate(ObjectVisitor* visitor); 213 static void SetSnapshotCacheSize(int size); 214 215 protected: 216 // Where the pointed-to object can be found: 217 enum Where { 218 kNewObject = 0, // Object is next in snapshot. 219 // 1-8 One per space. 220 kRootArray = 0x9, // Object is found in root array. 221 kPartialSnapshotCache = 0xa, // Object is in the cache. 222 kExternalReference = 0xb, // Pointer to an external reference. 223 kSkip = 0xc, // Skip a pointer sized cell. 224 // 0xd-0xf Free. 225 kBackref = 0x10, // Object is described relative to end. 226 // 0x11-0x18 One per space. 227 // 0x19-0x1f Free. 228 kFromStart = 0x20, // Object is described relative to start. 229 // 0x21-0x28 One per space. 230 // 0x29-0x2f Free. 231 // 0x30-0x3f Used by misc. tags below. 232 kPointedToMask = 0x3f 233 }; 234 235 // How to code the pointer to the object. 236 enum HowToCode { 237 kPlain = 0, // Straight pointer. 238 // What this means depends on the architecture: 239 kFromCode = 0x40, // A pointer inlined in code. 240 kHowToCodeMask = 0x40 241 }; 242 243 // Where to point within the object. 244 enum WhereToPoint { 245 kStartOfObject = 0, 246 kFirstInstruction = 0x80, 247 kWhereToPointMask = 0x80 248 }; 249 250 // Misc. 251 // Raw data to be copied from the snapshot. 252 static const int kRawData = 0x30; 253 // Some common raw lengths: 0x31-0x3f 254 // A tag emitted at strategic points in the snapshot to delineate sections. 255 // If the deserializer does not find these at the expected moments then it 256 // is an indication that the snapshot and the VM do not fit together. 257 // Examine the build process for architecture, version or configuration 258 // mismatches. 259 static const int kSynchronize = 0x70; 260 // Used for the source code of the natives, which is in the executable, but 261 // is referred to from external strings in the snapshot. 262 static const int kNativesStringResource = 0x71; 263 static const int kNewPage = 0x72; 264 static const int kRepeat = 0x73; 265 static const int kConstantRepeat = 0x74; 266 // 0x74-0x7f Repeat last word (subtract 0x73 to get the count). 267 static const int kMaxRepeats = 0x7f - 0x73; 268 static int CodeForRepeats(int repeats) { 269 ASSERT(repeats >= 1 && repeats <= kMaxRepeats); 270 return 0x73 + repeats; 271 } 272 static int RepeatsForCode(int byte_code) { 273 ASSERT(byte_code >= kConstantRepeat && byte_code <= 0x7f); 274 return byte_code - 0x73; 275 } 276 static const int kRootArrayLowConstants = 0xb0; 277 // 0xb0-0xbf Things from the first 16 elements of the root array. 278 static const int kRootArrayHighConstants = 0xf0; 279 // 0xf0-0xff Things from the next 16 elements of the root array. 280 static const int kRootArrayNumberOfConstantEncodings = 0x20; 281 static const int kRootArrayNumberOfLowConstantEncodings = 0x10; 282 static int RootArrayConstantFromByteCode(int byte_code) { 283 int constant = (byte_code & 0xf) | ((byte_code & 0x40) >> 2); 284 ASSERT(constant >= 0 && constant < kRootArrayNumberOfConstantEncodings); 285 return constant; 286 } 287 288 289 static const int kLargeData = LAST_SPACE; 290 static const int kLargeCode = kLargeData + 1; 291 static const int kLargeFixedArray = kLargeCode + 1; 292 static const int kNumberOfSpaces = kLargeFixedArray + 1; 293 static const int kAnyOldSpace = -1; 294 295 // A bitmask for getting the space out of an instruction. 296 static const int kSpaceMask = 15; 297 298 static inline bool SpaceIsLarge(int space) { return space >= kLargeData; } 299 static inline bool SpaceIsPaged(int space) { 300 return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE; 301 } 302 }; 303 304 305 int SnapshotByteSource::GetInt() { 306 // A little unwind to catch the really small ints. 307 int snapshot_byte = Get(); 308 if ((snapshot_byte & 0x80) == 0) { 309 return snapshot_byte; 310 } 311 int accumulator = (snapshot_byte & 0x7f) << 7; 312 while (true) { 313 snapshot_byte = Get(); 314 if ((snapshot_byte & 0x80) == 0) { 315 return accumulator | snapshot_byte; 316 } 317 accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7; 318 } 319 UNREACHABLE(); 320 return accumulator; 321 } 322 323 324 void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) { 325 memcpy(to, data_ + position_, number_of_bytes); 326 position_ += number_of_bytes; 327 } 328 329 330 // A Deserializer reads a snapshot and reconstructs the Object graph it defines. 331 class Deserializer: public SerializerDeserializer { 332 public: 333 // Create a deserializer from a snapshot byte source. 334 explicit Deserializer(SnapshotByteSource* source); 335 336 virtual ~Deserializer(); 337 338 // Deserialize the snapshot into an empty heap. 339 void Deserialize(); 340 341 // Deserialize a single object and the objects reachable from it. 342 void DeserializePartial(Object** root); 343 344 private: 345 virtual void VisitPointers(Object** start, Object** end); 346 347 virtual void VisitExternalReferences(Address* start, Address* end) { 348 UNREACHABLE(); 349 } 350 351 virtual void VisitRuntimeEntry(RelocInfo* rinfo) { 352 UNREACHABLE(); 353 } 354 355 // Fills in some heap data in an area from start to end (non-inclusive). The 356 // space id is used for the write barrier. The object_address is the address 357 // of the object we are writing into, or NULL if we are not writing into an 358 // object, i.e. if we are writing a series of tagged values that are not on 359 // the heap. 360 void ReadChunk( 361 Object** start, Object** end, int space, Address object_address); 362 HeapObject* GetAddressFromStart(int space); 363 inline HeapObject* GetAddressFromEnd(int space); 364 Address Allocate(int space_number, Space* space, int size); 365 void ReadObject(int space_number, Space* space, Object** write_back); 366 367 // Cached current isolate. 368 Isolate* isolate_; 369 370 // Keep track of the pages in the paged spaces. 371 // (In large object space we are keeping track of individual objects 372 // rather than pages.) In new space we just need the address of the 373 // first object and the others will flow from that. 374 List<Address> pages_[SerializerDeserializer::kNumberOfSpaces]; 375 376 SnapshotByteSource* source_; 377 // This is the address of the next object that will be allocated in each 378 // space. It is used to calculate the addresses of back-references. 379 Address high_water_[LAST_SPACE + 1]; 380 // This is the address of the most recent object that was allocated. It 381 // is used to set the location of the new page when we encounter a 382 // START_NEW_PAGE_SERIALIZATION tag. 383 Address last_object_address_; 384 385 ExternalReferenceDecoder* external_reference_decoder_; 386 387 DISALLOW_COPY_AND_ASSIGN(Deserializer); 388 }; 389 390 391 class SnapshotByteSink { 392 public: 393 virtual ~SnapshotByteSink() { } 394 virtual void Put(int byte, const char* description) = 0; 395 virtual void PutSection(int byte, const char* description) { 396 Put(byte, description); 397 } 398 void PutInt(uintptr_t integer, const char* description); 399 virtual int Position() = 0; 400 }; 401 402 403 // Mapping objects to their location after deserialization. 404 // This is used during building, but not at runtime by V8. 405 class SerializationAddressMapper { 406 public: 407 SerializationAddressMapper() 408 : serialization_map_(new HashMap(&SerializationMatchFun)), 409 no_allocation_(new AssertNoAllocation()) { } 410 411 ~SerializationAddressMapper() { 412 delete serialization_map_; 413 delete no_allocation_; 414 } 415 416 bool IsMapped(HeapObject* obj) { 417 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL; 418 } 419 420 int MappedTo(HeapObject* obj) { 421 ASSERT(IsMapped(obj)); 422 return static_cast<int>(reinterpret_cast<intptr_t>( 423 serialization_map_->Lookup(Key(obj), Hash(obj), false)->value)); 424 } 425 426 void AddMapping(HeapObject* obj, int to) { 427 ASSERT(!IsMapped(obj)); 428 HashMap::Entry* entry = 429 serialization_map_->Lookup(Key(obj), Hash(obj), true); 430 entry->value = Value(to); 431 } 432 433 private: 434 static bool SerializationMatchFun(void* key1, void* key2) { 435 return key1 == key2; 436 } 437 438 static uint32_t Hash(HeapObject* obj) { 439 return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address())); 440 } 441 442 static void* Key(HeapObject* obj) { 443 return reinterpret_cast<void*>(obj->address()); 444 } 445 446 static void* Value(int v) { 447 return reinterpret_cast<void*>(v); 448 } 449 450 HashMap* serialization_map_; 451 AssertNoAllocation* no_allocation_; 452 DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper); 453 }; 454 455 456 // There can be only one serializer per V8 process. 457 class Serializer : public SerializerDeserializer { 458 public: 459 explicit Serializer(SnapshotByteSink* sink); 460 ~Serializer(); 461 void VisitPointers(Object** start, Object** end); 462 // You can call this after serialization to find out how much space was used 463 // in each space. 464 int CurrentAllocationAddress(int space) { 465 if (SpaceIsLarge(space)) return large_object_total_; 466 return fullness_[space]; 467 } 468 469 static void Enable() { 470 if (!serialization_enabled_) { 471 ASSERT(!too_late_to_enable_now_); 472 } 473 serialization_enabled_ = true; 474 } 475 476 static void Disable() { serialization_enabled_ = false; } 477 // Call this when you have made use of the fact that there is no serialization 478 // going on. 479 static void TooLateToEnableNow() { too_late_to_enable_now_ = true; } 480 static bool enabled() { return serialization_enabled_; } 481 SerializationAddressMapper* address_mapper() { return &address_mapper_; } 482 void PutRoot( 483 int index, HeapObject* object, HowToCode how, WhereToPoint where); 484 485 protected: 486 static const int kInvalidRootIndex = -1; 487 488 int RootIndex(HeapObject* heap_object, HowToCode from); 489 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0; 490 intptr_t root_index_wave_front() { return root_index_wave_front_; } 491 void set_root_index_wave_front(intptr_t value) { 492 ASSERT(value >= root_index_wave_front_); 493 root_index_wave_front_ = value; 494 } 495 496 class ObjectSerializer : public ObjectVisitor { 497 public: 498 ObjectSerializer(Serializer* serializer, 499 Object* o, 500 SnapshotByteSink* sink, 501 HowToCode how_to_code, 502 WhereToPoint where_to_point) 503 : serializer_(serializer), 504 object_(HeapObject::cast(o)), 505 sink_(sink), 506 reference_representation_(how_to_code + where_to_point), 507 bytes_processed_so_far_(0) { } 508 void Serialize(); 509 void VisitPointers(Object** start, Object** end); 510 void VisitEmbeddedPointer(RelocInfo* target); 511 void VisitExternalReferences(Address* start, Address* end); 512 void VisitExternalReference(RelocInfo* rinfo); 513 void VisitCodeTarget(RelocInfo* target); 514 void VisitCodeEntry(Address entry_address); 515 void VisitGlobalPropertyCell(RelocInfo* rinfo); 516 void VisitRuntimeEntry(RelocInfo* reloc); 517 // Used for seralizing the external strings that hold the natives source. 518 void VisitExternalAsciiString( 519 v8::String::ExternalAsciiStringResource** resource); 520 // We can't serialize a heap with external two byte strings. 521 void VisitExternalTwoByteString( 522 v8::String::ExternalStringResource** resource) { 523 UNREACHABLE(); 524 } 525 526 private: 527 void OutputRawData(Address up_to); 528 529 Serializer* serializer_; 530 HeapObject* object_; 531 SnapshotByteSink* sink_; 532 int reference_representation_; 533 int bytes_processed_so_far_; 534 }; 535 536 virtual void SerializeObject(Object* o, 537 HowToCode how_to_code, 538 WhereToPoint where_to_point) = 0; 539 void SerializeReferenceToPreviousObject( 540 int space, 541 int address, 542 HowToCode how_to_code, 543 WhereToPoint where_to_point); 544 void InitializeAllocators(); 545 // This will return the space for an object. If the object is in large 546 // object space it may return kLargeCode or kLargeFixedArray in order 547 // to indicate to the deserializer what kind of large object allocation 548 // to make. 549 static int SpaceOfObject(HeapObject* object); 550 // This just returns the space of the object. It will return LO_SPACE 551 // for all large objects since you can't check the type of the object 552 // once the map has been used for the serialization address. 553 static int SpaceOfAlreadySerializedObject(HeapObject* object); 554 int Allocate(int space, int size, bool* new_page_started); 555 int EncodeExternalReference(Address addr) { 556 return external_reference_encoder_->Encode(addr); 557 } 558 559 int SpaceAreaSize(int space); 560 561 Isolate* isolate_; 562 // Keep track of the fullness of each space in order to generate 563 // relative addresses for back references. Large objects are 564 // just numbered sequentially since relative addresses make no 565 // sense in large object space. 566 int fullness_[LAST_SPACE + 1]; 567 SnapshotByteSink* sink_; 568 int current_root_index_; 569 ExternalReferenceEncoder* external_reference_encoder_; 570 static bool serialization_enabled_; 571 // Did we already make use of the fact that serialization was not enabled? 572 static bool too_late_to_enable_now_; 573 int large_object_total_; 574 SerializationAddressMapper address_mapper_; 575 intptr_t root_index_wave_front_; 576 577 friend class ObjectSerializer; 578 friend class Deserializer; 579 580 private: 581 DISALLOW_COPY_AND_ASSIGN(Serializer); 582 }; 583 584 585 class PartialSerializer : public Serializer { 586 public: 587 PartialSerializer(Serializer* startup_snapshot_serializer, 588 SnapshotByteSink* sink) 589 : Serializer(sink), 590 startup_serializer_(startup_snapshot_serializer) { 591 set_root_index_wave_front(Heap::kStrongRootListLength); 592 } 593 594 // Serialize the objects reachable from a single object pointer. 595 virtual void Serialize(Object** o); 596 virtual void SerializeObject(Object* o, 597 HowToCode how_to_code, 598 WhereToPoint where_to_point); 599 600 protected: 601 virtual int PartialSnapshotCacheIndex(HeapObject* o); 602 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) { 603 // Scripts should be referred only through shared function infos. We can't 604 // allow them to be part of the partial snapshot because they contain a 605 // unique ID, and deserializing several partial snapshots containing script 606 // would cause dupes. 607 ASSERT(!o->IsScript()); 608 return o->IsString() || o->IsSharedFunctionInfo() || 609 o->IsHeapNumber() || o->IsCode() || 610 o->IsScopeInfo() || 611 o->map() == HEAP->fixed_cow_array_map(); 612 } 613 614 private: 615 Serializer* startup_serializer_; 616 DISALLOW_COPY_AND_ASSIGN(PartialSerializer); 617 }; 618 619 620 class StartupSerializer : public Serializer { 621 public: 622 explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) { 623 // Clear the cache of objects used by the partial snapshot. After the 624 // strong roots have been serialized we can create a partial snapshot 625 // which will repopulate the cache with objects needed by that partial 626 // snapshot. 627 Isolate::Current()->set_serialize_partial_snapshot_cache_length(0); 628 } 629 // Serialize the current state of the heap. The order is: 630 // 1) Strong references. 631 // 2) Partial snapshot cache. 632 // 3) Weak references (e.g. the symbol table). 633 virtual void SerializeStrongReferences(); 634 virtual void SerializeObject(Object* o, 635 HowToCode how_to_code, 636 WhereToPoint where_to_point); 637 void SerializeWeakReferences(); 638 void Serialize() { 639 SerializeStrongReferences(); 640 SerializeWeakReferences(); 641 } 642 643 private: 644 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) { 645 return false; 646 } 647 }; 648 649 650 } } // namespace v8::internal 651 652 #endif // V8_SERIALIZE_H_ 653