blob: a6099afc23f397fdcfedea0781cca8c7767c5ec2 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_SERIALIZE_H_
29#define V8_SERIALIZE_H_
30
31#include "hashmap.h"
32
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033namespace v8 {
34namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
36// A TypeCode is used to distinguish different kinds of external reference.
37// It is a single bit to make testing for types easy.
38enum TypeCode {
39 UNCLASSIFIED, // One-of-a-kind references.
40 BUILTIN,
41 RUNTIME_FUNCTION,
42 IC_UTILITY,
43 DEBUG_ADDRESS,
44 STATS_COUNTER,
45 TOP_ADDRESS,
46 C_BUILTIN,
47 EXTENSION,
48 ACCESSOR,
49 RUNTIME_ENTRY,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000050 STUB_CACHE_TABLE,
51 LAZY_DEOPTIMIZATION
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052};
53
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000054const int kTypeCodeCount = LAZY_DEOPTIMIZATION + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055const int kFirstTypeCode = UNCLASSIFIED;
56
57const int kReferenceIdBits = 16;
58const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
59const int kReferenceTypeShift = kReferenceIdBits;
60const int kDebugRegisterBits = 4;
61const int kDebugIdShift = kDebugRegisterBits;
62
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000063const int kDeoptTableSerializeEntryCount = 8;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
danno@chromium.orgb6451162011-08-17 14:33:23 +000065// ExternalReferenceTable is a helper class that defines the relationship
66// between external references and their encodings. It is used to build
67// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
68class ExternalReferenceTable {
69 public:
70 static ExternalReferenceTable* instance(Isolate* isolate);
71
72 ~ExternalReferenceTable() { }
73
74 int size() const { return refs_.length(); }
75
76 Address address(int i) { return refs_[i].address; }
77
78 uint32_t code(int i) { return refs_[i].code; }
79
80 const char* name(int i) { return refs_[i].name; }
81
82 int max_id(int code) { return max_id_[code]; }
83
84 private:
85 explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
86 PopulateTable(isolate);
87 }
88
89 struct ExternalReferenceEntry {
90 Address address;
91 uint32_t code;
92 const char* name;
93 };
94
95 void PopulateTable(Isolate* isolate);
96
97 // For a few types of references, we can get their address from their id.
98 void AddFromId(TypeCode type,
99 uint16_t id,
100 const char* name,
101 Isolate* isolate);
102
103 // For other types of references, the caller will figure out the address.
104 void Add(Address address, TypeCode type, uint16_t id, const char* name);
105
106 List<ExternalReferenceEntry> refs_;
107 int max_id_[kTypeCodeCount];
108};
109
110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111class ExternalReferenceEncoder {
112 public:
113 ExternalReferenceEncoder();
114
115 uint32_t Encode(Address key) const;
116
117 const char* NameOfAddress(Address key) const;
118
119 private:
120 HashMap encodings_;
121 static uint32_t Hash(Address key) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000122 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 }
124
125 int IndexOf(Address key) const;
126
127 static bool Match(void* key1, void* key2) { return key1 == key2; }
128
129 void Put(Address key, int index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130
131 Isolate* isolate_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132};
133
134
135class ExternalReferenceDecoder {
136 public:
137 ExternalReferenceDecoder();
138 ~ExternalReferenceDecoder();
139
140 Address Decode(uint32_t key) const {
141 if (key == 0) return NULL;
142 return *Lookup(key);
143 }
144
145 private:
146 Address** encodings_;
147
148 Address* Lookup(uint32_t key) const {
149 int type = key >> kReferenceTypeShift;
150 ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
151 int id = key & kReferenceIdMask;
152 return &encodings_[type][id];
153 }
154
155 void Put(uint32_t key, Address value) {
156 *Lookup(key) = value;
157 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158
159 Isolate* isolate_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000160};
161
162
ager@chromium.org3811b432009-10-28 14:53:37 +0000163class SnapshotByteSource {
164 public:
165 SnapshotByteSource(const byte* array, int length)
166 : data_(array), length_(length), position_(0) { }
167
168 bool HasMore() { return position_ < length_; }
169
170 int Get() {
171 ASSERT(position_ < length_);
172 return data_[position_++];
173 }
174
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000175 int32_t GetUnalignedInt() {
176#if defined(V8_HOST_CAN_READ_UNALIGNED) && __BYTE_ORDER == __LITTLE_ENDIAN
177 int32_t answer;
178 ASSERT(position_ + sizeof(answer) <= length_ + 0u);
179 answer = *reinterpret_cast<const int32_t*>(data_ + position_);
180#else
181 int32_t answer = data_[position_];
182 answer |= data_[position_ + 1] << 8;
183 answer |= data_[position_ + 2] << 16;
184 answer |= data_[position_ + 3] << 24;
185#endif
186 return answer;
187 }
188
189 void Advance(int by) { position_ += by; }
190
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000191 inline void CopyRaw(byte* to, int number_of_bytes);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000192
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000193 inline int GetInt();
ager@chromium.org3811b432009-10-28 14:53:37 +0000194
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000195 bool AtEOF();
ager@chromium.org3811b432009-10-28 14:53:37 +0000196
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000197 int position() { return position_; }
198
ager@chromium.org3811b432009-10-28 14:53:37 +0000199 private:
200 const byte* data_;
201 int length_;
202 int position_;
203};
204
205
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000206// The Serializer/Deserializer class is a common superclass for Serializer and
207// Deserializer which is used to store common constants and methods used by
208// both.
209class SerializerDeserializer: public ObjectVisitor {
210 public:
danno@chromium.org40cb8782011-05-25 07:58:50 +0000211 static void Iterate(ObjectVisitor* visitor);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000213 static int nop() { return kNop; }
214
ager@chromium.org3811b432009-10-28 14:53:37 +0000215 protected:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000216 // Where the pointed-to object can be found:
217 enum Where {
218 kNewObject = 0, // Object is next in snapshot.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000219 // 1-6 One per space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000220 kRootArray = 0x9, // Object is found in root array.
221 kPartialSnapshotCache = 0xa, // Object is in the cache.
222 kExternalReference = 0xb, // Pointer to an external reference.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000223 kSkip = 0xc, // Skip n bytes.
224 kNop = 0xd, // Does nothing, used to pad.
225 // 0xe-0xf Free.
226 kBackref = 0x10, // Object is described relative to end.
227 // 0x11-0x16 One per space.
228 kBackrefWithSkip = 0x18, // Object is described relative to end.
229 // 0x19-0x1e One per space.
230 // 0x20-0x3f Used by misc. tags below.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000231 kPointedToMask = 0x3f
ager@chromium.org3811b432009-10-28 14:53:37 +0000232 };
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000233
234 // How to code the pointer to the object.
235 enum HowToCode {
236 kPlain = 0, // Straight pointer.
237 // What this means depends on the architecture:
238 kFromCode = 0x40, // A pointer inlined in code.
239 kHowToCodeMask = 0x40
240 };
241
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000242 // For kRootArrayConstants
243 enum WithSkip {
244 kNoSkipDistance = 0,
245 kHasSkipDistance = 0x40,
246 kWithSkipMask = 0x40
247 };
248
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000249 // Where to point within the object.
250 enum WhereToPoint {
251 kStartOfObject = 0,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000252 kInnerPointer = 0x80, // First insn in code object or payload of cell.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000253 kWhereToPointMask = 0x80
254 };
255
256 // Misc.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000257 // Raw data to be copied from the snapshot. This byte code does not advance
258 // the current pointer, which is used for code objects, where we write the
259 // entire code in one memcpy, then fix up stuff with kSkip and other byte
260 // codes that overwrite data.
261 static const int kRawData = 0x20;
262 // Some common raw lengths: 0x21-0x3f. These autoadvance the current pointer.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000263 // A tag emitted at strategic points in the snapshot to delineate sections.
264 // If the deserializer does not find these at the expected moments then it
265 // is an indication that the snapshot and the VM do not fit together.
266 // Examine the build process for architecture, version or configuration
267 // mismatches.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000268 static const int kSynchronize = 0x70;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000269 // Used for the source code of the natives, which is in the executable, but
270 // is referred to from external strings in the snapshot.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000271 static const int kNativesStringResource = 0x71;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000272 static const int kRepeat = 0x72;
273 static const int kConstantRepeat = 0x73;
274 // 0x73-0x7f Repeat last word (subtract 0x72 to get the count).
275 static const int kMaxRepeats = 0x7f - 0x72;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000276 static int CodeForRepeats(int repeats) {
277 ASSERT(repeats >= 1 && repeats <= kMaxRepeats);
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000278 return 0x72 + repeats;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000279 }
280 static int RepeatsForCode(int byte_code) {
281 ASSERT(byte_code >= kConstantRepeat && byte_code <= 0x7f);
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000282 return byte_code - 0x72;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000283 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000284 static const int kRootArrayConstants = 0xa0;
285 // 0xa0-0xbf Things from the first 32 elements of the root array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000286 static const int kRootArrayNumberOfConstantEncodings = 0x20;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000287 static int RootArrayConstantFromByteCode(int byte_code) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000288 return byte_code & 0x1f;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000289 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000290
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000291 static const int kNumberOfSpaces = LO_SPACE;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000292 static const int kAnyOldSpace = -1;
ager@chromium.org3811b432009-10-28 14:53:37 +0000293
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000294 // A bitmask for getting the space out of an instruction.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000295 static const int kSpaceMask = 7;
ager@chromium.org3811b432009-10-28 14:53:37 +0000296};
297
298
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000299int SnapshotByteSource::GetInt() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000300 // This way of variable-length encoding integers does not suffer from branch
301 // mispredictions.
302 uint32_t answer = GetUnalignedInt();
303 int bytes = answer & 3;
304 Advance(bytes);
305 uint32_t mask = 0xffffffffu;
306 mask >>= 32 - (bytes << 3);
307 answer &= mask;
308 answer >>= 2;
309 return answer;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000310}
311
312
313void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000314 OS::MemCopy(to, data_ + position_, number_of_bytes);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000315 position_ += number_of_bytes;
316}
317
ager@chromium.org3811b432009-10-28 14:53:37 +0000318
319// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000320class Deserializer: public SerializerDeserializer {
ager@chromium.org3811b432009-10-28 14:53:37 +0000321 public:
322 // Create a deserializer from a snapshot byte source.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000323 explicit Deserializer(SnapshotByteSource* source);
ager@chromium.org3811b432009-10-28 14:53:37 +0000324
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000325 virtual ~Deserializer();
ager@chromium.org3811b432009-10-28 14:53:37 +0000326
327 // Deserialize the snapshot into an empty heap.
328 void Deserialize();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000329
330 // Deserialize a single object and the objects reachable from it.
331 void DeserializePartial(Object** root);
332
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000333 void set_reservation(int space_number, int reservation) {
334 ASSERT(space_number >= 0);
335 ASSERT(space_number <= LAST_SPACE);
336 reservations_[space_number] = reservation;
337 }
338
ager@chromium.org3811b432009-10-28 14:53:37 +0000339 private:
340 virtual void VisitPointers(Object** start, Object** end);
341
342 virtual void VisitExternalReferences(Address* start, Address* end) {
343 UNREACHABLE();
344 }
345
346 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
347 UNREACHABLE();
348 }
349
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000350 // Fills in some heap data in an area from start to end (non-inclusive). The
351 // space id is used for the write barrier. The object_address is the address
352 // of the object we are writing into, or NULL if we are not writing into an
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000353 // object, i.e. if we are writing a series of tagged values that are not on
354 // the heap.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000355 void ReadChunk(
356 Object** start, Object** end, int space, Address object_address);
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000357 void ReadObject(int space_number, Object** write_back);
358
359 // This routine both allocates a new object, and also keeps
360 // track of where objects have been allocated so that we can
361 // fix back references when deserializing.
362 Address Allocate(int space_index, int size) {
363 Address address = high_water_[space_index];
364 high_water_[space_index] = address + size;
365 return address;
366 }
367
368 // This returns the address of an object that has been described in the
369 // snapshot as being offset bytes back in a particular space.
370 HeapObject* GetAddressFromEnd(int space) {
371 int offset = source_->GetInt();
372 offset <<= kObjectAlignmentBits;
373 return HeapObject::FromAddress(high_water_[space] - offset);
374 }
375
ager@chromium.org3811b432009-10-28 14:53:37 +0000376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 // Cached current isolate.
378 Isolate* isolate_;
379
ager@chromium.org3811b432009-10-28 14:53:37 +0000380 SnapshotByteSource* source_;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000381 // This is the address of the next object that will be allocated in each
382 // space. It is used to calculate the addresses of back-references.
383 Address high_water_[LAST_SPACE + 1];
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000384
385 int reservations_[LAST_SPACE + 1];
386 static const intptr_t kUninitializedReservation = -1;
ager@chromium.org3811b432009-10-28 14:53:37 +0000387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000388 ExternalReferenceDecoder* external_reference_decoder_;
389
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000390 DISALLOW_COPY_AND_ASSIGN(Deserializer);
ager@chromium.org3811b432009-10-28 14:53:37 +0000391};
392
393
394class SnapshotByteSink {
395 public:
396 virtual ~SnapshotByteSink() { }
397 virtual void Put(int byte, const char* description) = 0;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000398 virtual void PutSection(int byte, const char* description) {
399 Put(byte, description);
400 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000401 void PutInt(uintptr_t integer, const char* description);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000402 virtual int Position() = 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000403};
404
405
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000406// Mapping objects to their location after deserialization.
407// This is used during building, but not at runtime by V8.
408class SerializationAddressMapper {
409 public:
410 SerializationAddressMapper()
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000411 : no_allocation_(),
412 serialization_map_(new HashMap(&SerializationMatchFun)) { }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000413
414 ~SerializationAddressMapper() {
415 delete serialization_map_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000416 }
417
418 bool IsMapped(HeapObject* obj) {
419 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
420 }
421
422 int MappedTo(HeapObject* obj) {
423 ASSERT(IsMapped(obj));
424 return static_cast<int>(reinterpret_cast<intptr_t>(
425 serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
426 }
427
428 void AddMapping(HeapObject* obj, int to) {
429 ASSERT(!IsMapped(obj));
430 HashMap::Entry* entry =
431 serialization_map_->Lookup(Key(obj), Hash(obj), true);
432 entry->value = Value(to);
433 }
434
435 private:
danno@chromium.org40cb8782011-05-25 07:58:50 +0000436 static bool SerializationMatchFun(void* key1, void* key2) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000437 return key1 == key2;
438 }
439
danno@chromium.org40cb8782011-05-25 07:58:50 +0000440 static uint32_t Hash(HeapObject* obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000441 return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
442 }
443
danno@chromium.org40cb8782011-05-25 07:58:50 +0000444 static void* Key(HeapObject* obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000445 return reinterpret_cast<void*>(obj->address());
446 }
447
danno@chromium.org40cb8782011-05-25 07:58:50 +0000448 static void* Value(int v) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000449 return reinterpret_cast<void*>(v);
450 }
451
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000452 DisallowHeapAllocation no_allocation_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000453 HashMap* serialization_map_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000454 DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
455};
456
457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458// There can be only one serializer per V8 process.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000459class Serializer : public SerializerDeserializer {
ager@chromium.org3811b432009-10-28 14:53:37 +0000460 public:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000461 explicit Serializer(SnapshotByteSink* sink);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000462 ~Serializer();
ager@chromium.org3811b432009-10-28 14:53:37 +0000463 void VisitPointers(Object** start, Object** end);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000464 // You can call this after serialization to find out how much space was used
465 // in each space.
466 int CurrentAllocationAddress(int space) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000467 ASSERT(space < kNumberOfSpaces);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000468 return fullness_[space];
469 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000470
danno@chromium.org40cb8782011-05-25 07:58:50 +0000471 static void Enable() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000472 if (!serialization_enabled_) {
473 ASSERT(!too_late_to_enable_now_);
474 }
475 serialization_enabled_ = true;
476 }
477
danno@chromium.org40cb8782011-05-25 07:58:50 +0000478 static void Disable() { serialization_enabled_ = false; }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000479 // Call this when you have made use of the fact that there is no serialization
480 // going on.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000481 static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
482 static bool enabled() { return serialization_enabled_; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000483 SerializationAddressMapper* address_mapper() { return &address_mapper_; }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000484 void PutRoot(int index,
485 HeapObject* object,
486 HowToCode how,
487 WhereToPoint where,
488 int skip);
ager@chromium.org3811b432009-10-28 14:53:37 +0000489
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000490 protected:
danno@chromium.org40cb8782011-05-25 07:58:50 +0000491 static const int kInvalidRootIndex = -1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000492
danno@chromium.org88aa0582012-03-23 15:11:57 +0000493 int RootIndex(HeapObject* heap_object, HowToCode from);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000494 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000495 intptr_t root_index_wave_front() { return root_index_wave_front_; }
496 void set_root_index_wave_front(intptr_t value) {
497 ASSERT(value >= root_index_wave_front_);
498 root_index_wave_front_ = value;
499 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000500
ager@chromium.org3811b432009-10-28 14:53:37 +0000501 class ObjectSerializer : public ObjectVisitor {
502 public:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000503 ObjectSerializer(Serializer* serializer,
ager@chromium.org3811b432009-10-28 14:53:37 +0000504 Object* o,
505 SnapshotByteSink* sink,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000506 HowToCode how_to_code,
507 WhereToPoint where_to_point)
ager@chromium.org3811b432009-10-28 14:53:37 +0000508 : serializer_(serializer),
509 object_(HeapObject::cast(o)),
510 sink_(sink),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000511 reference_representation_(how_to_code + where_to_point),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000512 bytes_processed_so_far_(0),
513 code_object_(o->IsCode()),
514 code_has_been_output_(false) { }
ager@chromium.org3811b432009-10-28 14:53:37 +0000515 void Serialize();
516 void VisitPointers(Object** start, Object** end);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000517 void VisitEmbeddedPointer(RelocInfo* target);
ager@chromium.org3811b432009-10-28 14:53:37 +0000518 void VisitExternalReferences(Address* start, Address* end);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000519 void VisitExternalReference(RelocInfo* rinfo);
ager@chromium.org3811b432009-10-28 14:53:37 +0000520 void VisitCodeTarget(RelocInfo* target);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000521 void VisitCodeEntry(Address entry_address);
danno@chromium.org41728482013-06-12 22:31:22 +0000522 void VisitCell(RelocInfo* rinfo);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000523 void VisitRuntimeEntry(RelocInfo* reloc);
524 // Used for seralizing the external strings that hold the natives source.
525 void VisitExternalAsciiString(
526 v8::String::ExternalAsciiStringResource** resource);
527 // We can't serialize a heap with external two byte strings.
528 void VisitExternalTwoByteString(
529 v8::String::ExternalStringResource** resource) {
530 UNREACHABLE();
531 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000532
533 private:
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000534 enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
535 // This function outputs or skips the raw data between the last pointer and
536 // up to the current position. It optionally can just return the number of
537 // bytes to skip instead of performing a skip instruction, in case the skip
538 // can be merged into the next instruction.
539 int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
ager@chromium.org3811b432009-10-28 14:53:37 +0000540
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000541 Serializer* serializer_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000542 HeapObject* object_;
543 SnapshotByteSink* sink_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000544 int reference_representation_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000545 int bytes_processed_so_far_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000546 bool code_object_;
547 bool code_has_been_output_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000548 };
549
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000550 virtual void SerializeObject(Object* o,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000551 HowToCode how_to_code,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000552 WhereToPoint where_to_point,
553 int skip) = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000554 void SerializeReferenceToPreviousObject(
555 int space,
556 int address,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000557 HowToCode how_to_code,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000558 WhereToPoint where_to_point,
559 int skip);
ager@chromium.org3811b432009-10-28 14:53:37 +0000560 void InitializeAllocators();
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000561 // This will return the space for an object.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000562 static int SpaceOfObject(HeapObject* object);
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000563 int Allocate(int space, int size);
ager@chromium.org3811b432009-10-28 14:53:37 +0000564 int EncodeExternalReference(Address addr) {
565 return external_reference_encoder_->Encode(addr);
566 }
567
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000568 int SpaceAreaSize(int space);
569
570 Isolate* isolate_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000571 // Keep track of the fullness of each space in order to generate
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000572 // relative addresses for back references.
ager@chromium.org3811b432009-10-28 14:53:37 +0000573 int fullness_[LAST_SPACE + 1];
574 SnapshotByteSink* sink_;
575 int current_root_index_;
576 ExternalReferenceEncoder* external_reference_encoder_;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000577 static bool serialization_enabled_;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000578 // Did we already make use of the fact that serialization was not enabled?
danno@chromium.org40cb8782011-05-25 07:58:50 +0000579 static bool too_late_to_enable_now_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000580 SerializationAddressMapper address_mapper_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000581 intptr_t root_index_wave_front_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000582 void Pad();
ager@chromium.org3811b432009-10-28 14:53:37 +0000583
584 friend class ObjectSerializer;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000585 friend class Deserializer;
ager@chromium.org3811b432009-10-28 14:53:37 +0000586
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000587 private:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000588 DISALLOW_COPY_AND_ASSIGN(Serializer);
ager@chromium.org3811b432009-10-28 14:53:37 +0000589};
590
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591
592class PartialSerializer : public Serializer {
593 public:
594 PartialSerializer(Serializer* startup_snapshot_serializer,
595 SnapshotByteSink* sink)
596 : Serializer(sink),
597 startup_serializer_(startup_snapshot_serializer) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000598 set_root_index_wave_front(Heap::kStrongRootListLength);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000599 }
600
601 // Serialize the objects reachable from a single object pointer.
602 virtual void Serialize(Object** o);
603 virtual void SerializeObject(Object* o,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000604 HowToCode how_to_code,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000605 WhereToPoint where_to_point,
606 int skip);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000607
608 protected:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000609 virtual int PartialSnapshotCacheIndex(HeapObject* o);
610 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000611 // Scripts should be referred only through shared function infos. We can't
612 // allow them to be part of the partial snapshot because they contain a
613 // unique ID, and deserializing several partial snapshots containing script
614 // would cause dupes.
615 ASSERT(!o->IsScript());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000616 return o->IsName() || o->IsSharedFunctionInfo() ||
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000617 o->IsHeapNumber() || o->IsCode() ||
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000618 o->IsScopeInfo() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 o->map() == HEAP->fixed_cow_array_map();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000620 }
621
622 private:
623 Serializer* startup_serializer_;
624 DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
625};
626
627
628class StartupSerializer : public Serializer {
629 public:
630 explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) {
631 // Clear the cache of objects used by the partial snapshot. After the
632 // strong roots have been serialized we can create a partial snapshot
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000633 // which will repopulate the cache with objects needed by that partial
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000634 // snapshot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 Isolate::Current()->set_serialize_partial_snapshot_cache_length(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000636 }
637 // Serialize the current state of the heap. The order is:
638 // 1) Strong references.
639 // 2) Partial snapshot cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000640 // 3) Weak references (e.g. the string table).
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000641 virtual void SerializeStrongReferences();
642 virtual void SerializeObject(Object* o,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000643 HowToCode how_to_code,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000644 WhereToPoint where_to_point,
645 int skip);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000646 void SerializeWeakReferences();
647 void Serialize() {
648 SerializeStrongReferences();
649 SerializeWeakReferences();
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000650 Pad();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000651 }
652
653 private:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000654 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
655 return false;
656 }
657};
658
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660} } // namespace v8::internal
661
662#endif // V8_SERIALIZE_H_