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.
5 #ifndef V8_SERIALIZE_H_
6 #define V8_SERIALIZE_H_
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"
17 // A TypeCode is used to distinguish different kinds of external reference.
18 // It is a single bit to make testing for types easy.
20 UNCLASSIFIED, // One-of-a-kind references.
33 const int kTypeCodeCount = LAZY_DEOPTIMIZATION + 1;
34 const int kFirstTypeCode = UNCLASSIFIED;
36 const int kReferenceIdBits = 16;
37 const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
38 const int kReferenceTypeShift = kReferenceIdBits;
40 const int kDeoptTableSerializeEntryCount = 64;
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.
45 class ExternalReferenceTable {
47 static ExternalReferenceTable* instance(Isolate* isolate);
49 ~ExternalReferenceTable() { }
51 int size() const { return refs_.length(); }
53 Address address(int i) { return refs_[i].address; }
55 uint32_t code(int i) { return refs_[i].code; }
57 const char* name(int i) { return refs_[i].name; }
59 int max_id(int code) { return max_id_[code]; }
62 explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
63 PopulateTable(isolate);
66 struct ExternalReferenceEntry {
72 void PopulateTable(Isolate* isolate);
74 // For a few types of references, we can get their address from their id.
75 void AddFromId(TypeCode type,
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);
83 void Add(Address address, const char* name) {
84 Add(address, UNCLASSIFIED, ++max_id_[UNCLASSIFIED], name);
87 List<ExternalReferenceEntry> refs_;
88 uint16_t max_id_[kTypeCodeCount];
92 class ExternalReferenceEncoder {
94 explicit ExternalReferenceEncoder(Isolate* isolate);
96 uint32_t Encode(Address key) const;
98 const char* NameOfAddress(Address key) const;
102 static uint32_t Hash(Address key) {
103 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
106 int IndexOf(Address key) const;
108 void Put(Address key, int index);
114 class ExternalReferenceDecoder {
116 explicit ExternalReferenceDecoder(Isolate* isolate);
117 ~ExternalReferenceDecoder();
119 Address Decode(uint32_t key) const {
120 if (key == 0) return NULL;
125 Address** encodings_;
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];
134 void Put(uint32_t key, Address value) {
135 *Lookup(key) = value;
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
145 class SerializerDeserializer: public ObjectVisitor {
147 static void Iterate(Isolate* isolate, ObjectVisitor* visitor);
149 static int nop() { return kNop; }
152 // Where the pointed-to object can be found:
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
171 // How to code the pointer to the object.
173 kPlain = 0, // Straight pointer.
174 // What this means depends on the architecture:
175 kFromCode = 0x40, // A pointer inlined in code.
176 kHowToCodeMask = 0x40
179 // For kRootArrayConstants
182 kHasSkipDistance = 0x40,
186 // Where to point within the object.
189 kInnerPointer = 0x80, // First insn in code object or payload of cell.
190 kWhereToPointMask = 0x80
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
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;
217 static int RepeatsForCode(int byte_code) {
218 DCHECK(byte_code >= kConstantRepeat && byte_code <= 0x7f);
219 return byte_code - 0x72;
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;
228 static const int kNumberOfSpaces = LO_SPACE;
229 static const int kAnyOldSpace = -1;
231 // A bitmask for getting the space out of an instruction.
232 static const int kSpaceMask = 7;
236 // A Deserializer reads a snapshot and reconstructs the Object graph it defines.
237 class Deserializer: public SerializerDeserializer {
239 // Create a deserializer from a snapshot byte source.
240 explicit Deserializer(SnapshotByteSource* source);
242 virtual ~Deserializer();
244 // Deserialize the snapshot into an empty heap.
245 void Deserialize(Isolate* isolate);
247 // Deserialize a single object and the objects reachable from it.
248 void DeserializePartial(Isolate* isolate, Object** root);
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;
256 void FlushICacheForNewCodeObjects();
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;
264 bool deserializing_user_code() { return attached_objects_ != NULL; }
267 virtual void VisitPointers(Object** start, Object** end);
269 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
273 // Allocation sites are present in the snapshot, and must be linked into
274 // a list at deserialization time.
275 void RelinkAllocationSite(AllocationSite* site);
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
283 Object** start, Object** end, int space, Address object_address);
284 void ReadObject(int space_number, Object** write_back);
286 // Special handling for serialized code like hooking up internalized strings.
287 HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj);
288 Object* ProcessBackRefInSerializedCode(Object* obj);
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;
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);
307 // Cached current isolate.
310 // Objects from the attached object descriptions in the serialized user code.
311 Vector<Handle<Object> >* attached_objects_;
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];
318 int reservations_[LAST_SPACE + 1];
319 static const intptr_t kUninitializedReservation = -1;
321 ExternalReferenceDecoder* external_reference_decoder_;
323 DISALLOW_COPY_AND_ASSIGN(Deserializer);
327 // Mapping objects to their location after deserialization.
328 // This is used during building, but not at runtime by V8.
329 class SerializationAddressMapper {
331 SerializationAddressMapper()
333 serialization_map_(new HashMap(HashMap::PointersMatch)) { }
335 ~SerializationAddressMapper() {
336 delete serialization_map_;
339 bool IsMapped(HeapObject* obj) {
340 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
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));
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);
357 static uint32_t Hash(HeapObject* obj) {
358 return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
361 static void* Key(HeapObject* obj) {
362 return reinterpret_cast<void*>(obj->address());
365 static void* Value(int v) {
366 return reinterpret_cast<void*>(v);
369 DisallowHeapAllocation no_allocation_;
370 HashMap* serialization_map_;
371 DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
375 class CodeAddressMap;
377 // There can be only one serializer per V8 process.
378 class Serializer : public SerializerDeserializer {
380 Serializer(Isolate* isolate, SnapshotByteSink* sink);
382 void VisitPointers(Object** start, Object** end);
383 // You can call this after serialization to find out how much space was used
385 int CurrentAllocationAddress(int space) const {
386 DCHECK(space < kNumberOfSpaces);
387 return fullness_[space];
390 Isolate* isolate() const { return isolate_; }
392 SerializationAddressMapper* address_mapper() { return &address_mapper_; }
393 void PutRoot(int index,
400 static const int kInvalidRootIndex = -1;
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;
409 class ObjectSerializer : public ObjectVisitor {
411 ObjectSerializer(Serializer* serializer,
413 SnapshotByteSink* sink,
414 HowToCode how_to_code,
415 WhereToPoint where_to_point)
416 : serializer_(serializer),
417 object_(HeapObject::cast(o)),
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) { }
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) {
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);
449 Serializer* serializer_;
451 SnapshotByteSink* sink_;
452 int reference_representation_;
453 int bytes_processed_so_far_;
455 bool code_has_been_output_;
458 virtual void SerializeObject(Object* o,
459 HowToCode how_to_code,
460 WhereToPoint where_to_point,
462 void SerializeReferenceToPreviousObject(HeapObject* heap_object,
463 HowToCode how_to_code,
464 WhereToPoint where_to_point,
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);
474 int SpaceAreaSize(int space);
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);
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_;
487 SerializationAddressMapper address_mapper_;
488 intptr_t root_index_wave_front_;
491 friend class ObjectSerializer;
492 friend class Deserializer;
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();
499 CodeAddressMap* code_address_map_;
500 DISALLOW_COPY_AND_ASSIGN(Serializer);
504 class PartialSerializer : public Serializer {
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();
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,
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() ||
534 startup_serializer_->isolate()->heap()->fixed_cow_array_map();
538 Serializer* startup_serializer_;
539 DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
543 class StartupSerializer : public Serializer {
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
551 isolate->set_serialize_partial_snapshot_cache_length(0);
552 InitializeCodeAddressMap();
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,
563 void SerializeWeakReferences();
565 SerializeStrongReferences();
566 SerializeWeakReferences();
571 DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
575 class CodeSerializer : public Serializer {
577 CodeSerializer(Isolate* isolate, SnapshotByteSink* sink, String* source)
578 : Serializer(isolate, sink), source_(source) {
579 set_root_index_wave_front(Heap::kStrongRootListLength);
580 InitializeCodeAddressMap();
583 static ScriptData* Serialize(Isolate* isolate,
584 Handle<SharedFunctionInfo> info,
585 Handle<String> source);
587 virtual void SerializeObject(Object* o, HowToCode how_to_code,
588 WhereToPoint where_to_point, int skip);
590 static Handle<SharedFunctionInfo> Deserialize(Isolate* isolate,
592 Handle<String> source);
594 static const int kSourceObjectIndex = 0;
595 static const int kCodeStubsBaseIndex = 1;
598 DCHECK(!AllowHeapAllocation::IsAllowed());
602 List<uint32_t>* stub_keys() { return &stub_keys_; }
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,
611 void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code,
612 WhereToPoint where_to_point, int skip);
613 int AddCodeStubKey(uint32_t stub_key);
615 DisallowHeapAllocation no_gc_;
617 List<uint32_t> stub_keys_;
618 DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
622 // Wrapper around ScriptData to provide code-serializer-specific functionality.
623 class SerializedCodeData {
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));
632 // Used when producing.
633 SerializedCodeData(List<byte>* payload, CodeSerializer* cs);
635 ~SerializedCodeData() {
636 if (owns_script_data_) delete script_data_;
639 // Return ScriptData object and relinquish ownership over it to the caller.
640 ScriptData* GetScriptData() {
641 ScriptData* result = script_data_;
643 DCHECK(owns_script_data_);
644 owns_script_data_ = false;
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));
654 const byte* Payload() const {
655 int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
656 return script_data_->data() + kHeaderSize + code_stubs_size;
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;
666 int GetReservation(int space) const {
667 return GetHeaderValue(kReservationsOffset + space);
671 void SetHeaderValue(int offset, int value) {
672 reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] =
676 int GetHeaderValue(int offset) const {
677 return reinterpret_cast<const int*>(script_data_->data())[offset];
680 bool IsSane(String* source);
682 int CheckSum(String* source);
684 // The data header consists of int-sized entries:
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;
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;
698 // Following the header, we store, in sequential order
700 // - serialization payload
702 ScriptData* script_data_;
703 bool owns_script_data_;
705 } } // namespace v8::internal
707 #endif // V8_SERIALIZE_H_