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_
13 // A TypeCode is used to distinguish different kinds of external reference.
14 // It is a single bit to make testing for types easy.
16 UNCLASSIFIED, // One-of-a-kind references.
31 const int kTypeCodeCount = LAZY_DEOPTIMIZATION + 1;
32 const int kFirstTypeCode = UNCLASSIFIED;
34 const int kReferenceIdBits = 16;
35 const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
36 const int kReferenceTypeShift = kReferenceIdBits;
37 const int kDebugRegisterBits = 4;
38 const int kDebugIdShift = kDebugRegisterBits;
40 const int kDeoptTableSerializeEntryCount = 12;
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 List<ExternalReferenceEntry> refs_;
84 int max_id_[kTypeCodeCount];
88 class ExternalReferenceEncoder {
90 explicit ExternalReferenceEncoder(Isolate* isolate);
92 uint32_t Encode(Address key) const;
94 const char* NameOfAddress(Address key) const;
98 static uint32_t Hash(Address key) {
99 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
102 int IndexOf(Address key) const;
104 void Put(Address key, int index);
110 class ExternalReferenceDecoder {
112 explicit ExternalReferenceDecoder(Isolate* isolate);
113 ~ExternalReferenceDecoder();
115 Address Decode(uint32_t key) const {
116 if (key == 0) return NULL;
121 Address** encodings_;
123 Address* Lookup(uint32_t key) const {
124 int type = key >> kReferenceTypeShift;
125 ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
126 int id = key & kReferenceIdMask;
127 return &encodings_[type][id];
130 void Put(uint32_t key, Address value) {
131 *Lookup(key) = value;
138 class SnapshotByteSource {
140 SnapshotByteSource(const byte* array, int length)
141 : data_(array), length_(length), position_(0) { }
143 bool HasMore() { return position_ < length_; }
146 ASSERT(position_ < length_);
147 return data_[position_++];
150 int32_t GetUnalignedInt() {
151 #if defined(V8_HOST_CAN_READ_UNALIGNED) && __BYTE_ORDER == __LITTLE_ENDIAN
153 ASSERT(position_ + sizeof(answer) <= length_ + 0u);
154 answer = *reinterpret_cast<const int32_t*>(data_ + position_);
156 int32_t answer = data_[position_];
157 answer |= data_[position_ + 1] << 8;
158 answer |= data_[position_ + 2] << 16;
159 answer |= data_[position_ + 3] << 24;
164 void Advance(int by) { position_ += by; }
166 inline void CopyRaw(byte* to, int number_of_bytes);
172 int position() { return position_; }
181 // The Serializer/Deserializer class is a common superclass for Serializer and
182 // Deserializer which is used to store common constants and methods used by
184 class SerializerDeserializer: public ObjectVisitor {
186 static void Iterate(Isolate* isolate, ObjectVisitor* visitor);
188 static int nop() { return kNop; }
191 // Where the pointed-to object can be found:
193 kNewObject = 0, // Object is next in snapshot.
194 // 1-6 One per space.
195 kRootArray = 0x9, // Object is found in root array.
196 kPartialSnapshotCache = 0xa, // Object is in the cache.
197 kExternalReference = 0xb, // Pointer to an external reference.
198 kSkip = 0xc, // Skip n bytes.
199 kNop = 0xd, // Does nothing, used to pad.
201 kBackref = 0x10, // Object is described relative to end.
202 // 0x11-0x16 One per space.
203 kBackrefWithSkip = 0x18, // Object is described relative to end.
204 // 0x19-0x1e One per space.
205 // 0x20-0x3f Used by misc. tags below.
206 kPointedToMask = 0x3f
209 // How to code the pointer to the object.
211 kPlain = 0, // Straight pointer.
212 // What this means depends on the architecture:
213 kFromCode = 0x40, // A pointer inlined in code.
214 kHowToCodeMask = 0x40
217 // For kRootArrayConstants
220 kHasSkipDistance = 0x40,
224 // Where to point within the object.
227 kInnerPointer = 0x80, // First insn in code object or payload of cell.
228 kWhereToPointMask = 0x80
232 // Raw data to be copied from the snapshot. This byte code does not advance
233 // the current pointer, which is used for code objects, where we write the
234 // entire code in one memcpy, then fix up stuff with kSkip and other byte
235 // codes that overwrite data.
236 static const int kRawData = 0x20;
237 // Some common raw lengths: 0x21-0x3f. These autoadvance the current pointer.
238 // A tag emitted at strategic points in the snapshot to delineate sections.
239 // If the deserializer does not find these at the expected moments then it
240 // is an indication that the snapshot and the VM do not fit together.
241 // Examine the build process for architecture, version or configuration
243 static const int kSynchronize = 0x70;
244 // Used for the source code of the natives, which is in the executable, but
245 // is referred to from external strings in the snapshot.
246 static const int kNativesStringResource = 0x71;
247 static const int kRepeat = 0x72;
248 static const int kConstantRepeat = 0x73;
249 // 0x73-0x7f Repeat last word (subtract 0x72 to get the count).
250 static const int kMaxRepeats = 0x7f - 0x72;
251 static int CodeForRepeats(int repeats) {
252 ASSERT(repeats >= 1 && repeats <= kMaxRepeats);
253 return 0x72 + repeats;
255 static int RepeatsForCode(int byte_code) {
256 ASSERT(byte_code >= kConstantRepeat && byte_code <= 0x7f);
257 return byte_code - 0x72;
259 static const int kRootArrayConstants = 0xa0;
260 // 0xa0-0xbf Things from the first 32 elements of the root array.
261 static const int kRootArrayNumberOfConstantEncodings = 0x20;
262 static int RootArrayConstantFromByteCode(int byte_code) {
263 return byte_code & 0x1f;
266 static const int kNumberOfSpaces = LO_SPACE;
267 static const int kAnyOldSpace = -1;
269 // A bitmask for getting the space out of an instruction.
270 static const int kSpaceMask = 7;
274 int SnapshotByteSource::GetInt() {
275 // This way of variable-length encoding integers does not suffer from branch
277 uint32_t answer = GetUnalignedInt();
278 int bytes = answer & 3;
280 uint32_t mask = 0xffffffffu;
281 mask >>= 32 - (bytes << 3);
288 void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
289 OS::MemCopy(to, data_ + position_, number_of_bytes);
290 position_ += number_of_bytes;
294 // A Deserializer reads a snapshot and reconstructs the Object graph it defines.
295 class Deserializer: public SerializerDeserializer {
297 // Create a deserializer from a snapshot byte source.
298 explicit Deserializer(SnapshotByteSource* source);
300 virtual ~Deserializer();
302 // Deserialize the snapshot into an empty heap.
303 void Deserialize(Isolate* isolate);
305 // Deserialize a single object and the objects reachable from it.
306 void DeserializePartial(Isolate* isolate, Object** root);
308 void set_reservation(int space_number, int reservation) {
309 ASSERT(space_number >= 0);
310 ASSERT(space_number <= LAST_SPACE);
311 reservations_[space_number] = reservation;
315 virtual void VisitPointers(Object** start, Object** end);
317 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
321 // Allocation sites are present in the snapshot, and must be linked into
322 // a list at deserialization time.
323 void RelinkAllocationSite(AllocationSite* site);
325 // Fills in some heap data in an area from start to end (non-inclusive). The
326 // space id is used for the write barrier. The object_address is the address
327 // of the object we are writing into, or NULL if we are not writing into an
328 // object, i.e. if we are writing a series of tagged values that are not on
331 Object** start, Object** end, int space, Address object_address);
332 void ReadObject(int space_number, Object** write_back);
334 // This routine both allocates a new object, and also keeps
335 // track of where objects have been allocated so that we can
336 // fix back references when deserializing.
337 Address Allocate(int space_index, int size) {
338 Address address = high_water_[space_index];
339 high_water_[space_index] = address + size;
340 HeapProfiler* profiler = isolate_->heap_profiler();
341 if (profiler->is_tracking_allocations()) {
342 profiler->AllocationEvent(address, size);
347 // This returns the address of an object that has been described in the
348 // snapshot as being offset bytes back in a particular space.
349 HeapObject* GetAddressFromEnd(int space) {
350 int offset = source_->GetInt();
351 offset <<= kObjectAlignmentBits;
352 return HeapObject::FromAddress(high_water_[space] - offset);
355 void FlushICacheForNewCodeObjects();
357 // Cached current isolate.
360 SnapshotByteSource* source_;
361 // This is the address of the next object that will be allocated in each
362 // space. It is used to calculate the addresses of back-references.
363 Address high_water_[LAST_SPACE + 1];
365 int reservations_[LAST_SPACE + 1];
366 static const intptr_t kUninitializedReservation = -1;
368 ExternalReferenceDecoder* external_reference_decoder_;
370 DISALLOW_COPY_AND_ASSIGN(Deserializer);
374 class SnapshotByteSink {
376 virtual ~SnapshotByteSink() { }
377 virtual void Put(int byte, const char* description) = 0;
378 virtual void PutSection(int byte, const char* description) {
379 Put(byte, description);
381 void PutInt(uintptr_t integer, const char* description);
382 virtual int Position() = 0;
386 // Mapping objects to their location after deserialization.
387 // This is used during building, but not at runtime by V8.
388 class SerializationAddressMapper {
390 SerializationAddressMapper()
392 serialization_map_(new HashMap(HashMap::PointersMatch)) { }
394 ~SerializationAddressMapper() {
395 delete serialization_map_;
398 bool IsMapped(HeapObject* obj) {
399 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
402 int MappedTo(HeapObject* obj) {
403 ASSERT(IsMapped(obj));
404 return static_cast<int>(reinterpret_cast<intptr_t>(
405 serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
408 void AddMapping(HeapObject* obj, int to) {
409 ASSERT(!IsMapped(obj));
410 HashMap::Entry* entry =
411 serialization_map_->Lookup(Key(obj), Hash(obj), true);
412 entry->value = Value(to);
416 static uint32_t Hash(HeapObject* obj) {
417 return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
420 static void* Key(HeapObject* obj) {
421 return reinterpret_cast<void*>(obj->address());
424 static void* Value(int v) {
425 return reinterpret_cast<void*>(v);
428 DisallowHeapAllocation no_allocation_;
429 HashMap* serialization_map_;
430 DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
434 class CodeAddressMap;
436 // There can be only one serializer per V8 process.
437 class Serializer : public SerializerDeserializer {
439 Serializer(Isolate* isolate, SnapshotByteSink* sink);
441 void VisitPointers(Object** start, Object** end);
442 // You can call this after serialization to find out how much space was used
444 int CurrentAllocationAddress(int space) const {
445 ASSERT(space < kNumberOfSpaces);
446 return fullness_[space];
449 Isolate* isolate() const { return isolate_; }
450 static void RequestEnable(Isolate* isolate);
451 static void InitializeOncePerProcess();
452 static void TearDown();
454 static bool enabled(Isolate* isolate) {
455 SerializationState state = static_cast<SerializationState>(
456 NoBarrier_Load(&serialization_state_));
457 ASSERT(state != SERIALIZER_STATE_UNINITIALIZED);
458 return state == SERIALIZER_STATE_ENABLED;
460 SerializationAddressMapper* address_mapper() { return &address_mapper_; }
461 void PutRoot(int index,
468 static const int kInvalidRootIndex = -1;
470 int RootIndex(HeapObject* heap_object, HowToCode from);
471 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
472 intptr_t root_index_wave_front() { return root_index_wave_front_; }
473 void set_root_index_wave_front(intptr_t value) {
474 ASSERT(value >= root_index_wave_front_);
475 root_index_wave_front_ = value;
478 class ObjectSerializer : public ObjectVisitor {
480 ObjectSerializer(Serializer* serializer,
482 SnapshotByteSink* sink,
483 HowToCode how_to_code,
484 WhereToPoint where_to_point)
485 : serializer_(serializer),
486 object_(HeapObject::cast(o)),
488 reference_representation_(how_to_code + where_to_point),
489 bytes_processed_so_far_(0),
490 code_object_(o->IsCode()),
491 code_has_been_output_(false) { }
493 void VisitPointers(Object** start, Object** end);
494 void VisitEmbeddedPointer(RelocInfo* target);
495 void VisitExternalReference(Address* p);
496 void VisitExternalReference(RelocInfo* rinfo);
497 void VisitCodeTarget(RelocInfo* target);
498 void VisitCodeEntry(Address entry_address);
499 void VisitCell(RelocInfo* rinfo);
500 void VisitRuntimeEntry(RelocInfo* reloc);
501 // Used for seralizing the external strings that hold the natives source.
502 void VisitExternalAsciiString(
503 v8::String::ExternalAsciiStringResource** resource);
504 // We can't serialize a heap with external two byte strings.
505 void VisitExternalTwoByteString(
506 v8::String::ExternalStringResource** resource) {
511 enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
512 // This function outputs or skips the raw data between the last pointer and
513 // up to the current position. It optionally can just return the number of
514 // bytes to skip instead of performing a skip instruction, in case the skip
515 // can be merged into the next instruction.
516 int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
518 Serializer* serializer_;
520 SnapshotByteSink* sink_;
521 int reference_representation_;
522 int bytes_processed_so_far_;
524 bool code_has_been_output_;
527 virtual void SerializeObject(Object* o,
528 HowToCode how_to_code,
529 WhereToPoint where_to_point,
531 void SerializeReferenceToPreviousObject(
534 HowToCode how_to_code,
535 WhereToPoint where_to_point,
537 void InitializeAllocators();
538 // This will return the space for an object.
539 static int SpaceOfObject(HeapObject* object);
540 int Allocate(int space, int size);
541 int EncodeExternalReference(Address addr) {
542 return external_reference_encoder_->Encode(addr);
545 int SpaceAreaSize(int space);
547 // Some roots should not be serialized, because their actual value depends on
548 // absolute addresses and they are reset after deserialization, anyway.
549 bool ShouldBeSkipped(Object** current);
552 // Keep track of the fullness of each space in order to generate
553 // relative addresses for back references.
554 int fullness_[LAST_SPACE + 1];
555 SnapshotByteSink* sink_;
556 ExternalReferenceEncoder* external_reference_encoder_;
558 enum SerializationState {
559 SERIALIZER_STATE_UNINITIALIZED = 0,
560 SERIALIZER_STATE_DISABLED = 1,
561 SERIALIZER_STATE_ENABLED = 2
564 static AtomicWord serialization_state_;
566 SerializationAddressMapper address_mapper_;
567 intptr_t root_index_wave_front_;
570 friend class ObjectSerializer;
571 friend class Deserializer;
574 static CodeAddressMap* code_address_map_;
575 DISALLOW_COPY_AND_ASSIGN(Serializer);
579 class PartialSerializer : public Serializer {
581 PartialSerializer(Isolate* isolate,
582 Serializer* startup_snapshot_serializer,
583 SnapshotByteSink* sink)
584 : Serializer(isolate, sink),
585 startup_serializer_(startup_snapshot_serializer) {
586 set_root_index_wave_front(Heap::kStrongRootListLength);
589 // Serialize the objects reachable from a single object pointer.
590 virtual void Serialize(Object** o);
591 virtual void SerializeObject(Object* o,
592 HowToCode how_to_code,
593 WhereToPoint where_to_point,
597 virtual int PartialSnapshotCacheIndex(HeapObject* o);
598 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
599 // Scripts should be referred only through shared function infos. We can't
600 // allow them to be part of the partial snapshot because they contain a
601 // unique ID, and deserializing several partial snapshots containing script
602 // would cause dupes.
603 ASSERT(!o->IsScript());
604 return o->IsName() || o->IsSharedFunctionInfo() ||
605 o->IsHeapNumber() || o->IsCode() ||
608 startup_serializer_->isolate()->heap()->fixed_cow_array_map();
612 Serializer* startup_serializer_;
613 DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
617 class StartupSerializer : public Serializer {
619 StartupSerializer(Isolate* isolate, SnapshotByteSink* sink)
620 : Serializer(isolate, sink) {
621 // Clear the cache of objects used by the partial snapshot. After the
622 // strong roots have been serialized we can create a partial snapshot
623 // which will repopulate the cache with objects needed by that partial
625 isolate->set_serialize_partial_snapshot_cache_length(0);
627 // Serialize the current state of the heap. The order is:
628 // 1) Strong references.
629 // 2) Partial snapshot cache.
630 // 3) Weak references (e.g. the string table).
631 virtual void SerializeStrongReferences();
632 virtual void SerializeObject(Object* o,
633 HowToCode how_to_code,
634 WhereToPoint where_to_point,
636 void SerializeWeakReferences();
638 SerializeStrongReferences();
639 SerializeWeakReferences();
644 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
650 } } // namespace v8::internal
652 #endif // V8_SERIALIZE_H_