1 // Copyright 2012 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_SERIALIZE_H_
6 #define V8_SNAPSHOT_SERIALIZE_H_
7 
8 #include "src/address-map.h"
9 #include "src/heap/heap.h"
10 #include "src/objects.h"
11 #include "src/snapshot/snapshot-source-sink.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 class Isolate;
17 class ScriptData;
18 
19 static const int kDeoptTableSerializeEntryCount = 64;
20 
21 // ExternalReferenceTable is a helper class that defines the relationship
22 // between external references and their encodings. It is used to build
23 // hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
24 class ExternalReferenceTable {
25  public:
26   static ExternalReferenceTable* instance(Isolate* isolate);
27 
size()28   int size() const { return refs_.length(); }
address(int i)29   Address address(int i) { return refs_[i].address; }
name(int i)30   const char* name(int i) { return refs_[i].name; }
31 
NotAvailable()32   inline static Address NotAvailable() { return NULL; }
33 
34  private:
35   struct ExternalReferenceEntry {
36     Address address;
37     const char* name;
38   };
39 
40   explicit ExternalReferenceTable(Isolate* isolate);
41 
Add(Address address,const char * name)42   void Add(Address address, const char* name) {
43     ExternalReferenceEntry entry = {address, name};
44     refs_.Add(entry);
45   }
46 
47   List<ExternalReferenceEntry> refs_;
48 
49   DISALLOW_COPY_AND_ASSIGN(ExternalReferenceTable);
50 };
51 
52 
53 class ExternalReferenceEncoder {
54  public:
55   explicit ExternalReferenceEncoder(Isolate* isolate);
56 
57   uint32_t Encode(Address key) const;
58 
59   const char* NameOfAddress(Isolate* isolate, Address address) const;
60 
61  private:
Hash(Address key)62   static uint32_t Hash(Address key) {
63     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >>
64                                  kPointerSizeLog2);
65   }
66 
67   HashMap* map_;
68 
69   DISALLOW_COPY_AND_ASSIGN(ExternalReferenceEncoder);
70 };
71 
72 
73 class PartialCacheIndexMap : public AddressMapBase {
74  public:
PartialCacheIndexMap()75   PartialCacheIndexMap() : map_(HashMap::PointersMatch) {}
76 
77   static const int kInvalidIndex = -1;
78 
79   // Lookup object in the map. Return its index if found, or create
80   // a new entry with new_index as value, and return kInvalidIndex.
LookupOrInsert(HeapObject * obj,int new_index)81   int LookupOrInsert(HeapObject* obj, int new_index) {
82     HashMap::Entry* entry = LookupEntry(&map_, obj, false);
83     if (entry != NULL) return GetValue(entry);
84     SetValue(LookupEntry(&map_, obj, true), static_cast<uint32_t>(new_index));
85     return kInvalidIndex;
86   }
87 
88  private:
89   HashMap map_;
90 
91   DISALLOW_COPY_AND_ASSIGN(PartialCacheIndexMap);
92 };
93 
94 
95 class HotObjectsList {
96  public:
HotObjectsList()97   HotObjectsList() : index_(0) {
98     for (int i = 0; i < kSize; i++) circular_queue_[i] = NULL;
99   }
100 
Add(HeapObject * object)101   void Add(HeapObject* object) {
102     circular_queue_[index_] = object;
103     index_ = (index_ + 1) & kSizeMask;
104   }
105 
Get(int index)106   HeapObject* Get(int index) {
107     DCHECK_NOT_NULL(circular_queue_[index]);
108     return circular_queue_[index];
109   }
110 
111   static const int kNotFound = -1;
112 
Find(HeapObject * object)113   int Find(HeapObject* object) {
114     for (int i = 0; i < kSize; i++) {
115       if (circular_queue_[i] == object) return i;
116     }
117     return kNotFound;
118   }
119 
120   static const int kSize = 8;
121 
122  private:
123   STATIC_ASSERT(IS_POWER_OF_TWO(kSize));
124   static const int kSizeMask = kSize - 1;
125   HeapObject* circular_queue_[kSize];
126   int index_;
127 
128   DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
129 };
130 
131 
132 // The Serializer/Deserializer class is a common superclass for Serializer and
133 // Deserializer which is used to store common constants and methods used by
134 // both.
135 class SerializerDeserializer: public ObjectVisitor {
136  public:
137   static void Iterate(Isolate* isolate, ObjectVisitor* visitor);
138 
139   // No reservation for large object space necessary.
140   static const int kNumberOfPreallocatedSpaces = LAST_PAGED_SPACE + 1;
141   static const int kNumberOfSpaces = LAST_SPACE + 1;
142 
143  protected:
144   static bool CanBeDeferred(HeapObject* o);
145 
146   // ---------- byte code range 0x00..0x7f ----------
147   // Byte codes in this range represent Where, HowToCode and WhereToPoint.
148   // Where the pointed-to object can be found:
149   // The static assert below will trigger when the number of preallocated spaces
150   // changed. If that happens, update the bytecode ranges in the comments below.
151   STATIC_ASSERT(5 == kNumberOfSpaces);
152   enum Where {
153     // 0x00..0x04  Allocate new object, in specified space.
154     kNewObject = 0,
155     // 0x05        Unused (including 0x25, 0x45, 0x65).
156     // 0x06        Unused (including 0x26, 0x46, 0x66).
157     // 0x07        Unused (including 0x27, 0x47, 0x67).
158     // 0x08..0x0c  Reference to previous object from space.
159     kBackref = 0x08,
160     // 0x0d        Unused (including 0x2d, 0x4d, 0x6d).
161     // 0x0e        Unused (including 0x2e, 0x4e, 0x6e).
162     // 0x0f        Unused (including 0x2f, 0x4f, 0x6f).
163     // 0x10..0x14  Reference to previous object from space after skip.
164     kBackrefWithSkip = 0x10,
165     // 0x15        Unused (including 0x35, 0x55, 0x75).
166     // 0x16        Unused (including 0x36, 0x56, 0x76).
167     // 0x17        Misc (including 0x37, 0x57, 0x77).
168     // 0x18        Root array item.
169     kRootArray = 0x18,
170     // 0x19        Object in the partial snapshot cache.
171     kPartialSnapshotCache = 0x19,
172     // 0x1a        External reference referenced by id.
173     kExternalReference = 0x1a,
174     // 0x1b        Object provided in the attached list.
175     kAttachedReference = 0x1b,
176     // 0x1c        Builtin code referenced by index.
177     kBuiltin = 0x1c
178     // 0x1d..0x1f  Misc (including 0x3d..0x3f, 0x5d..0x5f, 0x7d..0x7f)
179   };
180 
181   static const int kWhereMask = 0x1f;
182   static const int kSpaceMask = 7;
183   STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
184 
185   // How to code the pointer to the object.
186   enum HowToCode {
187     // Straight pointer.
188     kPlain = 0,
189     // A pointer inlined in code. What this means depends on the architecture.
190     kFromCode = 0x20
191   };
192 
193   static const int kHowToCodeMask = 0x20;
194 
195   // Where to point within the object.
196   enum WhereToPoint {
197     // Points to start of object
198     kStartOfObject = 0,
199     // Points to instruction in code object or payload of cell.
200     kInnerPointer = 0x40
201   };
202 
203   static const int kWhereToPointMask = 0x40;
204 
205   // ---------- Misc ----------
206   // Skip.
207   static const int kSkip = 0x1d;
208   // Internal reference encoded as offsets of pc and target from code entry.
209   static const int kInternalReference = 0x1e;
210   static const int kInternalReferenceEncoded = 0x1f;
211   // Do nothing, used for padding.
212   static const int kNop = 0x3d;
213   // Move to next reserved chunk.
214   static const int kNextChunk = 0x3e;
215   // Deferring object content.
216   static const int kDeferred = 0x3f;
217   // Used for the source code of the natives, which is in the executable, but
218   // is referred to from external strings in the snapshot.
219   static const int kNativesStringResource = 0x5d;
220   // Used for the source code for compiled stubs, which is in the executable,
221   // but is referred to from external strings in the snapshot.
222   static const int kExtraNativesStringResource = 0x5e;
223   // A tag emitted at strategic points in the snapshot to delineate sections.
224   // If the deserializer does not find these at the expected moments then it
225   // is an indication that the snapshot and the VM do not fit together.
226   // Examine the build process for architecture, version or configuration
227   // mismatches.
228   static const int kSynchronize = 0x17;
229   // Repeats of variable length.
230   static const int kVariableRepeat = 0x37;
231   // Raw data of variable length.
232   static const int kVariableRawData = 0x57;
233   // Alignment prefixes 0x7d..0x7f
234   static const int kAlignmentPrefix = 0x7d;
235 
236   // 0x77 unused
237 
238   // ---------- byte code range 0x80..0xff ----------
239   // First 32 root array items.
240   static const int kNumberOfRootArrayConstants = 0x20;
241   // 0x80..0x9f
242   static const int kRootArrayConstants = 0x80;
243   // 0xa0..0xbf
244   static const int kRootArrayConstantsWithSkip = 0xa0;
245   static const int kRootArrayConstantsMask = 0x1f;
246 
247   // 8 hot (recently seen or back-referenced) objects with optional skip.
248   static const int kNumberOfHotObjects = 0x08;
249   // 0xc0..0xc7
250   static const int kHotObject = 0xc0;
251   // 0xc8..0xcf
252   static const int kHotObjectWithSkip = 0xc8;
253   static const int kHotObjectMask = 0x07;
254 
255   // 32 common raw data lengths.
256   static const int kNumberOfFixedRawData = 0x20;
257   // 0xd0..0xef
258   static const int kFixedRawData = 0xd0;
259   static const int kOnePointerRawData = kFixedRawData;
260   static const int kFixedRawDataStart = kFixedRawData - 1;
261 
262   // 16 repeats lengths.
263   static const int kNumberOfFixedRepeat = 0x10;
264   // 0xf0..0xff
265   static const int kFixedRepeat = 0xf0;
266   static const int kFixedRepeatStart = kFixedRepeat - 1;
267 
268   // ---------- special values ----------
269   static const int kAnyOldSpace = -1;
270 
271   // Sentinel after a new object to indicate that double alignment is needed.
272   static const int kDoubleAlignmentSentinel = 0;
273 
274   // Used as index for the attached reference representing the source object.
275   static const int kSourceObjectReference = 0;
276 
277   // Used as index for the attached reference representing the global proxy.
278   static const int kGlobalProxyReference = 0;
279 
280   // ---------- member variable ----------
281   HotObjectsList hot_objects_;
282 };
283 
284 
285 class SerializedData {
286  public:
287   class Reservation {
288    public:
Reservation(uint32_t size)289     explicit Reservation(uint32_t size)
290         : reservation_(ChunkSizeBits::encode(size)) {}
291 
chunk_size()292     uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation_); }
is_last()293     bool is_last() const { return IsLastChunkBits::decode(reservation_); }
294 
mark_as_last()295     void mark_as_last() { reservation_ |= IsLastChunkBits::encode(true); }
296 
297    private:
298     uint32_t reservation_;
299   };
300 
SerializedData(byte * data,int size)301   SerializedData(byte* data, int size)
302       : data_(data), size_(size), owns_data_(false) {}
SerializedData()303   SerializedData() : data_(NULL), size_(0), owns_data_(false) {}
304 
~SerializedData()305   ~SerializedData() {
306     if (owns_data_) DeleteArray<byte>(data_);
307   }
308 
GetMagicNumber()309   uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
310 
311   class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
312   class IsLastChunkBits : public BitField<bool, 31, 1> {};
313 
ComputeMagicNumber(ExternalReferenceTable * table)314   static uint32_t ComputeMagicNumber(ExternalReferenceTable* table) {
315     uint32_t external_refs = table->size();
316     return 0xC0DE0000 ^ external_refs;
317   }
318 
319  protected:
SetHeaderValue(int offset,uint32_t value)320   void SetHeaderValue(int offset, uint32_t value) {
321     uint32_t* address = reinterpret_cast<uint32_t*>(data_ + offset);
322     memcpy(reinterpret_cast<uint32_t*>(address), &value, sizeof(value));
323   }
324 
GetHeaderValue(int offset)325   uint32_t GetHeaderValue(int offset) const {
326     uint32_t value;
327     memcpy(&value, reinterpret_cast<int*>(data_ + offset), sizeof(value));
328     return value;
329   }
330 
331   void AllocateData(int size);
332 
ComputeMagicNumber(Isolate * isolate)333   static uint32_t ComputeMagicNumber(Isolate* isolate) {
334     return ComputeMagicNumber(ExternalReferenceTable::instance(isolate));
335   }
336 
SetMagicNumber(Isolate * isolate)337   void SetMagicNumber(Isolate* isolate) {
338     SetHeaderValue(kMagicNumberOffset, ComputeMagicNumber(isolate));
339   }
340 
341   static const int kMagicNumberOffset = 0;
342 
343   byte* data_;
344   int size_;
345   bool owns_data_;
346 };
347 
348 
349 // A Deserializer reads a snapshot and reconstructs the Object graph it defines.
350 class Deserializer: public SerializerDeserializer {
351  public:
352   // Create a deserializer from a snapshot byte source.
353   template <class Data>
Deserializer(Data * data)354   explicit Deserializer(Data* data)
355       : isolate_(NULL),
356         source_(data->Payload()),
357         magic_number_(data->GetMagicNumber()),
358         external_reference_table_(NULL),
359         deserialized_large_objects_(0),
360         deserializing_user_code_(false),
361         next_alignment_(kWordAligned) {
362     DecodeReservation(data->Reservations());
363   }
364 
365   ~Deserializer() override;
366 
367   // Deserialize the snapshot into an empty heap.
368   void Deserialize(Isolate* isolate);
369 
370   // Deserialize a single object and the objects reachable from it.
371   MaybeHandle<Object> DeserializePartial(Isolate* isolate,
372                                          Handle<JSGlobalProxy> global_proxy);
373 
374   // Deserialize a shared function info. Fail gracefully.
375   MaybeHandle<SharedFunctionInfo> DeserializeCode(Isolate* isolate);
376 
377   // Pass a vector of externally-provided objects referenced by the snapshot.
378   // The ownership to its backing store is handed over as well.
SetAttachedObjects(Vector<Handle<Object>> attached_objects)379   void SetAttachedObjects(Vector<Handle<Object> > attached_objects) {
380     attached_objects_ = attached_objects;
381   }
382 
383  private:
384   void VisitPointers(Object** start, Object** end) override;
385 
VisitRuntimeEntry(RelocInfo * rinfo)386   void VisitRuntimeEntry(RelocInfo* rinfo) override { UNREACHABLE(); }
387 
388   void Initialize(Isolate* isolate);
389 
deserializing_user_code()390   bool deserializing_user_code() { return deserializing_user_code_; }
391 
392   void DecodeReservation(Vector<const SerializedData::Reservation> res);
393 
394   bool ReserveSpace();
395 
UnalignedCopy(Object ** dest,Object ** src)396   void UnalignedCopy(Object** dest, Object** src) {
397     memcpy(dest, src, sizeof(*src));
398   }
399 
SetAlignment(byte data)400   void SetAlignment(byte data) {
401     DCHECK_EQ(kWordAligned, next_alignment_);
402     int alignment = data - (kAlignmentPrefix - 1);
403     DCHECK_LE(kWordAligned, alignment);
404     DCHECK_LE(alignment, kSimd128Unaligned);
405     next_alignment_ = static_cast<AllocationAlignment>(alignment);
406   }
407 
408   void DeserializeDeferredObjects();
409 
410   void FlushICacheForNewIsolate();
411   void FlushICacheForNewCodeObjects();
412 
413   void CommitPostProcessedObjects(Isolate* isolate);
414 
415   // Fills in some heap data in an area from start to end (non-inclusive).  The
416   // space id is used for the write barrier.  The object_address is the address
417   // of the object we are writing into, or NULL if we are not writing into an
418   // object, i.e. if we are writing a series of tagged values that are not on
419   // the heap. Return false if the object content has been deferred.
420   bool ReadData(Object** start, Object** end, int space,
421                 Address object_address);
422   void ReadObject(int space_number, Object** write_back);
423   Address Allocate(int space_index, int size);
424 
425   // Special handling for serialized code like hooking up internalized strings.
426   HeapObject* PostProcessNewObject(HeapObject* obj, int space);
427 
428   // This returns the address of an object that has been described in the
429   // snapshot by chunk index and offset.
430   HeapObject* GetBackReferencedObject(int space);
431 
432   Object** CopyInNativesSource(Vector<const char> source_vector,
433                                Object** current);
434 
435   // Cached current isolate.
436   Isolate* isolate_;
437 
438   // Objects from the attached object descriptions in the serialized user code.
439   Vector<Handle<Object> > attached_objects_;
440 
441   SnapshotByteSource source_;
442   uint32_t magic_number_;
443 
444   // The address of the next object that will be allocated in each space.
445   // Each space has a number of chunks reserved by the GC, with each chunk
446   // fitting into a page. Deserialized objects are allocated into the
447   // current chunk of the target space by bumping up high water mark.
448   Heap::Reservation reservations_[kNumberOfSpaces];
449   uint32_t current_chunk_[kNumberOfPreallocatedSpaces];
450   Address high_water_[kNumberOfPreallocatedSpaces];
451 
452   ExternalReferenceTable* external_reference_table_;
453 
454   List<HeapObject*> deserialized_large_objects_;
455   List<Code*> new_code_objects_;
456   List<Handle<String> > new_internalized_strings_;
457   List<Handle<Script> > new_scripts_;
458 
459   bool deserializing_user_code_;
460 
461   AllocationAlignment next_alignment_;
462 
463   DISALLOW_COPY_AND_ASSIGN(Deserializer);
464 };
465 
466 
467 class CodeAddressMap;
468 
469 // There can be only one serializer per V8 process.
470 class Serializer : public SerializerDeserializer {
471  public:
472   Serializer(Isolate* isolate, SnapshotByteSink* sink);
473   ~Serializer() override;
474   void VisitPointers(Object** start, Object** end) override;
475 
476   void EncodeReservations(List<SerializedData::Reservation>* out) const;
477 
478   void SerializeDeferredObjects();
479 
isolate()480   Isolate* isolate() const { return isolate_; }
481 
back_reference_map()482   BackReferenceMap* back_reference_map() { return &back_reference_map_; }
root_index_map()483   RootIndexMap* root_index_map() { return &root_index_map_; }
484 
485 #ifdef OBJECT_PRINT
486   void CountInstanceType(Map* map, int size);
487 #endif  // OBJECT_PRINT
488 
489  protected:
490   class ObjectSerializer;
491   class RecursionScope {
492    public:
RecursionScope(Serializer * serializer)493     explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
494       serializer_->recursion_depth_++;
495     }
~RecursionScope()496     ~RecursionScope() { serializer_->recursion_depth_--; }
ExceedsMaximum()497     bool ExceedsMaximum() {
498       return serializer_->recursion_depth_ >= kMaxRecursionDepth;
499     }
500 
501    private:
502     static const int kMaxRecursionDepth = 32;
503     Serializer* serializer_;
504   };
505 
506   virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
507                                WhereToPoint where_to_point, int skip) = 0;
508 
509   void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
510                int skip);
511 
512   void PutBackReference(HeapObject* object, BackReference reference);
513 
514   // Emit alignment prefix if necessary, return required padding space in bytes.
515   int PutAlignmentPrefix(HeapObject* object);
516 
517   // Returns true if the object was successfully serialized.
518   bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
519                             WhereToPoint where_to_point, int skip);
520 
FlushSkip(int skip)521   inline void FlushSkip(int skip) {
522     if (skip != 0) {
523       sink_->Put(kSkip, "SkipFromSerializeObject");
524       sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
525     }
526   }
527 
528   bool BackReferenceIsAlreadyAllocated(BackReference back_reference);
529 
530   // This will return the space for an object.
531   BackReference AllocateLargeObject(int size);
532   BackReference Allocate(AllocationSpace space, int size);
EncodeExternalReference(Address addr)533   int EncodeExternalReference(Address addr) {
534     return external_reference_encoder_.Encode(addr);
535   }
536 
537   // GetInt reads 4 bytes at once, requiring padding at the end.
538   void Pad();
539 
540   // Some roots should not be serialized, because their actual value depends on
541   // absolute addresses and they are reset after deserialization, anyway.
542   bool ShouldBeSkipped(Object** current);
543 
544   // We may not need the code address map for logging for every instance
545   // of the serializer.  Initialize it on demand.
546   void InitializeCodeAddressMap();
547 
548   Code* CopyCode(Code* code);
549 
max_chunk_size(int space)550   inline uint32_t max_chunk_size(int space) const {
551     DCHECK_LE(0, space);
552     DCHECK_LT(space, kNumberOfSpaces);
553     return max_chunk_size_[space];
554   }
555 
sink()556   SnapshotByteSink* sink() const { return sink_; }
557 
QueueDeferredObject(HeapObject * obj)558   void QueueDeferredObject(HeapObject* obj) {
559     DCHECK(back_reference_map_.Lookup(obj).is_valid());
560     deferred_objects_.Add(obj);
561   }
562 
563   void OutputStatistics(const char* name);
564 
565   Isolate* isolate_;
566 
567   SnapshotByteSink* sink_;
568   ExternalReferenceEncoder external_reference_encoder_;
569 
570   BackReferenceMap back_reference_map_;
571   RootIndexMap root_index_map_;
572 
573   int recursion_depth_;
574 
575   friend class Deserializer;
576   friend class ObjectSerializer;
577   friend class RecursionScope;
578   friend class SnapshotData;
579 
580  private:
581   CodeAddressMap* code_address_map_;
582   // Objects from the same space are put into chunks for bulk-allocation
583   // when deserializing. We have to make sure that each chunk fits into a
584   // page. So we track the chunk size in pending_chunk_ of a space, but
585   // when it exceeds a page, we complete the current chunk and start a new one.
586   uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
587   List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
588   uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
589 
590   // We map serialized large objects to indexes for back-referencing.
591   uint32_t large_objects_total_size_;
592   uint32_t seen_large_objects_index_;
593 
594   List<byte> code_buffer_;
595 
596   // To handle stack overflow.
597   List<HeapObject*> deferred_objects_;
598 
599 #ifdef OBJECT_PRINT
600   static const int kInstanceTypes = 256;
601   int* instance_type_count_;
602   size_t* instance_type_size_;
603 #endif  // OBJECT_PRINT
604 
605   DISALLOW_COPY_AND_ASSIGN(Serializer);
606 };
607 
608 
609 class PartialSerializer : public Serializer {
610  public:
PartialSerializer(Isolate * isolate,Serializer * startup_snapshot_serializer,SnapshotByteSink * sink)611   PartialSerializer(Isolate* isolate, Serializer* startup_snapshot_serializer,
612                     SnapshotByteSink* sink)
613       : Serializer(isolate, sink),
614         startup_serializer_(startup_snapshot_serializer),
615         global_object_(NULL) {
616     InitializeCodeAddressMap();
617   }
618 
~PartialSerializer()619   ~PartialSerializer() override { OutputStatistics("PartialSerializer"); }
620 
621   // Serialize the objects reachable from a single object pointer.
622   void Serialize(Object** o);
623   void SerializeObject(HeapObject* o, HowToCode how_to_code,
624                        WhereToPoint where_to_point, int skip) override;
625 
626  private:
627   int PartialSnapshotCacheIndex(HeapObject* o);
628   bool ShouldBeInThePartialSnapshotCache(HeapObject* o);
629 
630   Serializer* startup_serializer_;
631   Object* global_object_;
632   PartialCacheIndexMap partial_cache_index_map_;
633   DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
634 };
635 
636 
637 class StartupSerializer : public Serializer {
638  public:
639   StartupSerializer(Isolate* isolate, SnapshotByteSink* sink);
~StartupSerializer()640   ~StartupSerializer() override { OutputStatistics("StartupSerializer"); }
641 
642   // The StartupSerializer has to serialize the root array, which is slightly
643   // different.
644   void VisitPointers(Object** start, Object** end) override;
645 
646   // Serialize the current state of the heap.  The order is:
647   // 1) Strong references.
648   // 2) Partial snapshot cache.
649   // 3) Weak references (e.g. the string table).
650   virtual void SerializeStrongReferences();
651   void SerializeObject(HeapObject* o, HowToCode how_to_code,
652                        WhereToPoint where_to_point, int skip) override;
653   void SerializeWeakReferencesAndDeferred();
654 
655  private:
656   intptr_t root_index_wave_front_;
657   DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
658 };
659 
660 
661 class CodeSerializer : public Serializer {
662  public:
663   static ScriptData* Serialize(Isolate* isolate,
664                                Handle<SharedFunctionInfo> info,
665                                Handle<String> source);
666 
667   MUST_USE_RESULT static MaybeHandle<SharedFunctionInfo> Deserialize(
668       Isolate* isolate, ScriptData* cached_data, Handle<String> source);
669 
670   static const int kSourceObjectIndex = 0;
671   STATIC_ASSERT(kSourceObjectReference == kSourceObjectIndex);
672 
673   static const int kCodeStubsBaseIndex = 1;
674 
source()675   String* source() const {
676     DCHECK(!AllowHeapAllocation::IsAllowed());
677     return source_;
678   }
679 
stub_keys()680   const List<uint32_t>* stub_keys() const { return &stub_keys_; }
681 
682  private:
CodeSerializer(Isolate * isolate,SnapshotByteSink * sink,String * source)683   CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source)
684       : Serializer(isolate, sink), source_(source) {
685     back_reference_map_.AddSourceString(source);
686   }
687 
~CodeSerializer()688   ~CodeSerializer() override { OutputStatistics("CodeSerializer"); }
689 
690   void SerializeObject(HeapObject* o, HowToCode how_to_code,
691                        WhereToPoint where_to_point, int skip) override;
692 
693   void SerializeBuiltin(int builtin_index, HowToCode how_to_code,
694                         WhereToPoint where_to_point);
695   void SerializeIC(Code* ic, HowToCode how_to_code,
696                    WhereToPoint where_to_point);
697   void SerializeCodeStub(uint32_t stub_key, HowToCode how_to_code,
698                          WhereToPoint where_to_point);
699   void SerializeGeneric(HeapObject* heap_object, HowToCode how_to_code,
700                         WhereToPoint where_to_point);
701   int AddCodeStubKey(uint32_t stub_key);
702 
703   DisallowHeapAllocation no_gc_;
704   String* source_;
705   List<uint32_t> stub_keys_;
706   DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
707 };
708 
709 
710 // Wrapper around reservation sizes and the serialization payload.
711 class SnapshotData : public SerializedData {
712  public:
713   // Used when producing.
714   explicit SnapshotData(const Serializer& ser);
715 
716   // Used when consuming.
SnapshotData(const Vector<const byte> snapshot)717   explicit SnapshotData(const Vector<const byte> snapshot)
718       : SerializedData(const_cast<byte*>(snapshot.begin()), snapshot.length()) {
719     CHECK(IsSane());
720   }
721 
722   Vector<const Reservation> Reservations() const;
723   Vector<const byte> Payload() const;
724 
RawData()725   Vector<const byte> RawData() const {
726     return Vector<const byte>(data_, size_);
727   }
728 
729  private:
730   bool IsSane();
731 
732   // The data header consists of uint32_t-sized entries:
733   // [0] magic number and external reference count
734   // [1] version hash
735   // [2] number of reservation size entries
736   // [3] payload length
737   // ... reservations
738   // ... serialized payload
739   static const int kCheckSumOffset = kMagicNumberOffset + kInt32Size;
740   static const int kNumReservationsOffset = kCheckSumOffset + kInt32Size;
741   static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size;
742   static const int kHeaderSize = kPayloadLengthOffset + kInt32Size;
743 };
744 
745 
746 // Wrapper around ScriptData to provide code-serializer-specific functionality.
747 class SerializedCodeData : public SerializedData {
748  public:
749   // Used when consuming.
750   static SerializedCodeData* FromCachedData(Isolate* isolate,
751                                             ScriptData* cached_data,
752                                             String* source);
753 
754   // Used when producing.
755   SerializedCodeData(const List<byte>& payload, const CodeSerializer& cs);
756 
757   // Return ScriptData object and relinquish ownership over it to the caller.
758   ScriptData* GetScriptData();
759 
760   Vector<const Reservation> Reservations() const;
761   Vector<const byte> Payload() const;
762 
763   Vector<const uint32_t> CodeStubKeys() const;
764 
765  private:
766   explicit SerializedCodeData(ScriptData* data);
767 
768   enum SanityCheckResult {
769     CHECK_SUCCESS = 0,
770     MAGIC_NUMBER_MISMATCH = 1,
771     VERSION_MISMATCH = 2,
772     SOURCE_MISMATCH = 3,
773     CPU_FEATURES_MISMATCH = 4,
774     FLAGS_MISMATCH = 5,
775     CHECKSUM_MISMATCH = 6
776   };
777 
778   SanityCheckResult SanityCheck(Isolate* isolate, String* source) const;
779 
780   uint32_t SourceHash(String* source) const;
781 
782   // The data header consists of uint32_t-sized entries:
783   // [0] magic number and external reference count
784   // [1] version hash
785   // [2] source hash
786   // [3] cpu features
787   // [4] flag hash
788   // [5] number of code stub keys
789   // [6] number of reservation size entries
790   // [7] payload length
791   // [8] payload checksum part 1
792   // [9] payload checksum part 2
793   // ...  reservations
794   // ...  code stub keys
795   // ...  serialized payload
796   static const int kVersionHashOffset = kMagicNumberOffset + kInt32Size;
797   static const int kSourceHashOffset = kVersionHashOffset + kInt32Size;
798   static const int kCpuFeaturesOffset = kSourceHashOffset + kInt32Size;
799   static const int kFlagHashOffset = kCpuFeaturesOffset + kInt32Size;
800   static const int kNumReservationsOffset = kFlagHashOffset + kInt32Size;
801   static const int kNumCodeStubKeysOffset = kNumReservationsOffset + kInt32Size;
802   static const int kPayloadLengthOffset = kNumCodeStubKeysOffset + kInt32Size;
803   static const int kChecksum1Offset = kPayloadLengthOffset + kInt32Size;
804   static const int kChecksum2Offset = kChecksum1Offset + kInt32Size;
805   static const int kHeaderSize = kChecksum2Offset + kInt32Size;
806 };
807 }  // namespace internal
808 }  // namespace v8
809 
810 #endif  // V8_SNAPSHOT_SERIALIZE_H_
811