Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2009 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 class ExternalReferenceEncoder {
     64  public:
     65   ExternalReferenceEncoder();
     66 
     67   uint32_t Encode(Address key) const;
     68 
     69   const char* NameOfAddress(Address key) const;
     70 
     71  private:
     72   HashMap encodings_;
     73   static uint32_t Hash(Address key) {
     74     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
     75   }
     76 
     77   int IndexOf(Address key) const;
     78 
     79   static bool Match(void* key1, void* key2) { return key1 == key2; }
     80 
     81   void Put(Address key, int index);
     82 };
     83 
     84 
     85 class ExternalReferenceDecoder {
     86  public:
     87   ExternalReferenceDecoder();
     88   ~ExternalReferenceDecoder();
     89 
     90   Address Decode(uint32_t key) const {
     91     if (key == 0) return NULL;
     92     return *Lookup(key);
     93   }
     94 
     95  private:
     96   Address** encodings_;
     97 
     98   Address* Lookup(uint32_t key) const {
     99     int type = key >> kReferenceTypeShift;
    100     ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
    101     int id = key & kReferenceIdMask;
    102     return &encodings_[type][id];
    103   }
    104 
    105   void Put(uint32_t key, Address value) {
    106     *Lookup(key) = value;
    107   }
    108 };
    109 
    110 
    111 class SnapshotByteSource {
    112  public:
    113   SnapshotByteSource(const byte* array, int length)
    114     : data_(array), length_(length), position_(0) { }
    115 
    116   bool HasMore() { return position_ < length_; }
    117 
    118   int Get() {
    119     ASSERT(position_ < length_);
    120     return data_[position_++];
    121   }
    122 
    123   inline void CopyRaw(byte* to, int number_of_bytes);
    124 
    125   inline int GetInt();
    126 
    127   bool AtEOF() {
    128     return position_ == length_;
    129   }
    130 
    131   int position() { return position_; }
    132 
    133  private:
    134   const byte* data_;
    135   int length_;
    136   int position_;
    137 };
    138 
    139 
    140 // It is very common to have a reference to the object at word 10 in space 2,
    141 // the object at word 5 in space 2 and the object at word 28 in space 4.  This
    142 // only works for objects in the first page of a space.
    143 #define COMMON_REFERENCE_PATTERNS(f)                              \
    144   f(kNumberOfSpaces, 2, 10)                                       \
    145   f(kNumberOfSpaces + 1, 2, 5)                                    \
    146   f(kNumberOfSpaces + 2, 4, 28)                                   \
    147   f(kNumberOfSpaces + 3, 2, 21)                                   \
    148   f(kNumberOfSpaces + 4, 2, 98)                                   \
    149   f(kNumberOfSpaces + 5, 2, 67)                                   \
    150   f(kNumberOfSpaces + 6, 4, 132)
    151 
    152 #define COMMON_RAW_LENGTHS(f)        \
    153   f(1, 1)  \
    154   f(2, 2)  \
    155   f(3, 3)  \
    156   f(4, 4)  \
    157   f(5, 5)  \
    158   f(6, 6)  \
    159   f(7, 7)  \
    160   f(8, 8)  \
    161   f(9, 12)  \
    162   f(10, 16) \
    163   f(11, 20) \
    164   f(12, 24) \
    165   f(13, 28) \
    166   f(14, 32) \
    167   f(15, 36)
    168 
    169 // The Serializer/Deserializer class is a common superclass for Serializer and
    170 // Deserializer which is used to store common constants and methods used by
    171 // both.
    172 class SerializerDeserializer: public ObjectVisitor {
    173  public:
    174   static void Iterate(ObjectVisitor* visitor);
    175   static void SetSnapshotCacheSize(int size);
    176 
    177  protected:
    178   enum DataType {
    179     RAW_DATA_SERIALIZATION = 0,
    180     // And 15 common raw lengths.
    181     OBJECT_SERIALIZATION = 16,
    182     // One variant per space.
    183     CODE_OBJECT_SERIALIZATION = 25,
    184     // One per space (only code spaces in use).
    185     EXTERNAL_REFERENCE_SERIALIZATION = 34,
    186     EXTERNAL_BRANCH_TARGET_SERIALIZATION = 35,
    187     SYNCHRONIZE = 36,
    188     START_NEW_PAGE_SERIALIZATION = 37,
    189     NATIVES_STRING_RESOURCE = 38,
    190     ROOT_SERIALIZATION = 39,
    191     PARTIAL_SNAPSHOT_CACHE_ENTRY = 40,
    192     // Free: 41-47.
    193     BACKREF_SERIALIZATION = 48,
    194     // One per space, must be kSpaceMask aligned.
    195     // Free: 57-63.
    196     REFERENCE_SERIALIZATION = 64,
    197     // One per space and common references.  Must be kSpaceMask aligned.
    198     CODE_BACKREF_SERIALIZATION = 80,
    199     // One per space, must be kSpaceMask aligned.
    200     // Free: 89-95.
    201     CODE_REFERENCE_SERIALIZATION = 96
    202     // One per space, must be kSpaceMask aligned.
    203     // Free: 105-255.
    204   };
    205   static const int kLargeData = LAST_SPACE;
    206   static const int kLargeCode = kLargeData + 1;
    207   static const int kLargeFixedArray = kLargeCode + 1;
    208   static const int kNumberOfSpaces = kLargeFixedArray + 1;
    209 
    210   // A bitmask for getting the space out of an instruction.
    211   static const int kSpaceMask = 15;
    212 
    213   static inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
    214   static inline bool SpaceIsPaged(int space) {
    215     return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE;
    216   }
    217 
    218   static int partial_snapshot_cache_length_;
    219   static const int kPartialSnapshotCacheCapacity = 1300;
    220   static Object* partial_snapshot_cache_[];
    221 };
    222 
    223 
    224 int SnapshotByteSource::GetInt() {
    225   // A little unwind to catch the really small ints.
    226   int snapshot_byte = Get();
    227   if ((snapshot_byte & 0x80) == 0) {
    228     return snapshot_byte;
    229   }
    230   int accumulator = (snapshot_byte & 0x7f) << 7;
    231   while (true) {
    232     snapshot_byte = Get();
    233     if ((snapshot_byte & 0x80) == 0) {
    234       return accumulator | snapshot_byte;
    235     }
    236     accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
    237   }
    238   UNREACHABLE();
    239   return accumulator;
    240 }
    241 
    242 
    243 void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
    244   memcpy(to, data_ + position_, number_of_bytes);
    245   position_ += number_of_bytes;
    246 }
    247 
    248 
    249 // A Deserializer reads a snapshot and reconstructs the Object graph it defines.
    250 class Deserializer: public SerializerDeserializer {
    251  public:
    252   // Create a deserializer from a snapshot byte source.
    253   explicit Deserializer(SnapshotByteSource* source);
    254 
    255   virtual ~Deserializer();
    256 
    257   // Deserialize the snapshot into an empty heap.
    258   void Deserialize();
    259 
    260   // Deserialize a single object and the objects reachable from it.
    261   void DeserializePartial(Object** root);
    262 
    263 #ifdef DEBUG
    264   virtual void Synchronize(const char* tag);
    265 #endif
    266 
    267  private:
    268   virtual void VisitPointers(Object** start, Object** end);
    269 
    270   virtual void VisitExternalReferences(Address* start, Address* end) {
    271     UNREACHABLE();
    272   }
    273 
    274   virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
    275     UNREACHABLE();
    276   }
    277 
    278   void ReadChunk(Object** start, Object** end, int space, Address address);
    279   HeapObject* GetAddressFromStart(int space);
    280   inline HeapObject* GetAddressFromEnd(int space);
    281   Address Allocate(int space_number, Space* space, int size);
    282   void ReadObject(int space_number, Space* space, Object** write_back);
    283 
    284   // Keep track of the pages in the paged spaces.
    285   // (In large object space we are keeping track of individual objects
    286   // rather than pages.)  In new space we just need the address of the
    287   // first object and the others will flow from that.
    288   List<Address> pages_[SerializerDeserializer::kNumberOfSpaces];
    289 
    290   SnapshotByteSource* source_;
    291   static ExternalReferenceDecoder* external_reference_decoder_;
    292   // This is the address of the next object that will be allocated in each
    293   // space.  It is used to calculate the addresses of back-references.
    294   Address high_water_[LAST_SPACE + 1];
    295   // This is the address of the most recent object that was allocated.  It
    296   // is used to set the location of the new page when we encounter a
    297   // START_NEW_PAGE_SERIALIZATION tag.
    298   Address last_object_address_;
    299 
    300   DISALLOW_COPY_AND_ASSIGN(Deserializer);
    301 };
    302 
    303 
    304 class SnapshotByteSink {
    305  public:
    306   virtual ~SnapshotByteSink() { }
    307   virtual void Put(int byte, const char* description) = 0;
    308   virtual void PutSection(int byte, const char* description) {
    309     Put(byte, description);
    310   }
    311   void PutInt(uintptr_t integer, const char* description);
    312   virtual int Position() = 0;
    313 };
    314 
    315 
    316 // Mapping objects to their location after deserialization.
    317 // This is used during building, but not at runtime by V8.
    318 class SerializationAddressMapper {
    319  public:
    320   SerializationAddressMapper()
    321       : serialization_map_(new HashMap(&SerializationMatchFun)),
    322         no_allocation_(new AssertNoAllocation()) { }
    323 
    324   ~SerializationAddressMapper() {
    325     delete serialization_map_;
    326     delete no_allocation_;
    327   }
    328 
    329   bool IsMapped(HeapObject* obj) {
    330     return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
    331   }
    332 
    333   int MappedTo(HeapObject* obj) {
    334     ASSERT(IsMapped(obj));
    335     return static_cast<int>(reinterpret_cast<intptr_t>(
    336         serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
    337   }
    338 
    339   void AddMapping(HeapObject* obj, int to) {
    340     ASSERT(!IsMapped(obj));
    341     HashMap::Entry* entry =
    342         serialization_map_->Lookup(Key(obj), Hash(obj), true);
    343     entry->value = Value(to);
    344   }
    345 
    346  private:
    347   static bool SerializationMatchFun(void* key1, void* key2) {
    348     return key1 == key2;
    349   }
    350 
    351   static uint32_t Hash(HeapObject* obj) {
    352     return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
    353   }
    354 
    355   static void* Key(HeapObject* obj) {
    356     return reinterpret_cast<void*>(obj->address());
    357   }
    358 
    359   static void* Value(int v) {
    360     return reinterpret_cast<void*>(v);
    361   }
    362 
    363   HashMap* serialization_map_;
    364   AssertNoAllocation* no_allocation_;
    365   DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
    366 };
    367 
    368 
    369 class Serializer : public SerializerDeserializer {
    370  public:
    371   explicit Serializer(SnapshotByteSink* sink);
    372   ~Serializer();
    373   void VisitPointers(Object** start, Object** end);
    374   // You can call this after serialization to find out how much space was used
    375   // in each space.
    376   int CurrentAllocationAddress(int space) {
    377     if (SpaceIsLarge(space)) return large_object_total_;
    378     return fullness_[space];
    379   }
    380 
    381   static void Enable() {
    382     if (!serialization_enabled_) {
    383       ASSERT(!too_late_to_enable_now_);
    384     }
    385     serialization_enabled_ = true;
    386   }
    387 
    388   static void Disable() { serialization_enabled_ = false; }
    389   // Call this when you have made use of the fact that there is no serialization
    390   // going on.
    391   static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
    392   static bool enabled() { return serialization_enabled_; }
    393   SerializationAddressMapper* address_mapper() { return &address_mapper_; }
    394 #ifdef DEBUG
    395   virtual void Synchronize(const char* tag);
    396 #endif
    397 
    398  protected:
    399   enum ReferenceRepresentation {
    400     TAGGED_REPRESENTATION,      // A tagged object reference.
    401     CODE_TARGET_REPRESENTATION  // A reference to first instruction in target.
    402   };
    403   static const int kInvalidRootIndex = -1;
    404   virtual int RootIndex(HeapObject* heap_object) = 0;
    405   virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
    406 
    407   class ObjectSerializer : public ObjectVisitor {
    408    public:
    409     ObjectSerializer(Serializer* serializer,
    410                      Object* o,
    411                      SnapshotByteSink* sink,
    412                      ReferenceRepresentation representation)
    413       : serializer_(serializer),
    414         object_(HeapObject::cast(o)),
    415         sink_(sink),
    416         reference_representation_(representation),
    417         bytes_processed_so_far_(0) { }
    418     void Serialize();
    419     void VisitPointers(Object** start, Object** end);
    420     void VisitExternalReferences(Address* start, Address* end);
    421     void VisitCodeTarget(RelocInfo* target);
    422     void VisitRuntimeEntry(RelocInfo* reloc);
    423     // Used for seralizing the external strings that hold the natives source.
    424     void VisitExternalAsciiString(
    425         v8::String::ExternalAsciiStringResource** resource);
    426     // We can't serialize a heap with external two byte strings.
    427     void VisitExternalTwoByteString(
    428         v8::String::ExternalStringResource** resource) {
    429       UNREACHABLE();
    430     }
    431 
    432    private:
    433     void OutputRawData(Address up_to);
    434 
    435     Serializer* serializer_;
    436     HeapObject* object_;
    437     SnapshotByteSink* sink_;
    438     ReferenceRepresentation reference_representation_;
    439     int bytes_processed_so_far_;
    440   };
    441 
    442   virtual void SerializeObject(Object* o,
    443                                ReferenceRepresentation representation) = 0;
    444   void SerializeReferenceToPreviousObject(
    445       int space,
    446       int address,
    447       ReferenceRepresentation reference_representation);
    448   void InitializeAllocators();
    449   // This will return the space for an object.  If the object is in large
    450   // object space it may return kLargeCode or kLargeFixedArray in order
    451   // to indicate to the deserializer what kind of large object allocation
    452   // to make.
    453   static int SpaceOfObject(HeapObject* object);
    454   // This just returns the space of the object.  It will return LO_SPACE
    455   // for all large objects since you can't check the type of the object
    456   // once the map has been used for the serialization address.
    457   static int SpaceOfAlreadySerializedObject(HeapObject* object);
    458   int Allocate(int space, int size, bool* new_page_started);
    459   int EncodeExternalReference(Address addr) {
    460     return external_reference_encoder_->Encode(addr);
    461   }
    462 
    463   // Keep track of the fullness of each space in order to generate
    464   // relative addresses for back references.  Large objects are
    465   // just numbered sequentially since relative addresses make no
    466   // sense in large object space.
    467   int fullness_[LAST_SPACE + 1];
    468   SnapshotByteSink* sink_;
    469   int current_root_index_;
    470   ExternalReferenceEncoder* external_reference_encoder_;
    471   static bool serialization_enabled_;
    472   // Did we already make use of the fact that serialization was not enabled?
    473   static bool too_late_to_enable_now_;
    474   int large_object_total_;
    475   SerializationAddressMapper address_mapper_;
    476 
    477   friend class ObjectSerializer;
    478   friend class Deserializer;
    479 
    480   DISALLOW_COPY_AND_ASSIGN(Serializer);
    481 };
    482 
    483 
    484 class PartialSerializer : public Serializer {
    485  public:
    486   PartialSerializer(Serializer* startup_snapshot_serializer,
    487                     SnapshotByteSink* sink)
    488     : Serializer(sink),
    489       startup_serializer_(startup_snapshot_serializer) {
    490   }
    491 
    492   // Serialize the objects reachable from a single object pointer.
    493   virtual void Serialize(Object** o);
    494   virtual void SerializeObject(Object* o,
    495                                ReferenceRepresentation representation);
    496 
    497  protected:
    498   virtual int RootIndex(HeapObject* o);
    499   virtual int PartialSnapshotCacheIndex(HeapObject* o);
    500   virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
    501     // Scripts should be referred only through shared function infos.  We can't
    502     // allow them to be part of the partial snapshot because they contain a
    503     // unique ID, and deserializing several partial snapshots containing script
    504     // would cause dupes.
    505     ASSERT(!o->IsScript());
    506     return o->IsString() || o->IsSharedFunctionInfo() || o->IsHeapNumber();
    507   }
    508 
    509  private:
    510   Serializer* startup_serializer_;
    511   DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
    512 };
    513 
    514 
    515 class StartupSerializer : public Serializer {
    516  public:
    517   explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) {
    518     // Clear the cache of objects used by the partial snapshot.  After the
    519     // strong roots have been serialized we can create a partial snapshot
    520     // which will repopulate the cache with objects neede by that partial
    521     // snapshot.
    522     partial_snapshot_cache_length_ = 0;
    523   }
    524   // Serialize the current state of the heap.  The order is:
    525   // 1) Strong references.
    526   // 2) Partial snapshot cache.
    527   // 3) Weak references (eg the symbol table).
    528   virtual void SerializeStrongReferences();
    529   virtual void SerializeObject(Object* o,
    530                                ReferenceRepresentation representation);
    531   void SerializeWeakReferences();
    532   void Serialize() {
    533     SerializeStrongReferences();
    534     SerializeWeakReferences();
    535   }
    536 
    537  private:
    538   virtual int RootIndex(HeapObject* o) { return kInvalidRootIndex; }
    539   virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
    540     return false;
    541   }
    542 };
    543 
    544 
    545 } }  // namespace v8::internal
    546 
    547 #endif  // V8_SERIALIZE_H_
    548