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_SERIALIZE_H_
6#define V8_SERIALIZE_H_
7
8#include "src/compiler.h"
9#include "src/hashmap.h"
10#include "src/heap-profiler.h"
11#include "src/isolate.h"
12#include "src/snapshot-source-sink.h"
13
14namespace v8 {
15namespace internal {
16
17// A TypeCode is used to distinguish different kinds of external reference.
18// It is a single bit to make testing for types easy.
19enum TypeCode {
20  UNCLASSIFIED,  // One-of-a-kind references.
21  C_BUILTIN,
22  BUILTIN,
23  RUNTIME_FUNCTION,
24  IC_UTILITY,
25  STATS_COUNTER,
26  TOP_ADDRESS,
27  ACCESSOR,
28  STUB_CACHE_TABLE,
29  RUNTIME_ENTRY,
30  LAZY_DEOPTIMIZATION
31};
32
33const int kTypeCodeCount = LAZY_DEOPTIMIZATION + 1;
34const int kFirstTypeCode = UNCLASSIFIED;
35
36const int kReferenceIdBits = 16;
37const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
38const int kReferenceTypeShift = kReferenceIdBits;
39
40const int kDeoptTableSerializeEntryCount = 64;
41
42// ExternalReferenceTable is a helper class that defines the relationship
43// between external references and their encodings. It is used to build
44// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
45class ExternalReferenceTable {
46 public:
47  static ExternalReferenceTable* instance(Isolate* isolate);
48
49  ~ExternalReferenceTable() { }
50
51  int size() const { return refs_.length(); }
52
53  Address address(int i) { return refs_[i].address; }
54
55  uint32_t code(int i) { return refs_[i].code; }
56
57  const char* name(int i) { return refs_[i].name; }
58
59  int max_id(int code) { return max_id_[code]; }
60
61 private:
62  explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
63    PopulateTable(isolate);
64  }
65
66  struct ExternalReferenceEntry {
67    Address address;
68    uint32_t code;
69    const char* name;
70  };
71
72  void PopulateTable(Isolate* isolate);
73
74  // For a few types of references, we can get their address from their id.
75  void AddFromId(TypeCode type,
76                 uint16_t id,
77                 const char* name,
78                 Isolate* isolate);
79
80  // For other types of references, the caller will figure out the address.
81  void Add(Address address, TypeCode type, uint16_t id, const char* name);
82
83  void Add(Address address, const char* name) {
84    Add(address, UNCLASSIFIED, ++max_id_[UNCLASSIFIED], name);
85  }
86
87  List<ExternalReferenceEntry> refs_;
88  uint16_t max_id_[kTypeCodeCount];
89};
90
91
92class ExternalReferenceEncoder {
93 public:
94  explicit ExternalReferenceEncoder(Isolate* isolate);
95
96  uint32_t Encode(Address key) const;
97
98  const char* NameOfAddress(Address key) const;
99
100 private:
101  HashMap encodings_;
102  static uint32_t Hash(Address key) {
103    return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
104  }
105
106  int IndexOf(Address key) const;
107
108  void Put(Address key, int index);
109
110  Isolate* isolate_;
111};
112
113
114class ExternalReferenceDecoder {
115 public:
116  explicit ExternalReferenceDecoder(Isolate* isolate);
117  ~ExternalReferenceDecoder();
118
119  Address Decode(uint32_t key) const {
120    if (key == 0) return NULL;
121    return *Lookup(key);
122  }
123
124 private:
125  Address** encodings_;
126
127  Address* Lookup(uint32_t key) const {
128    int type = key >> kReferenceTypeShift;
129    DCHECK(kFirstTypeCode <= type && type < kTypeCodeCount);
130    int id = key & kReferenceIdMask;
131    return &encodings_[type][id];
132  }
133
134  void Put(uint32_t key, Address value) {
135    *Lookup(key) = value;
136  }
137
138  Isolate* isolate_;
139};
140
141
142// The Serializer/Deserializer class is a common superclass for Serializer and
143// Deserializer which is used to store common constants and methods used by
144// both.
145class SerializerDeserializer: public ObjectVisitor {
146 public:
147  static void Iterate(Isolate* isolate, ObjectVisitor* visitor);
148
149  static int nop() { return kNop; }
150
151 protected:
152  // Where the pointed-to object can be found:
153  enum Where {
154    kNewObject = 0,  // Object is next in snapshot.
155    // 1-6                             One per space.
156    kRootArray = 0x9,             // Object is found in root array.
157    kPartialSnapshotCache = 0xa,  // Object is in the cache.
158    kExternalReference = 0xb,     // Pointer to an external reference.
159    kSkip = 0xc,                  // Skip n bytes.
160    kBuiltin = 0xd,               // Builtin code object.
161    kAttachedReference = 0xe,     // Object is described in an attached list.
162    kNop = 0xf,                   // Does nothing, used to pad.
163    kBackref = 0x10,              // Object is described relative to end.
164    // 0x11-0x16                       One per space.
165    kBackrefWithSkip = 0x18,  // Object is described relative to end.
166    // 0x19-0x1e                       One per space.
167    // 0x20-0x3f                       Used by misc. tags below.
168    kPointedToMask = 0x3f
169  };
170
171  // How to code the pointer to the object.
172  enum HowToCode {
173    kPlain = 0,                          // Straight pointer.
174    // What this means depends on the architecture:
175    kFromCode = 0x40,                    // A pointer inlined in code.
176    kHowToCodeMask = 0x40
177  };
178
179  // For kRootArrayConstants
180  enum WithSkip {
181    kNoSkipDistance = 0,
182    kHasSkipDistance = 0x40,
183    kWithSkipMask = 0x40
184  };
185
186  // Where to point within the object.
187  enum WhereToPoint {
188    kStartOfObject = 0,
189    kInnerPointer = 0x80,  // First insn in code object or payload of cell.
190    kWhereToPointMask = 0x80
191  };
192
193  // Misc.
194  // Raw data to be copied from the snapshot.  This byte code does not advance
195  // the current pointer, which is used for code objects, where we write the
196  // entire code in one memcpy, then fix up stuff with kSkip and other byte
197  // codes that overwrite data.
198  static const int kRawData = 0x20;
199  // Some common raw lengths: 0x21-0x3f.  These autoadvance the current pointer.
200  // A tag emitted at strategic points in the snapshot to delineate sections.
201  // If the deserializer does not find these at the expected moments then it
202  // is an indication that the snapshot and the VM do not fit together.
203  // Examine the build process for architecture, version or configuration
204  // mismatches.
205  static const int kSynchronize = 0x70;
206  // Used for the source code of the natives, which is in the executable, but
207  // is referred to from external strings in the snapshot.
208  static const int kNativesStringResource = 0x71;
209  static const int kRepeat = 0x72;
210  static const int kConstantRepeat = 0x73;
211  // 0x73-0x7f            Repeat last word (subtract 0x72 to get the count).
212  static const int kMaxRepeats = 0x7f - 0x72;
213  static int CodeForRepeats(int repeats) {
214    DCHECK(repeats >= 1 && repeats <= kMaxRepeats);
215    return 0x72 + repeats;
216  }
217  static int RepeatsForCode(int byte_code) {
218    DCHECK(byte_code >= kConstantRepeat && byte_code <= 0x7f);
219    return byte_code - 0x72;
220  }
221  static const int kRootArrayConstants = 0xa0;
222  // 0xa0-0xbf            Things from the first 32 elements of the root array.
223  static const int kRootArrayNumberOfConstantEncodings = 0x20;
224  static int RootArrayConstantFromByteCode(int byte_code) {
225    return byte_code & 0x1f;
226  }
227
228  static const int kNumberOfSpaces = LO_SPACE;
229  static const int kAnyOldSpace = -1;
230
231  // A bitmask for getting the space out of an instruction.
232  static const int kSpaceMask = 7;
233};
234
235
236// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
237class Deserializer: public SerializerDeserializer {
238 public:
239  // Create a deserializer from a snapshot byte source.
240  explicit Deserializer(SnapshotByteSource* source);
241
242  virtual ~Deserializer();
243
244  // Deserialize the snapshot into an empty heap.
245  void Deserialize(Isolate* isolate);
246
247  // Deserialize a single object and the objects reachable from it.
248  void DeserializePartial(Isolate* isolate, Object** root);
249
250  void set_reservation(int space_number, int reservation) {
251    DCHECK(space_number >= 0);
252    DCHECK(space_number <= LAST_SPACE);
253    reservations_[space_number] = reservation;
254  }
255
256  void FlushICacheForNewCodeObjects();
257
258  // Serialized user code reference certain objects that are provided in a list
259  // By calling this method, we assume that we are deserializing user code.
260  void SetAttachedObjects(Vector<Handle<Object> >* attached_objects) {
261    attached_objects_ = attached_objects;
262  }
263
264  bool deserializing_user_code() { return attached_objects_ != NULL; }
265
266 private:
267  virtual void VisitPointers(Object** start, Object** end);
268
269  virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
270    UNREACHABLE();
271  }
272
273  // Allocation sites are present in the snapshot, and must be linked into
274  // a list at deserialization time.
275  void RelinkAllocationSite(AllocationSite* site);
276
277  // Fills in some heap data in an area from start to end (non-inclusive).  The
278  // space id is used for the write barrier.  The object_address is the address
279  // of the object we are writing into, or NULL if we are not writing into an
280  // object, i.e. if we are writing a series of tagged values that are not on
281  // the heap.
282  void ReadChunk(
283      Object** start, Object** end, int space, Address object_address);
284  void ReadObject(int space_number, Object** write_back);
285
286  // Special handling for serialized code like hooking up internalized strings.
287  HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
288  Object* ProcessBackRefInSerializedCode(Object* obj);
289
290  // This routine both allocates a new object, and also keeps
291  // track of where objects have been allocated so that we can
292  // fix back references when deserializing.
293  Address Allocate(int space_index, int size) {
294    Address address = high_water_[space_index];
295    high_water_[space_index] = address + size;
296    return address;
297  }
298
299  // This returns the address of an object that has been described in the
300  // snapshot as being offset bytes back in a particular space.
301  HeapObject* GetAddressFromEnd(int space) {
302    int offset = source_->GetInt();
303    offset <<= kObjectAlignmentBits;
304    return HeapObject::FromAddress(high_water_[space] - offset);
305  }
306
307  // Cached current isolate.
308  Isolate* isolate_;
309
310  // Objects from the attached object descriptions in the serialized user code.
311  Vector<Handle<Object> >* attached_objects_;
312
313  SnapshotByteSource* source_;
314  // This is the address of the next object that will be allocated in each
315  // space.  It is used to calculate the addresses of back-references.
316  Address high_water_[LAST_SPACE + 1];
317
318  int reservations_[LAST_SPACE + 1];
319  static const intptr_t kUninitializedReservation = -1;
320
321  ExternalReferenceDecoder* external_reference_decoder_;
322
323  DISALLOW_COPY_AND_ASSIGN(Deserializer);
324};
325
326
327// Mapping objects to their location after deserialization.
328// This is used during building, but not at runtime by V8.
329class SerializationAddressMapper {
330 public:
331  SerializationAddressMapper()
332      : no_allocation_(),
333        serialization_map_(new HashMap(HashMap::PointersMatch)) { }
334
335  ~SerializationAddressMapper() {
336    delete serialization_map_;
337  }
338
339  bool IsMapped(HeapObject* obj) {
340    return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
341  }
342
343  int MappedTo(HeapObject* obj) {
344    DCHECK(IsMapped(obj));
345    return static_cast<int>(reinterpret_cast<intptr_t>(
346        serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
347  }
348
349  void AddMapping(HeapObject* obj, int to) {
350    DCHECK(!IsMapped(obj));
351    HashMap::Entry* entry =
352        serialization_map_->Lookup(Key(obj), Hash(obj), true);
353    entry->value = Value(to);
354  }
355
356 private:
357  static uint32_t Hash(HeapObject* obj) {
358    return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
359  }
360
361  static void* Key(HeapObject* obj) {
362    return reinterpret_cast<void*>(obj->address());
363  }
364
365  static void* Value(int v) {
366    return reinterpret_cast<void*>(v);
367  }
368
369  DisallowHeapAllocation no_allocation_;
370  HashMap* serialization_map_;
371  DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
372};
373
374
375class CodeAddressMap;
376
377// There can be only one serializer per V8 process.
378class Serializer : public SerializerDeserializer {
379 public:
380  Serializer(Isolate* isolate, SnapshotByteSink* sink);
381  ~Serializer();
382  void VisitPointers(Object** start, Object** end);
383  // You can call this after serialization to find out how much space was used
384  // in each space.
385  int CurrentAllocationAddress(int space) const {
386    DCHECK(space < kNumberOfSpaces);
387    return fullness_[space];
388  }
389
390  Isolate* isolate() const { return isolate_; }
391
392  SerializationAddressMapper* address_mapper() { return &address_mapper_; }
393  void PutRoot(int index,
394               HeapObject* object,
395               HowToCode how,
396               WhereToPoint where,
397               int skip);
398
399 protected:
400  static const int kInvalidRootIndex = -1;
401
402  int RootIndex(HeapObject* heap_object, HowToCode from);
403  intptr_t root_index_wave_front() { return root_index_wave_front_; }
404  void set_root_index_wave_front(intptr_t value) {
405    DCHECK(value >= root_index_wave_front_);
406    root_index_wave_front_ = value;
407  }
408
409  class ObjectSerializer : public ObjectVisitor {
410   public:
411    ObjectSerializer(Serializer* serializer,
412                     Object* o,
413                     SnapshotByteSink* sink,
414                     HowToCode how_to_code,
415                     WhereToPoint where_to_point)
416      : serializer_(serializer),
417        object_(HeapObject::cast(o)),
418        sink_(sink),
419        reference_representation_(how_to_code + where_to_point),
420        bytes_processed_so_far_(0),
421        code_object_(o->IsCode()),
422        code_has_been_output_(false) { }
423    void Serialize();
424    void VisitPointers(Object** start, Object** end);
425    void VisitEmbeddedPointer(RelocInfo* target);
426    void VisitExternalReference(Address* p);
427    void VisitExternalReference(RelocInfo* rinfo);
428    void VisitCodeTarget(RelocInfo* target);
429    void VisitCodeEntry(Address entry_address);
430    void VisitCell(RelocInfo* rinfo);
431    void VisitRuntimeEntry(RelocInfo* reloc);
432    // Used for seralizing the external strings that hold the natives source.
433    void VisitExternalOneByteString(
434        v8::String::ExternalOneByteStringResource** resource);
435    // We can't serialize a heap with external two byte strings.
436    void VisitExternalTwoByteString(
437        v8::String::ExternalStringResource** resource) {
438      UNREACHABLE();
439    }
440
441   private:
442    enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
443    // This function outputs or skips the raw data between the last pointer and
444    // up to the current position.  It optionally can just return the number of
445    // bytes to skip instead of performing a skip instruction, in case the skip
446    // can be merged into the next instruction.
447    int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
448
449    Serializer* serializer_;
450    HeapObject* object_;
451    SnapshotByteSink* sink_;
452    int reference_representation_;
453    int bytes_processed_so_far_;
454    bool code_object_;
455    bool code_has_been_output_;
456  };
457
458  virtual void SerializeObject(Object* o,
459                               HowToCode how_to_code,
460                               WhereToPoint where_to_point,
461                               int skip) = 0;
462  void SerializeReferenceToPreviousObject(HeapObject* heap_object,
463                                          HowToCode how_to_code,
464                                          WhereToPoint where_to_point,
465                                          int skip);
466  void InitializeAllocators();
467  // This will return the space for an object.
468  static int SpaceOfObject(HeapObject* object);
469  int Allocate(int space, int size);
470  int EncodeExternalReference(Address addr) {
471    return external_reference_encoder_->Encode(addr);
472  }
473
474  int SpaceAreaSize(int space);
475
476  // Some roots should not be serialized, because their actual value depends on
477  // absolute addresses and they are reset after deserialization, anyway.
478  bool ShouldBeSkipped(Object** current);
479
480  Isolate* isolate_;
481  // Keep track of the fullness of each space in order to generate
482  // relative addresses for back references.
483  int fullness_[LAST_SPACE + 1];
484  SnapshotByteSink* sink_;
485  ExternalReferenceEncoder* external_reference_encoder_;
486
487  SerializationAddressMapper address_mapper_;
488  intptr_t root_index_wave_front_;
489  void Pad();
490
491  friend class ObjectSerializer;
492  friend class Deserializer;
493
494  // We may not need the code address map for logging for every instance
495  // of the serializer.  Initialize it on demand.
496  void InitializeCodeAddressMap();
497
498 private:
499  CodeAddressMap* code_address_map_;
500  DISALLOW_COPY_AND_ASSIGN(Serializer);
501};
502
503
504class PartialSerializer : public Serializer {
505 public:
506  PartialSerializer(Isolate* isolate,
507                    Serializer* startup_snapshot_serializer,
508                    SnapshotByteSink* sink)
509    : Serializer(isolate, sink),
510      startup_serializer_(startup_snapshot_serializer) {
511    set_root_index_wave_front(Heap::kStrongRootListLength);
512    InitializeCodeAddressMap();
513  }
514
515  // Serialize the objects reachable from a single object pointer.
516  void Serialize(Object** o);
517  virtual void SerializeObject(Object* o,
518                               HowToCode how_to_code,
519                               WhereToPoint where_to_point,
520                               int skip);
521
522 private:
523  int PartialSnapshotCacheIndex(HeapObject* o);
524  bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
525    // Scripts should be referred only through shared function infos.  We can't
526    // allow them to be part of the partial snapshot because they contain a
527    // unique ID, and deserializing several partial snapshots containing script
528    // would cause dupes.
529    DCHECK(!o->IsScript());
530    return o->IsName() || o->IsSharedFunctionInfo() ||
531           o->IsHeapNumber() || o->IsCode() ||
532           o->IsScopeInfo() ||
533           o->map() ==
534               startup_serializer_->isolate()->heap()->fixed_cow_array_map();
535  }
536
537
538  Serializer* startup_serializer_;
539  DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
540};
541
542
543class StartupSerializer : public Serializer {
544 public:
545  StartupSerializer(Isolate* isolate, SnapshotByteSink* sink)
546    : Serializer(isolate, sink) {
547    // Clear the cache of objects used by the partial snapshot.  After the
548    // strong roots have been serialized we can create a partial snapshot
549    // which will repopulate the cache with objects needed by that partial
550    // snapshot.
551    isolate->set_serialize_partial_snapshot_cache_length(0);
552    InitializeCodeAddressMap();
553  }
554  // Serialize the current state of the heap.  The order is:
555  // 1) Strong references.
556  // 2) Partial snapshot cache.
557  // 3) Weak references (e.g. the string table).
558  virtual void SerializeStrongReferences();
559  virtual void SerializeObject(Object* o,
560                               HowToCode how_to_code,
561                               WhereToPoint where_to_point,
562                               int skip);
563  void SerializeWeakReferences();
564  void Serialize() {
565    SerializeStrongReferences();
566    SerializeWeakReferences();
567    Pad();
568  }
569
570 private:
571  DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
572};
573
574
575class CodeSerializer : public Serializer {
576 public:
577  CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source)
578      : Serializer(isolate, sink), source_(source) {
579    set_root_index_wave_front(Heap::kStrongRootListLength);
580    InitializeCodeAddressMap();
581  }
582
583  static ScriptData* Serialize(Isolate* isolate,
584                               Handle<SharedFunctionInfo> info,
585                               Handle<String> source);
586
587  virtual void SerializeObject(Object* o, HowToCode how_to_code,
588                               WhereToPoint where_to_point, int skip);
589
590  static Handle<SharedFunctionInfo> Deserialize(Isolate* isolate,
591                                                ScriptData* data,
592                                                Handle<String> source);
593
594  static const int kSourceObjectIndex = 0;
595  static const int kCodeStubsBaseIndex = 1;
596
597  String* source() {
598    DCHECK(!AllowHeapAllocation::IsAllowed());
599    return source_;
600  }
601
602  List<uint32_t>* stub_keys() { return &stub_keys_; }
603
604 private:
605  void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
606                        WhereToPoint where_to_point, int skip);
607  void SerializeCodeStub(Code* code, HowToCode how_to_code,
608                         WhereToPoint where_to_point, int skip);
609  void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point,
610                             int skip);
611  void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code,
612                           WhereToPoint where_to_point, int skip);
613  int AddCodeStubKey(uint32_t stub_key);
614
615  DisallowHeapAllocation no_gc_;
616  String* source_;
617  List<uint32_t> stub_keys_;
618  DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
619};
620
621
622// Wrapper around ScriptData to provide code-serializer-specific functionality.
623class SerializedCodeData {
624 public:
625  // Used by when consuming.
626  explicit SerializedCodeData(ScriptData* data, String* source)
627      : script_data_(data), owns_script_data_(false) {
628    DisallowHeapAllocation no_gc;
629    CHECK(IsSane(source));
630  }
631
632  // Used when producing.
633  SerializedCodeData(List<byte>* payload, CodeSerializer* cs);
634
635  ~SerializedCodeData() {
636    if (owns_script_data_) delete script_data_;
637  }
638
639  // Return ScriptData object and relinquish ownership over it to the caller.
640  ScriptData* GetScriptData() {
641    ScriptData* result = script_data_;
642    script_data_ = NULL;
643    DCHECK(owns_script_data_);
644    owns_script_data_ = false;
645    return result;
646  }
647
648  Vector<const uint32_t> CodeStubKeys() const {
649    return Vector<const uint32_t>(
650        reinterpret_cast<const uint32_t*>(script_data_->data() + kHeaderSize),
651        GetHeaderValue(kNumCodeStubKeysOffset));
652  }
653
654  const byte* Payload() const {
655    int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
656    return script_data_->data() + kHeaderSize + code_stubs_size;
657  }
658
659  int PayloadLength() const {
660    int payload_length = GetHeaderValue(kPayloadLengthOffset);
661    DCHECK_EQ(script_data_->data() + script_data_->length(),
662              Payload() + payload_length);
663    return payload_length;
664  }
665
666  int GetReservation(int space) const {
667    return GetHeaderValue(kReservationsOffset + space);
668  }
669
670 private:
671  void SetHeaderValue(int offset, int value) {
672    reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] =
673        value;
674  }
675
676  int GetHeaderValue(int offset) const {
677    return reinterpret_cast<const int*>(script_data_->data())[offset];
678  }
679
680  bool IsSane(String* source);
681
682  int CheckSum(String* source);
683
684  // The data header consists of int-sized entries:
685  // [0] version hash
686  // [1] number of code stub keys
687  // [2] payload length
688  // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
689  static const int kCheckSumOffset = 0;
690  static const int kNumCodeStubKeysOffset = 1;
691  static const int kPayloadLengthOffset = 2;
692  static const int kReservationsOffset = 3;
693
694  static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1;
695  static const int kHeaderEntries = kReservationsOffset + kNumSpaces;
696  static const int kHeaderSize = kHeaderEntries * kIntSize;
697
698  // Following the header, we store, in sequential order
699  // - code stub keys
700  // - serialization payload
701
702  ScriptData* script_data_;
703  bool owns_script_data_;
704};
705} }  // namespace v8::internal
706
707#endif  // V8_SERIALIZE_H_
708