Home | History | Annotate | Download | only in snapshot
      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 #ifndef V8_SNAPSHOT_SERIALIZER_H_
      6 #define V8_SNAPSHOT_SERIALIZER_H_
      7 
      8 #include "src/isolate.h"
      9 #include "src/log.h"
     10 #include "src/objects.h"
     11 #include "src/snapshot/serializer-common.h"
     12 #include "src/snapshot/snapshot-source-sink.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 class CodeAddressMap : public CodeEventLogger {
     18  public:
     19   explicit CodeAddressMap(Isolate* isolate) : isolate_(isolate) {
     20     isolate->logger()->addCodeEventListener(this);
     21   }
     22 
     23   ~CodeAddressMap() override {
     24     isolate_->logger()->removeCodeEventListener(this);
     25   }
     26 
     27   void CodeMoveEvent(AbstractCode* from, Address to) override {
     28     address_to_name_map_.Move(from->address(), to);
     29   }
     30 
     31   void CodeDisableOptEvent(AbstractCode* code,
     32                            SharedFunctionInfo* shared) override {}
     33 
     34   const char* Lookup(Address address) {
     35     return address_to_name_map_.Lookup(address);
     36   }
     37 
     38  private:
     39   class NameMap {
     40    public:
     41     NameMap() : impl_() {}
     42 
     43     ~NameMap() {
     44       for (base::HashMap::Entry* p = impl_.Start(); p != NULL;
     45            p = impl_.Next(p)) {
     46         DeleteArray(static_cast<const char*>(p->value));
     47       }
     48     }
     49 
     50     void Insert(Address code_address, const char* name, int name_size) {
     51       base::HashMap::Entry* entry = FindOrCreateEntry(code_address);
     52       if (entry->value == NULL) {
     53         entry->value = CopyName(name, name_size);
     54       }
     55     }
     56 
     57     const char* Lookup(Address code_address) {
     58       base::HashMap::Entry* entry = FindEntry(code_address);
     59       return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
     60     }
     61 
     62     void Remove(Address code_address) {
     63       base::HashMap::Entry* entry = FindEntry(code_address);
     64       if (entry != NULL) {
     65         DeleteArray(static_cast<char*>(entry->value));
     66         RemoveEntry(entry);
     67       }
     68     }
     69 
     70     void Move(Address from, Address to) {
     71       if (from == to) return;
     72       base::HashMap::Entry* from_entry = FindEntry(from);
     73       DCHECK(from_entry != NULL);
     74       void* value = from_entry->value;
     75       RemoveEntry(from_entry);
     76       base::HashMap::Entry* to_entry = FindOrCreateEntry(to);
     77       DCHECK(to_entry->value == NULL);
     78       to_entry->value = value;
     79     }
     80 
     81    private:
     82     static char* CopyName(const char* name, int name_size) {
     83       char* result = NewArray<char>(name_size + 1);
     84       for (int i = 0; i < name_size; ++i) {
     85         char c = name[i];
     86         if (c == '\0') c = ' ';
     87         result[i] = c;
     88       }
     89       result[name_size] = '\0';
     90       return result;
     91     }
     92 
     93     base::HashMap::Entry* FindOrCreateEntry(Address code_address) {
     94       return impl_.LookupOrInsert(code_address,
     95                                   ComputePointerHash(code_address));
     96     }
     97 
     98     base::HashMap::Entry* FindEntry(Address code_address) {
     99       return impl_.Lookup(code_address, ComputePointerHash(code_address));
    100     }
    101 
    102     void RemoveEntry(base::HashMap::Entry* entry) {
    103       impl_.Remove(entry->key, entry->hash);
    104     }
    105 
    106     base::HashMap impl_;
    107 
    108     DISALLOW_COPY_AND_ASSIGN(NameMap);
    109   };
    110 
    111   void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*,
    112                          const char* name, int length) override {
    113     address_to_name_map_.Insert(code->address(), name, length);
    114   }
    115 
    116   NameMap address_to_name_map_;
    117   Isolate* isolate_;
    118 };
    119 
    120 // There can be only one serializer per V8 process.
    121 class Serializer : public SerializerDeserializer {
    122  public:
    123   explicit Serializer(Isolate* isolate);
    124   ~Serializer() override;
    125 
    126   void EncodeReservations(List<SerializedData::Reservation>* out) const;
    127 
    128   void SerializeDeferredObjects();
    129 
    130   Isolate* isolate() const { return isolate_; }
    131 
    132   SerializerReferenceMap* reference_map() { return &reference_map_; }
    133   RootIndexMap* root_index_map() { return &root_index_map_; }
    134 
    135 #ifdef OBJECT_PRINT
    136   void CountInstanceType(Map* map, int size);
    137 #endif  // OBJECT_PRINT
    138 
    139  protected:
    140   class ObjectSerializer;
    141   class RecursionScope {
    142    public:
    143     explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
    144       serializer_->recursion_depth_++;
    145     }
    146     ~RecursionScope() { serializer_->recursion_depth_--; }
    147     bool ExceedsMaximum() {
    148       return serializer_->recursion_depth_ >= kMaxRecursionDepth;
    149     }
    150 
    151    private:
    152     static const int kMaxRecursionDepth = 32;
    153     Serializer* serializer_;
    154   };
    155 
    156   virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
    157                                WhereToPoint where_to_point, int skip) = 0;
    158 
    159   void VisitPointers(Object** start, Object** end) override;
    160 
    161   void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
    162                int skip);
    163 
    164   void PutSmi(Smi* smi);
    165 
    166   void PutBackReference(HeapObject* object, SerializerReference reference);
    167 
    168   void PutAttachedReference(SerializerReference reference,
    169                             HowToCode how_to_code, WhereToPoint where_to_point);
    170 
    171   // Emit alignment prefix if necessary, return required padding space in bytes.
    172   int PutAlignmentPrefix(HeapObject* object);
    173 
    174   // Returns true if the object was successfully serialized as hot object.
    175   bool SerializeHotObject(HeapObject* obj, HowToCode how_to_code,
    176                           WhereToPoint where_to_point, int skip);
    177 
    178   // Returns true if the object was successfully serialized as back reference.
    179   bool SerializeBackReference(HeapObject* obj, HowToCode how_to_code,
    180                               WhereToPoint where_to_point, int skip);
    181 
    182   inline void FlushSkip(int skip) {
    183     if (skip != 0) {
    184       sink_.Put(kSkip, "SkipFromSerializeObject");
    185       sink_.PutInt(skip, "SkipDistanceFromSerializeObject");
    186     }
    187   }
    188 
    189   bool BackReferenceIsAlreadyAllocated(SerializerReference back_reference);
    190 
    191   // This will return the space for an object.
    192   SerializerReference AllocateLargeObject(int size);
    193   SerializerReference AllocateMap();
    194   SerializerReference Allocate(AllocationSpace space, int size);
    195   int EncodeExternalReference(Address addr) {
    196     return external_reference_encoder_.Encode(addr);
    197   }
    198 
    199   bool HasNotExceededFirstPageOfEachSpace();
    200 
    201   // GetInt reads 4 bytes at once, requiring padding at the end.
    202   void Pad();
    203 
    204   // We may not need the code address map for logging for every instance
    205   // of the serializer.  Initialize it on demand.
    206   void InitializeCodeAddressMap();
    207 
    208   Code* CopyCode(Code* code);
    209 
    210   inline uint32_t max_chunk_size(int space) const {
    211     DCHECK_LE(0, space);
    212     DCHECK_LT(space, kNumberOfSpaces);
    213     return max_chunk_size_[space];
    214   }
    215 
    216   const SnapshotByteSink* sink() const { return &sink_; }
    217 
    218   void QueueDeferredObject(HeapObject* obj) {
    219     DCHECK(reference_map_.Lookup(obj).is_back_reference());
    220     deferred_objects_.Add(obj);
    221   }
    222 
    223   void OutputStatistics(const char* name);
    224 
    225   Isolate* isolate_;
    226 
    227   SnapshotByteSink sink_;
    228   ExternalReferenceEncoder external_reference_encoder_;
    229 
    230   SerializerReferenceMap reference_map_;
    231   RootIndexMap root_index_map_;
    232 
    233   int recursion_depth_;
    234 
    235   friend class Deserializer;
    236   friend class ObjectSerializer;
    237   friend class RecursionScope;
    238   friend class SnapshotData;
    239 
    240  private:
    241   CodeAddressMap* code_address_map_;
    242   // Objects from the same space are put into chunks for bulk-allocation
    243   // when deserializing. We have to make sure that each chunk fits into a
    244   // page. So we track the chunk size in pending_chunk_ of a space, but
    245   // when it exceeds a page, we complete the current chunk and start a new one.
    246   uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
    247   List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
    248   uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
    249   // Number of maps that we need to allocate.
    250   uint32_t num_maps_;
    251 
    252   // We map serialized large objects to indexes for back-referencing.
    253   uint32_t large_objects_total_size_;
    254   uint32_t seen_large_objects_index_;
    255 
    256   List<byte> code_buffer_;
    257 
    258   // To handle stack overflow.
    259   List<HeapObject*> deferred_objects_;
    260 
    261 #ifdef OBJECT_PRINT
    262   static const int kInstanceTypes = 256;
    263   int* instance_type_count_;
    264   size_t* instance_type_size_;
    265 #endif  // OBJECT_PRINT
    266 
    267   DISALLOW_COPY_AND_ASSIGN(Serializer);
    268 };
    269 
    270 class Serializer::ObjectSerializer : public ObjectVisitor {
    271  public:
    272   ObjectSerializer(Serializer* serializer, HeapObject* obj,
    273                    SnapshotByteSink* sink, HowToCode how_to_code,
    274                    WhereToPoint where_to_point)
    275       : serializer_(serializer),
    276         object_(obj),
    277         sink_(sink),
    278         reference_representation_(how_to_code + where_to_point),
    279         bytes_processed_so_far_(0),
    280         code_has_been_output_(false) {}
    281   ~ObjectSerializer() override {}
    282   void Serialize();
    283   void SerializeDeferred();
    284   void VisitPointers(Object** start, Object** end) override;
    285   void VisitEmbeddedPointer(RelocInfo* target) override;
    286   void VisitExternalReference(Address* p) override;
    287   void VisitExternalReference(RelocInfo* rinfo) override;
    288   void VisitInternalReference(RelocInfo* rinfo) override;
    289   void VisitCodeTarget(RelocInfo* target) override;
    290   void VisitCodeEntry(Address entry_address) override;
    291   void VisitCell(RelocInfo* rinfo) override;
    292   void VisitRuntimeEntry(RelocInfo* reloc) override;
    293   // Used for seralizing the external strings that hold the natives source.
    294   void VisitExternalOneByteString(
    295       v8::String::ExternalOneByteStringResource** resource) override;
    296   // We can't serialize a heap with external two byte strings.
    297   void VisitExternalTwoByteString(
    298       v8::String::ExternalStringResource** resource) override {
    299     UNREACHABLE();
    300   }
    301 
    302  private:
    303   void SerializePrologue(AllocationSpace space, int size, Map* map);
    304 
    305   bool SerializeExternalNativeSourceString(
    306       int builtin_count,
    307       v8::String::ExternalOneByteStringResource** resource_pointer,
    308       FixedArray* source_cache, int resource_index);
    309 
    310   enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
    311   // This function outputs or skips the raw data between the last pointer and
    312   // up to the current position.  It optionally can just return the number of
    313   // bytes to skip instead of performing a skip instruction, in case the skip
    314   // can be merged into the next instruction.
    315   int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
    316   // External strings are serialized in a way to resemble sequential strings.
    317   void SerializeExternalString();
    318 
    319   Address PrepareCode();
    320 
    321   Serializer* serializer_;
    322   HeapObject* object_;
    323   SnapshotByteSink* sink_;
    324   int reference_representation_;
    325   int bytes_processed_so_far_;
    326   bool code_has_been_output_;
    327 };
    328 
    329 }  // namespace internal
    330 }  // namespace v8
    331 
    332 #endif  // V8_SNAPSHOT_SERIALIZER_H_
    333