blob: d42231a8f6bbfa85376b5a012a51c883160431a0 [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,
50 STUB_CACHE_TABLE
51};
52
53const int kTypeCodeCount = STUB_CACHE_TABLE + 1;
54const int kFirstTypeCode = UNCLASSIFIED;
55
56const int kReferenceIdBits = 16;
57const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
58const int kReferenceTypeShift = kReferenceIdBits;
59const int kDebugRegisterBits = 4;
60const int kDebugIdShift = kDebugRegisterBits;
61
62
danno@chromium.orgb6451162011-08-17 14:33:23 +000063// ExternalReferenceTable is a helper class that defines the relationship
64// between external references and their encodings. It is used to build
65// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
66class ExternalReferenceTable {
67 public:
68 static ExternalReferenceTable* instance(Isolate* isolate);
69
70 ~ExternalReferenceTable() { }
71
72 int size() const { return refs_.length(); }
73
74 Address address(int i) { return refs_[i].address; }
75
76 uint32_t code(int i) { return refs_[i].code; }
77
78 const char* name(int i) { return refs_[i].name; }
79
80 int max_id(int code) { return max_id_[code]; }
81
82 private:
83 explicit ExternalReferenceTable(Isolate* isolate) : refs_(64) {
84 PopulateTable(isolate);
85 }
86
87 struct ExternalReferenceEntry {
88 Address address;
89 uint32_t code;
90 const char* name;
91 };
92
93 void PopulateTable(Isolate* isolate);
94
95 // For a few types of references, we can get their address from their id.
96 void AddFromId(TypeCode type,
97 uint16_t id,
98 const char* name,
99 Isolate* isolate);
100
101 // For other types of references, the caller will figure out the address.
102 void Add(Address address, TypeCode type, uint16_t id, const char* name);
103
104 List<ExternalReferenceEntry> refs_;
105 int max_id_[kTypeCodeCount];
106};
107
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109class ExternalReferenceEncoder {
110 public:
111 ExternalReferenceEncoder();
112
113 uint32_t Encode(Address key) const;
114
115 const char* NameOfAddress(Address key) const;
116
117 private:
118 HashMap encodings_;
119 static uint32_t Hash(Address key) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000120 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 }
122
123 int IndexOf(Address key) const;
124
125 static bool Match(void* key1, void* key2) { return key1 == key2; }
126
127 void Put(Address key, int index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000128
129 Isolate* isolate_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130};
131
132
133class ExternalReferenceDecoder {
134 public:
135 ExternalReferenceDecoder();
136 ~ExternalReferenceDecoder();
137
138 Address Decode(uint32_t key) const {
139 if (key == 0) return NULL;
140 return *Lookup(key);
141 }
142
143 private:
144 Address** encodings_;
145
146 Address* Lookup(uint32_t key) const {
147 int type = key >> kReferenceTypeShift;
148 ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
149 int id = key & kReferenceIdMask;
150 return &encodings_[type][id];
151 }
152
153 void Put(uint32_t key, Address value) {
154 *Lookup(key) = value;
155 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000156
157 Isolate* isolate_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158};
159
160
ager@chromium.org3811b432009-10-28 14:53:37 +0000161class SnapshotByteSource {
162 public:
163 SnapshotByteSource(const byte* array, int length)
164 : data_(array), length_(length), position_(0) { }
165
166 bool HasMore() { return position_ < length_; }
167
168 int Get() {
169 ASSERT(position_ < length_);
170 return data_[position_++];
171 }
172
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000173 inline void CopyRaw(byte* to, int number_of_bytes);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000174
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000175 inline int GetInt();
ager@chromium.org3811b432009-10-28 14:53:37 +0000176
177 bool AtEOF() {
178 return position_ == length_;
179 }
180
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000181 int position() { return position_; }
182
ager@chromium.org3811b432009-10-28 14:53:37 +0000183 private:
184 const byte* data_;
185 int length_;
186 int position_;
187};
188
189
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000190#define COMMON_RAW_LENGTHS(f) \
191 f(1, 1) \
192 f(2, 2) \
193 f(3, 3) \
194 f(4, 4) \
195 f(5, 5) \
196 f(6, 6) \
197 f(7, 7) \
198 f(8, 8) \
199 f(9, 12) \
200 f(10, 16) \
201 f(11, 20) \
202 f(12, 24) \
203 f(13, 28) \
204 f(14, 32) \
205 f(15, 36)
206
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000207// The Serializer/Deserializer class is a common superclass for Serializer and
208// Deserializer which is used to store common constants and methods used by
209// both.
210class SerializerDeserializer: public ObjectVisitor {
211 public:
danno@chromium.org40cb8782011-05-25 07:58:50 +0000212 static void Iterate(ObjectVisitor* visitor);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000213
ager@chromium.org3811b432009-10-28 14:53:37 +0000214 protected:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000215 // Where the pointed-to object can be found:
216 enum Where {
217 kNewObject = 0, // Object is next in snapshot.
218 // 1-8 One per space.
219 kRootArray = 0x9, // Object is found in root array.
220 kPartialSnapshotCache = 0xa, // Object is in the cache.
221 kExternalReference = 0xb, // Pointer to an external reference.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000222 kSkip = 0xc, // Skip a pointer sized cell.
223 // 0xd-0xf Free.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000224 kBackref = 0x10, // Object is described relative to end.
225 // 0x11-0x18 One per space.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000226 // 0x19-0x1f Free.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000227 kFromStart = 0x20, // Object is described relative to start.
228 // 0x21-0x28 One per space.
229 // 0x29-0x2f Free.
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000230 // 0x30-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
242 // Where to point within the object.
243 enum WhereToPoint {
244 kStartOfObject = 0,
245 kFirstInstruction = 0x80,
246 kWhereToPointMask = 0x80
247 };
248
249 // Misc.
250 // Raw data to be copied from the snapshot.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000251 static const int kRawData = 0x30;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000252 // Some common raw lengths: 0x31-0x3f
253 // A tag emitted at strategic points in the snapshot to delineate sections.
254 // If the deserializer does not find these at the expected moments then it
255 // is an indication that the snapshot and the VM do not fit together.
256 // Examine the build process for architecture, version or configuration
257 // mismatches.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000258 static const int kSynchronize = 0x70;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000259 // Used for the source code of the natives, which is in the executable, but
260 // is referred to from external strings in the snapshot.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000261 static const int kNativesStringResource = 0x71;
262 static const int kNewPage = 0x72;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000263 static const int kRepeat = 0x73;
264 static const int kConstantRepeat = 0x74;
265 // 0x74-0x7f Repeat last word (subtract 0x73 to get the count).
266 static const int kMaxRepeats = 0x7f - 0x73;
267 static int CodeForRepeats(int repeats) {
268 ASSERT(repeats >= 1 && repeats <= kMaxRepeats);
269 return 0x73 + repeats;
270 }
271 static int RepeatsForCode(int byte_code) {
272 ASSERT(byte_code >= kConstantRepeat && byte_code <= 0x7f);
273 return byte_code - 0x73;
274 }
275 static const int kRootArrayLowConstants = 0xb0;
276 // 0xb0-0xbf Things from the first 16 elements of the root array.
277 static const int kRootArrayHighConstants = 0xf0;
278 // 0xf0-0xff Things from the next 16 elements of the root array.
279 static const int kRootArrayNumberOfConstantEncodings = 0x20;
280 static const int kRootArrayNumberOfLowConstantEncodings = 0x10;
281 static int RootArrayConstantFromByteCode(int byte_code) {
282 int constant = (byte_code & 0xf) | ((byte_code & 0x40) >> 2);
283 ASSERT(constant >= 0 && constant < kRootArrayNumberOfConstantEncodings);
284 return constant;
285 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000286
287
danno@chromium.org40cb8782011-05-25 07:58:50 +0000288 static const int kLargeData = LAST_SPACE;
289 static const int kLargeCode = kLargeData + 1;
290 static const int kLargeFixedArray = kLargeCode + 1;
291 static const int kNumberOfSpaces = kLargeFixedArray + 1;
292 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.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000295 static const int kSpaceMask = 15;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000296
danno@chromium.org40cb8782011-05-25 07:58:50 +0000297 static inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
298 static inline bool SpaceIsPaged(int space) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000299 return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE;
300 }
301};
302
303
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000304int SnapshotByteSource::GetInt() {
305 // A little unwind to catch the really small ints.
306 int snapshot_byte = Get();
307 if ((snapshot_byte & 0x80) == 0) {
308 return snapshot_byte;
309 }
310 int accumulator = (snapshot_byte & 0x7f) << 7;
311 while (true) {
312 snapshot_byte = Get();
313 if ((snapshot_byte & 0x80) == 0) {
314 return accumulator | snapshot_byte;
315 }
316 accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
317 }
318 UNREACHABLE();
319 return accumulator;
320}
321
322
323void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
324 memcpy(to, data_ + position_, number_of_bytes);
325 position_ += number_of_bytes;
326}
327
ager@chromium.org3811b432009-10-28 14:53:37 +0000328
329// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000330class Deserializer: public SerializerDeserializer {
ager@chromium.org3811b432009-10-28 14:53:37 +0000331 public:
332 // Create a deserializer from a snapshot byte source.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000333 explicit Deserializer(SnapshotByteSource* source);
ager@chromium.org3811b432009-10-28 14:53:37 +0000334
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000335 virtual ~Deserializer();
ager@chromium.org3811b432009-10-28 14:53:37 +0000336
337 // Deserialize the snapshot into an empty heap.
338 void Deserialize();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000339
340 // Deserialize a single object and the objects reachable from it.
341 void DeserializePartial(Object** root);
342
ager@chromium.org3811b432009-10-28 14:53:37 +0000343 private:
344 virtual void VisitPointers(Object** start, Object** end);
345
346 virtual void VisitExternalReferences(Address* start, Address* end) {
347 UNREACHABLE();
348 }
349
350 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
351 UNREACHABLE();
352 }
353
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000354 // Fills in some heap data in an area from start to end (non-inclusive). The
355 // space id is used for the write barrier. The object_address is the address
356 // of the object we are writing into, or NULL if we are not writing into an
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000357 // object, i.e. if we are writing a series of tagged values that are not on
358 // the heap.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000359 void ReadChunk(
360 Object** start, Object** end, int space, Address object_address);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000361 HeapObject* GetAddressFromStart(int space);
362 inline HeapObject* GetAddressFromEnd(int space);
363 Address Allocate(int space_number, Space* space, int size);
364 void ReadObject(int space_number, Space* space, Object** write_back);
ager@chromium.org3811b432009-10-28 14:53:37 +0000365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 // Cached current isolate.
367 Isolate* isolate_;
368
ager@chromium.org3811b432009-10-28 14:53:37 +0000369 // Keep track of the pages in the paged spaces.
370 // (In large object space we are keeping track of individual objects
371 // rather than pages.) In new space we just need the address of the
372 // first object and the others will flow from that.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000373 List<Address> pages_[SerializerDeserializer::kNumberOfSpaces];
ager@chromium.org3811b432009-10-28 14:53:37 +0000374
375 SnapshotByteSource* source_;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000376 // This is the address of the next object that will be allocated in each
377 // space. It is used to calculate the addresses of back-references.
378 Address high_water_[LAST_SPACE + 1];
379 // This is the address of the most recent object that was allocated. It
380 // is used to set the location of the new page when we encounter a
381 // START_NEW_PAGE_SERIALIZATION tag.
382 Address last_object_address_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 ExternalReferenceDecoder* external_reference_decoder_;
385
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000386 DISALLOW_COPY_AND_ASSIGN(Deserializer);
ager@chromium.org3811b432009-10-28 14:53:37 +0000387};
388
389
390class SnapshotByteSink {
391 public:
392 virtual ~SnapshotByteSink() { }
393 virtual void Put(int byte, const char* description) = 0;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000394 virtual void PutSection(int byte, const char* description) {
395 Put(byte, description);
396 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000397 void PutInt(uintptr_t integer, const char* description);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000398 virtual int Position() = 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000399};
400
401
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000402// Mapping objects to their location after deserialization.
403// This is used during building, but not at runtime by V8.
404class SerializationAddressMapper {
405 public:
406 SerializationAddressMapper()
407 : serialization_map_(new HashMap(&SerializationMatchFun)),
408 no_allocation_(new AssertNoAllocation()) { }
409
410 ~SerializationAddressMapper() {
411 delete serialization_map_;
412 delete no_allocation_;
413 }
414
415 bool IsMapped(HeapObject* obj) {
416 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
417 }
418
419 int MappedTo(HeapObject* obj) {
420 ASSERT(IsMapped(obj));
421 return static_cast<int>(reinterpret_cast<intptr_t>(
422 serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
423 }
424
425 void AddMapping(HeapObject* obj, int to) {
426 ASSERT(!IsMapped(obj));
427 HashMap::Entry* entry =
428 serialization_map_->Lookup(Key(obj), Hash(obj), true);
429 entry->value = Value(to);
430 }
431
432 private:
danno@chromium.org40cb8782011-05-25 07:58:50 +0000433 static bool SerializationMatchFun(void* key1, void* key2) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000434 return key1 == key2;
435 }
436
danno@chromium.org40cb8782011-05-25 07:58:50 +0000437 static uint32_t Hash(HeapObject* obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000438 return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
439 }
440
danno@chromium.org40cb8782011-05-25 07:58:50 +0000441 static void* Key(HeapObject* obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000442 return reinterpret_cast<void*>(obj->address());
443 }
444
danno@chromium.org40cb8782011-05-25 07:58:50 +0000445 static void* Value(int v) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000446 return reinterpret_cast<void*>(v);
447 }
448
449 HashMap* serialization_map_;
450 AssertNoAllocation* no_allocation_;
451 DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
452};
453
454
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455// There can be only one serializer per V8 process.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000456class Serializer : public SerializerDeserializer {
ager@chromium.org3811b432009-10-28 14:53:37 +0000457 public:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000458 explicit Serializer(SnapshotByteSink* sink);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000459 ~Serializer();
ager@chromium.org3811b432009-10-28 14:53:37 +0000460 void VisitPointers(Object** start, Object** end);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000461 // You can call this after serialization to find out how much space was used
462 // in each space.
463 int CurrentAllocationAddress(int space) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000464 if (SpaceIsLarge(space)) return large_object_total_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000465 return fullness_[space];
466 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000467
danno@chromium.org40cb8782011-05-25 07:58:50 +0000468 static void Enable() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000469 if (!serialization_enabled_) {
470 ASSERT(!too_late_to_enable_now_);
471 }
472 serialization_enabled_ = true;
473 }
474
danno@chromium.org40cb8782011-05-25 07:58:50 +0000475 static void Disable() { serialization_enabled_ = false; }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000476 // Call this when you have made use of the fact that there is no serialization
477 // going on.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000478 static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
479 static bool enabled() { return serialization_enabled_; }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000480 SerializationAddressMapper* address_mapper() { return &address_mapper_; }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 void PutRoot(
482 int index, HeapObject* object, HowToCode how, WhereToPoint where);
ager@chromium.org3811b432009-10-28 14:53:37 +0000483
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000484 protected:
danno@chromium.org40cb8782011-05-25 07:58:50 +0000485 static const int kInvalidRootIndex = -1;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000486
danno@chromium.org88aa0582012-03-23 15:11:57 +0000487 int RootIndex(HeapObject* heap_object, HowToCode from);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000488 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000489 intptr_t root_index_wave_front() { return root_index_wave_front_; }
490 void set_root_index_wave_front(intptr_t value) {
491 ASSERT(value >= root_index_wave_front_);
492 root_index_wave_front_ = value;
493 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000494
ager@chromium.org3811b432009-10-28 14:53:37 +0000495 class ObjectSerializer : public ObjectVisitor {
496 public:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000497 ObjectSerializer(Serializer* serializer,
ager@chromium.org3811b432009-10-28 14:53:37 +0000498 Object* o,
499 SnapshotByteSink* sink,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000500 HowToCode how_to_code,
501 WhereToPoint where_to_point)
ager@chromium.org3811b432009-10-28 14:53:37 +0000502 : serializer_(serializer),
503 object_(HeapObject::cast(o)),
504 sink_(sink),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000505 reference_representation_(how_to_code + where_to_point),
ager@chromium.org3811b432009-10-28 14:53:37 +0000506 bytes_processed_so_far_(0) { }
507 void Serialize();
508 void VisitPointers(Object** start, Object** end);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000509 void VisitEmbeddedPointer(RelocInfo* target);
ager@chromium.org3811b432009-10-28 14:53:37 +0000510 void VisitExternalReferences(Address* start, Address* end);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000511 void VisitExternalReference(RelocInfo* rinfo);
ager@chromium.org3811b432009-10-28 14:53:37 +0000512 void VisitCodeTarget(RelocInfo* target);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000513 void VisitCodeEntry(Address entry_address);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000514 void VisitGlobalPropertyCell(RelocInfo* rinfo);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000515 void VisitRuntimeEntry(RelocInfo* reloc);
516 // Used for seralizing the external strings that hold the natives source.
517 void VisitExternalAsciiString(
518 v8::String::ExternalAsciiStringResource** resource);
519 // We can't serialize a heap with external two byte strings.
520 void VisitExternalTwoByteString(
521 v8::String::ExternalStringResource** resource) {
522 UNREACHABLE();
523 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000524
525 private:
526 void OutputRawData(Address up_to);
527
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000528 Serializer* serializer_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000529 HeapObject* object_;
530 SnapshotByteSink* sink_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000531 int reference_representation_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000532 int bytes_processed_so_far_;
533 };
534
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000535 virtual void SerializeObject(Object* o,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000536 HowToCode how_to_code,
537 WhereToPoint where_to_point) = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000538 void SerializeReferenceToPreviousObject(
539 int space,
540 int address,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000541 HowToCode how_to_code,
542 WhereToPoint where_to_point);
ager@chromium.org3811b432009-10-28 14:53:37 +0000543 void InitializeAllocators();
544 // This will return the space for an object. If the object is in large
545 // object space it may return kLargeCode or kLargeFixedArray in order
546 // to indicate to the deserializer what kind of large object allocation
547 // to make.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000548 static int SpaceOfObject(HeapObject* object);
ager@chromium.org3811b432009-10-28 14:53:37 +0000549 // This just returns the space of the object. It will return LO_SPACE
550 // for all large objects since you can't check the type of the object
551 // once the map has been used for the serialization address.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000552 static int SpaceOfAlreadySerializedObject(HeapObject* object);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000553 int Allocate(int space, int size, bool* new_page_started);
ager@chromium.org3811b432009-10-28 14:53:37 +0000554 int EncodeExternalReference(Address addr) {
555 return external_reference_encoder_->Encode(addr);
556 }
557
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000558 int SpaceAreaSize(int space);
559
560 Isolate* isolate_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000561 // Keep track of the fullness of each space in order to generate
562 // relative addresses for back references. Large objects are
563 // just numbered sequentially since relative addresses make no
564 // sense in large object space.
565 int fullness_[LAST_SPACE + 1];
566 SnapshotByteSink* sink_;
567 int current_root_index_;
568 ExternalReferenceEncoder* external_reference_encoder_;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000569 static bool serialization_enabled_;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000570 // Did we already make use of the fact that serialization was not enabled?
danno@chromium.org40cb8782011-05-25 07:58:50 +0000571 static bool too_late_to_enable_now_;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572 int large_object_total_;
573 SerializationAddressMapper address_mapper_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000574 intptr_t root_index_wave_front_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000575
576 friend class ObjectSerializer;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000577 friend class Deserializer;
ager@chromium.org3811b432009-10-28 14:53:37 +0000578
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000579 private:
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000580 DISALLOW_COPY_AND_ASSIGN(Serializer);
ager@chromium.org3811b432009-10-28 14:53:37 +0000581};
582
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000583
584class PartialSerializer : public Serializer {
585 public:
586 PartialSerializer(Serializer* startup_snapshot_serializer,
587 SnapshotByteSink* sink)
588 : Serializer(sink),
589 startup_serializer_(startup_snapshot_serializer) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000590 set_root_index_wave_front(Heap::kStrongRootListLength);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591 }
592
593 // Serialize the objects reachable from a single object pointer.
594 virtual void Serialize(Object** o);
595 virtual void SerializeObject(Object* o,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000596 HowToCode how_to_code,
597 WhereToPoint where_to_point);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000598
599 protected:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000600 virtual int PartialSnapshotCacheIndex(HeapObject* o);
601 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000602 // Scripts should be referred only through shared function infos. We can't
603 // allow them to be part of the partial snapshot because they contain a
604 // unique ID, and deserializing several partial snapshots containing script
605 // would cause dupes.
606 ASSERT(!o->IsScript());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000607 return o->IsString() || o->IsSharedFunctionInfo() ||
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000608 o->IsHeapNumber() || o->IsCode() ||
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000609 o->IsScopeInfo() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 o->map() == HEAP->fixed_cow_array_map();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000611 }
612
613 private:
614 Serializer* startup_serializer_;
615 DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
616};
617
618
619class StartupSerializer : public Serializer {
620 public:
621 explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) {
622 // Clear the cache of objects used by the partial snapshot. After the
623 // strong roots have been serialized we can create a partial snapshot
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000624 // which will repopulate the cache with objects needed by that partial
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000625 // snapshot.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Isolate::Current()->set_serialize_partial_snapshot_cache_length(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000627 }
628 // Serialize the current state of the heap. The order is:
629 // 1) Strong references.
630 // 2) Partial snapshot cache.
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000631 // 3) Weak references (e.g. the symbol table).
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000632 virtual void SerializeStrongReferences();
633 virtual void SerializeObject(Object* o,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000634 HowToCode how_to_code,
635 WhereToPoint where_to_point);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000636 void SerializeWeakReferences();
637 void Serialize() {
638 SerializeStrongReferences();
639 SerializeWeakReferences();
640 }
641
642 private:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000643 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
644 return false;
645 }
646};
647
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649} } // namespace v8::internal
650
651#endif // V8_SERIALIZE_H_