blob: 96bd751da924a149b26d12e926f448b2887b8040 [file] [log] [blame]
Steve Blockd0582a62009-12-15 09:54:21 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
33namespace v8 {
34namespace internal {
35
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
63class ExternalReferenceEncoder {
64 public:
65 ExternalReferenceEncoder();
66
67 uint32_t Encode(Address key) const;
68
69 const char* NameOfAddress(Address key) const;
70
71 private:
72 HashMap encodings_;
73 static uint32_t Hash(Address key) {
74 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2);
75 }
76
77 int IndexOf(Address key) const;
78
79 static bool Match(void* key1, void* key2) { return key1 == key2; }
80
81 void Put(Address key, int index);
82};
83
84
85class ExternalReferenceDecoder {
86 public:
87 ExternalReferenceDecoder();
88 ~ExternalReferenceDecoder();
89
90 Address Decode(uint32_t key) const {
91 if (key == 0) return NULL;
92 return *Lookup(key);
93 }
94
95 private:
96 Address** encodings_;
97
98 Address* Lookup(uint32_t key) const {
99 int type = key >> kReferenceTypeShift;
100 ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
101 int id = key & kReferenceIdMask;
102 return &encodings_[type][id];
103 }
104
105 void Put(uint32_t key, Address value) {
106 *Lookup(key) = value;
107 }
108};
109
110
Steve Blockd0582a62009-12-15 09:54:21 +0000111class SnapshotByteSource {
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000113 SnapshotByteSource(const byte* array, int length)
114 : data_(array), length_(length), position_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000115
Steve Blockd0582a62009-12-15 09:54:21 +0000116 bool HasMore() { return position_ < length_; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000117
Steve Blockd0582a62009-12-15 09:54:21 +0000118 int Get() {
119 ASSERT(position_ < length_);
120 return data_[position_++];
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 }
122
Steve Blockd0582a62009-12-15 09:54:21 +0000123 void CopyRaw(byte* to, int number_of_bytes) {
124 memcpy(to, data_ + position_, number_of_bytes);
125 position_ += number_of_bytes;
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 }
127
128 int GetInt() {
Steve Blockd0582a62009-12-15 09:54:21 +0000129 // A little unwind to catch the really small ints.
130 int snapshot_byte = Get();
131 if ((snapshot_byte & 0x80) == 0) {
132 return snapshot_byte;
133 }
134 int accumulator = (snapshot_byte & 0x7f) << 7;
135 while (true) {
136 snapshot_byte = Get();
137 if ((snapshot_byte & 0x80) == 0) {
138 return accumulator | snapshot_byte;
139 }
140 accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
141 }
142 UNREACHABLE();
143 return accumulator;
Steve Blocka7e24c12009-10-30 11:49:00 +0000144 }
145
Steve Blockd0582a62009-12-15 09:54:21 +0000146 bool AtEOF() {
147 return position_ == length_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000148 }
149
150 private:
Steve Blockd0582a62009-12-15 09:54:21 +0000151 const byte* data_;
152 int length_;
153 int position_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000154};
155
156
Steve Blockd0582a62009-12-15 09:54:21 +0000157// It is very common to have a reference to the object at word 10 in space 2,
158// the object at word 5 in space 2 and the object at word 28 in space 4. This
159// only works for objects in the first page of a space.
160#define COMMON_REFERENCE_PATTERNS(f) \
161 f(kNumberOfSpaces, 2, 10) \
162 f(kNumberOfSpaces + 1, 2, 5) \
163 f(kNumberOfSpaces + 2, 4, 28) \
164 f(kNumberOfSpaces + 3, 2, 21) \
165 f(kNumberOfSpaces + 4, 2, 98) \
166 f(kNumberOfSpaces + 5, 2, 67) \
167 f(kNumberOfSpaces + 6, 4, 132)
168
169#define COMMON_RAW_LENGTHS(f) \
170 f(1, 1) \
171 f(2, 2) \
172 f(3, 3) \
173 f(4, 4) \
174 f(5, 5) \
175 f(6, 6) \
176 f(7, 7) \
177 f(8, 8) \
178 f(9, 12) \
179 f(10, 16) \
180 f(11, 20) \
181 f(12, 24) \
182 f(13, 28) \
183 f(14, 32) \
184 f(15, 36)
185
186// The SerDes class is a common superclass for Serializer and Deserializer
187// which is used to store common constants and methods used by both.
188class SerDes: public ObjectVisitor {
189 protected:
190 enum DataType {
191 RAW_DATA_SERIALIZATION = 0,
192 // And 15 common raw lengths.
193 OBJECT_SERIALIZATION = 16,
194 // One variant per space.
195 CODE_OBJECT_SERIALIZATION = 25,
196 // One per space (only code spaces in use).
197 EXTERNAL_REFERENCE_SERIALIZATION = 34,
198 EXTERNAL_BRANCH_TARGET_SERIALIZATION = 35,
199 SYNCHRONIZE = 36,
200 START_NEW_PAGE_SERIALIZATION = 37,
201 NATIVES_STRING_RESOURCE = 38,
202 // Free: 39-47.
203 BACKREF_SERIALIZATION = 48,
204 // One per space, must be kSpaceMask aligned.
205 // Free: 57-63.
206 REFERENCE_SERIALIZATION = 64,
207 // One per space and common references. Must be kSpaceMask aligned.
208 CODE_BACKREF_SERIALIZATION = 80,
209 // One per space, must be kSpaceMask aligned.
210 // Free: 89-95.
211 CODE_REFERENCE_SERIALIZATION = 96
212 // One per space, must be kSpaceMask aligned.
213 // Free: 105-255.
214 };
215 static const int kLargeData = LAST_SPACE;
216 static const int kLargeCode = kLargeData + 1;
217 static const int kLargeFixedArray = kLargeCode + 1;
218 static const int kNumberOfSpaces = kLargeFixedArray + 1;
219
220 // A bitmask for getting the space out of an instruction.
221 static const int kSpaceMask = 15;
222
223 static inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
224 static inline bool SpaceIsPaged(int space) {
225 return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE;
226 }
227};
228
229
230
Steve Blocka7e24c12009-10-30 11:49:00 +0000231// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
Steve Blockd0582a62009-12-15 09:54:21 +0000232class Deserializer: public SerDes {
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000234 // Create a deserializer from a snapshot byte source.
235 explicit Deserializer(SnapshotByteSource* source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000236
Steve Blockd0582a62009-12-15 09:54:21 +0000237 virtual ~Deserializer() { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000238
239 // Deserialize the snapshot into an empty heap.
240 void Deserialize();
Steve Blocka7e24c12009-10-30 11:49:00 +0000241#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 virtual void Synchronize(const char* tag);
243#endif
244
245 private:
246 virtual void VisitPointers(Object** start, Object** end);
Steve Blocka7e24c12009-10-30 11:49:00 +0000247
Steve Blockd0582a62009-12-15 09:54:21 +0000248 virtual void VisitExternalReferences(Address* start, Address* end) {
249 UNREACHABLE();
250 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000251
Steve Blockd0582a62009-12-15 09:54:21 +0000252 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
253 UNREACHABLE();
254 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000255
Steve Blockd0582a62009-12-15 09:54:21 +0000256 void ReadChunk(Object** start, Object** end, int space, Address address);
257 HeapObject* GetAddressFromStart(int space);
258 inline HeapObject* GetAddressFromEnd(int space);
259 Address Allocate(int space_number, Space* space, int size);
260 void ReadObject(int space_number, Space* space, Object** write_back);
Steve Blocka7e24c12009-10-30 11:49:00 +0000261
Steve Blockd0582a62009-12-15 09:54:21 +0000262 // Keep track of the pages in the paged spaces.
263 // (In large object space we are keeping track of individual objects
264 // rather than pages.) In new space we just need the address of the
265 // first object and the others will flow from that.
266 List<Address> pages_[SerDes::kNumberOfSpaces];
Steve Blocka7e24c12009-10-30 11:49:00 +0000267
Steve Blockd0582a62009-12-15 09:54:21 +0000268 SnapshotByteSource* source_;
269 ExternalReferenceDecoder* external_reference_decoder_;
270 // This is the address of the next object that will be allocated in each
271 // space. It is used to calculate the addresses of back-references.
272 Address high_water_[LAST_SPACE + 1];
273 // This is the address of the most recent object that was allocated. It
274 // is used to set the location of the new page when we encounter a
275 // START_NEW_PAGE_SERIALIZATION tag.
276 Address last_object_address_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000277
278 DISALLOW_COPY_AND_ASSIGN(Deserializer);
279};
280
Steve Blockd0582a62009-12-15 09:54:21 +0000281
282class SnapshotByteSink {
283 public:
284 virtual ~SnapshotByteSink() { }
285 virtual void Put(int byte, const char* description) = 0;
286 virtual void PutSection(int byte, const char* description) {
287 Put(byte, description);
288 }
289 void PutInt(uintptr_t integer, const char* description);
290};
291
292
293class Serializer : public SerDes {
294 public:
295 explicit Serializer(SnapshotByteSink* sink);
296 // Serialize the current state of the heap. This operation destroys the
297 // heap contents.
298 void Serialize();
299 void VisitPointers(Object** start, Object** end);
300
301 static void Enable() {
302 if (!serialization_enabled_) {
303 ASSERT(!too_late_to_enable_now_);
304 }
305 serialization_enabled_ = true;
306 }
307
308 static void Disable() { serialization_enabled_ = false; }
309 // Call this when you have made use of the fact that there is no serialization
310 // going on.
311 static void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
312 static bool enabled() { return serialization_enabled_; }
313#ifdef DEBUG
314 virtual void Synchronize(const char* tag);
315#endif
316
317 private:
318 enum ReferenceRepresentation {
319 TAGGED_REPRESENTATION, // A tagged object reference.
320 CODE_TARGET_REPRESENTATION // A reference to first instruction in target.
321 };
322 class ObjectSerializer : public ObjectVisitor {
323 public:
324 ObjectSerializer(Serializer* serializer,
325 Object* o,
326 SnapshotByteSink* sink,
327 ReferenceRepresentation representation)
328 : serializer_(serializer),
329 object_(HeapObject::cast(o)),
330 sink_(sink),
331 reference_representation_(representation),
332 bytes_processed_so_far_(0) { }
333 void Serialize();
334 void VisitPointers(Object** start, Object** end);
335 void VisitExternalReferences(Address* start, Address* end);
336 void VisitCodeTarget(RelocInfo* target);
337 void VisitRuntimeEntry(RelocInfo* reloc);
338 // Used for seralizing the external strings that hold the natives source.
339 void VisitExternalAsciiString(
340 v8::String::ExternalAsciiStringResource** resource);
341 // We can't serialize a heap with external two byte strings.
342 void VisitExternalTwoByteString(
343 v8::String::ExternalStringResource** resource) {
344 UNREACHABLE();
345 }
346
347 private:
348 void OutputRawData(Address up_to);
349
350 Serializer* serializer_;
351 HeapObject* object_;
352 SnapshotByteSink* sink_;
353 ReferenceRepresentation reference_representation_;
354 int bytes_processed_so_far_;
355 };
356
357 void SerializeObject(Object* o, ReferenceRepresentation representation);
358 void InitializeAllocators();
359 // This will return the space for an object. If the object is in large
360 // object space it may return kLargeCode or kLargeFixedArray in order
361 // to indicate to the deserializer what kind of large object allocation
362 // to make.
363 static int SpaceOfObject(HeapObject* object);
364 // This just returns the space of the object. It will return LO_SPACE
365 // for all large objects since you can't check the type of the object
366 // once the map has been used for the serialization address.
367 static int SpaceOfAlreadySerializedObject(HeapObject* object);
368 int Allocate(int space, int size, bool* new_page_started);
369 int CurrentAllocationAddress(int space) {
370 if (SpaceIsLarge(space)) space = LO_SPACE;
371 return fullness_[space];
372 }
373 int EncodeExternalReference(Address addr) {
374 return external_reference_encoder_->Encode(addr);
375 }
376
377 // Keep track of the fullness of each space in order to generate
378 // relative addresses for back references. Large objects are
379 // just numbered sequentially since relative addresses make no
380 // sense in large object space.
381 int fullness_[LAST_SPACE + 1];
382 SnapshotByteSink* sink_;
383 int current_root_index_;
384 ExternalReferenceEncoder* external_reference_encoder_;
385 static bool serialization_enabled_;
386 // Did we already make use of the fact that serialization was not enabled?
387 static bool too_late_to_enable_now_;
388
389 friend class ObjectSerializer;
390 friend class Deserializer;
391
392 DISALLOW_COPY_AND_ASSIGN(Serializer);
393};
394
Steve Blocka7e24c12009-10-30 11:49:00 +0000395} } // namespace v8::internal
396
397#endif // V8_SERIALIZE_H_