1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // 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
33 namespace v8 {
34 namespace 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.
38 enum 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
53 const int kTypeCodeCount = STUB_CACHE_TABLE + 1;
54 const int kFirstTypeCode = UNCLASSIFIED;
55
56 const int kReferenceIdBits = 16;
57 const int kReferenceIdMask = (1 << kReferenceIdBits) - 1;
58 const int kReferenceTypeShift = kReferenceIdBits;
59 const int kDebugRegisterBits = 4;
60 const int kDebugIdShift = kDebugRegisterBits;
61
62
63 class 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_;
Hash(Address key)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
Match(void * key1,void * key2)79 static bool Match(void* key1, void* key2) { return key1 == key2; }
80
81 void Put(Address key, int index);
82
83 Isolate* isolate_;
84 };
85
86
87 class ExternalReferenceDecoder {
88 public:
89 ExternalReferenceDecoder();
90 ~ExternalReferenceDecoder();
91
Decode(uint32_t key)92 Address Decode(uint32_t key) const {
93 if (key == 0) return NULL;
94 return *Lookup(key);
95 }
96
97 private:
98 Address** encodings_;
99
Lookup(uint32_t key)100 Address* Lookup(uint32_t key) const {
101 int type = key >> kReferenceTypeShift;
102 ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount);
103 int id = key & kReferenceIdMask;
104 return &encodings_[type][id];
105 }
106
Put(uint32_t key,Address value)107 void Put(uint32_t key, Address value) {
108 *Lookup(key) = value;
109 }
110
111 Isolate* isolate_;
112 };
113
114
115 class SnapshotByteSource {
116 public:
SnapshotByteSource(const byte * array,int length)117 SnapshotByteSource(const byte* array, int length)
118 : data_(array), length_(length), position_(0) { }
119
HasMore()120 bool HasMore() { return position_ < length_; }
121
Get()122 int Get() {
123 ASSERT(position_ < length_);
124 return data_[position_++];
125 }
126
127 inline void CopyRaw(byte* to, int number_of_bytes);
128
129 inline int GetInt();
130
AtEOF()131 bool AtEOF() {
132 return position_ == length_;
133 }
134
position()135 int position() { return position_; }
136
137 private:
138 const byte* data_;
139 int length_;
140 int position_;
141 };
142
143
144 // It is very common to have a reference to objects at certain offsets in the
145 // heap. These offsets have been determined experimentally. We code
146 // references to such objects in a single byte that encodes the way the pointer
147 // is written (only plain pointers allowed), the space number and the offset.
148 // This only works for objects in the first page of a space. Don't use this for
149 // things in newspace since it bypasses the write barrier.
150
151 RLYSTC const int k64 = (sizeof(uintptr_t) - 4) / 4;
152
153 #define COMMON_REFERENCE_PATTERNS(f) \
154 f(kNumberOfSpaces, 2, (11 - k64)) \
155 f((kNumberOfSpaces + 1), 2, 0) \
156 f((kNumberOfSpaces + 2), 2, (142 - 16 * k64)) \
157 f((kNumberOfSpaces + 3), 2, (74 - 15 * k64)) \
158 f((kNumberOfSpaces + 4), 2, 5) \
159 f((kNumberOfSpaces + 5), 1, 135) \
160 f((kNumberOfSpaces + 6), 2, (228 - 39 * k64))
161
162 #define COMMON_RAW_LENGTHS(f) \
163 f(1, 1) \
164 f(2, 2) \
165 f(3, 3) \
166 f(4, 4) \
167 f(5, 5) \
168 f(6, 6) \
169 f(7, 7) \
170 f(8, 8) \
171 f(9, 12) \
172 f(10, 16) \
173 f(11, 20) \
174 f(12, 24) \
175 f(13, 28) \
176 f(14, 32) \
177 f(15, 36)
178
179 // The Serializer/Deserializer class is a common superclass for Serializer and
180 // Deserializer which is used to store common constants and methods used by
181 // both.
182 class SerializerDeserializer: public ObjectVisitor {
183 public:
184 RLYSTC void Iterate(ObjectVisitor* visitor);
185 RLYSTC void SetSnapshotCacheSize(int size);
186
187 protected:
188 // Where the pointed-to object can be found:
189 enum Where {
190 kNewObject = 0, // Object is next in snapshot.
191 // 1-8 One per space.
192 kRootArray = 0x9, // Object is found in root array.
193 kPartialSnapshotCache = 0xa, // Object is in the cache.
194 kExternalReference = 0xb, // Pointer to an external reference.
195 // 0xc-0xf Free.
196 kBackref = 0x10, // Object is described relative to end.
197 // 0x11-0x18 One per space.
198 // 0x19-0x1f Common backref offsets.
199 kFromStart = 0x20, // Object is described relative to start.
200 // 0x21-0x28 One per space.
201 // 0x29-0x2f Free.
202 // 0x30-0x3f Used by misc tags below.
203 kPointedToMask = 0x3f
204 };
205
206 // How to code the pointer to the object.
207 enum HowToCode {
208 kPlain = 0, // Straight pointer.
209 // What this means depends on the architecture:
210 kFromCode = 0x40, // A pointer inlined in code.
211 kHowToCodeMask = 0x40
212 };
213
214 // Where to point within the object.
215 enum WhereToPoint {
216 kStartOfObject = 0,
217 kFirstInstruction = 0x80,
218 kWhereToPointMask = 0x80
219 };
220
221 // Misc.
222 // Raw data to be copied from the snapshot.
223 RLYSTC const int kRawData = 0x30;
224 // Some common raw lengths: 0x31-0x3f
225 // A tag emitted at strategic points in the snapshot to delineate sections.
226 // If the deserializer does not find these at the expected moments then it
227 // is an indication that the snapshot and the VM do not fit together.
228 // Examine the build process for architecture, version or configuration
229 // mismatches.
230 RLYSTC const int kSynchronize = 0x70;
231 // Used for the source code of the natives, which is in the executable, but
232 // is referred to from external strings in the snapshot.
233 RLYSTC const int kNativesStringResource = 0x71;
234 RLYSTC const int kNewPage = 0x72;
235 // 0x73-0x7f Free.
236 // 0xb0-0xbf Free.
237 // 0xf0-0xff Free.
238
239
240 RLYSTC const int kLargeData = LAST_SPACE;
241 RLYSTC const int kLargeCode = kLargeData + 1;
242 RLYSTC const int kLargeFixedArray = kLargeCode + 1;
243 RLYSTC const int kNumberOfSpaces = kLargeFixedArray + 1;
244 RLYSTC const int kAnyOldSpace = -1;
245
246 // A bitmask for getting the space out of an instruction.
247 RLYSTC const int kSpaceMask = 15;
248
SpaceIsLarge(int space)249 RLYSTC inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
SpaceIsPaged(int space)250 RLYSTC inline bool SpaceIsPaged(int space) {
251 return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE;
252 }
253 };
254
255
GetInt()256 int SnapshotByteSource::GetInt() {
257 // A little unwind to catch the really small ints.
258 int snapshot_byte = Get();
259 if ((snapshot_byte & 0x80) == 0) {
260 return snapshot_byte;
261 }
262 int accumulator = (snapshot_byte & 0x7f) << 7;
263 while (true) {
264 snapshot_byte = Get();
265 if ((snapshot_byte & 0x80) == 0) {
266 return accumulator | snapshot_byte;
267 }
268 accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
269 }
270 UNREACHABLE();
271 return accumulator;
272 }
273
274
CopyRaw(byte * to,int number_of_bytes)275 void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
276 memcpy(to, data_ + position_, number_of_bytes);
277 position_ += number_of_bytes;
278 }
279
280
281 // A Deserializer reads a snapshot and reconstructs the Object graph it defines.
282 class Deserializer: public SerializerDeserializer {
283 public:
284 // Create a deserializer from a snapshot byte source.
285 explicit Deserializer(SnapshotByteSource* source);
286
287 virtual ~Deserializer();
288
289 // Deserialize the snapshot into an empty heap.
290 void Deserialize();
291
292 // Deserialize a single object and the objects reachable from it.
293 void DeserializePartial(Object** root);
294
295 #ifdef DEBUG
296 virtual void Synchronize(const char* tag);
297 #endif
298
299 private:
300 virtual void VisitPointers(Object** start, Object** end);
301
VisitExternalReferences(Address * start,Address * end)302 virtual void VisitExternalReferences(Address* start, Address* end) {
303 UNREACHABLE();
304 }
305
VisitRuntimeEntry(RelocInfo * rinfo)306 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
307 UNREACHABLE();
308 }
309
310 void ReadChunk(Object** start, Object** end, int space, Address address);
311 HeapObject* GetAddressFromStart(int space);
312 inline HeapObject* GetAddressFromEnd(int space);
313 Address Allocate(int space_number, Space* space, int size);
314 void ReadObject(int space_number, Space* space, Object** write_back);
315
316 // Cached current isolate.
317 Isolate* isolate_;
318
319 // Keep track of the pages in the paged spaces.
320 // (In large object space we are keeping track of individual objects
321 // rather than pages.) In new space we just need the address of the
322 // first object and the others will flow from that.
323 List<Address> pages_[SerializerDeserializer::kNumberOfSpaces];
324
325 SnapshotByteSource* source_;
326 // This is the address of the next object that will be allocated in each
327 // space. It is used to calculate the addresses of back-references.
328 Address high_water_[LAST_SPACE + 1];
329 // This is the address of the most recent object that was allocated. It
330 // is used to set the location of the new page when we encounter a
331 // START_NEW_PAGE_SERIALIZATION tag.
332 Address last_object_address_;
333
334 ExternalReferenceDecoder* external_reference_decoder_;
335
336 DISALLOW_COPY_AND_ASSIGN(Deserializer);
337 };
338
339
340 class SnapshotByteSink {
341 public:
~SnapshotByteSink()342 virtual ~SnapshotByteSink() { }
343 virtual void Put(int byte, const char* description) = 0;
PutSection(int byte,const char * description)344 virtual void PutSection(int byte, const char* description) {
345 Put(byte, description);
346 }
347 void PutInt(uintptr_t integer, const char* description);
348 virtual int Position() = 0;
349 };
350
351
352 // Mapping objects to their location after deserialization.
353 // This is used during building, but not at runtime by V8.
354 class SerializationAddressMapper {
355 public:
SerializationAddressMapper()356 SerializationAddressMapper()
357 : serialization_map_(new HashMap(&SerializationMatchFun)),
358 no_allocation_(new AssertNoAllocation()) { }
359
~SerializationAddressMapper()360 ~SerializationAddressMapper() {
361 delete serialization_map_;
362 delete no_allocation_;
363 }
364
IsMapped(HeapObject * obj)365 bool IsMapped(HeapObject* obj) {
366 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
367 }
368
MappedTo(HeapObject * obj)369 int MappedTo(HeapObject* obj) {
370 ASSERT(IsMapped(obj));
371 return static_cast<int>(reinterpret_cast<intptr_t>(
372 serialization_map_->Lookup(Key(obj), Hash(obj), false)->value));
373 }
374
AddMapping(HeapObject * obj,int to)375 void AddMapping(HeapObject* obj, int to) {
376 ASSERT(!IsMapped(obj));
377 HashMap::Entry* entry =
378 serialization_map_->Lookup(Key(obj), Hash(obj), true);
379 entry->value = Value(to);
380 }
381
382 private:
SerializationMatchFun(void * key1,void * key2)383 RLYSTC bool SerializationMatchFun(void* key1, void* key2) {
384 return key1 == key2;
385 }
386
Hash(HeapObject * obj)387 RLYSTC uint32_t Hash(HeapObject* obj) {
388 return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address()));
389 }
390
Key(HeapObject * obj)391 RLYSTC void* Key(HeapObject* obj) {
392 return reinterpret_cast<void*>(obj->address());
393 }
394
Value(int v)395 RLYSTC void* Value(int v) {
396 return reinterpret_cast<void*>(v);
397 }
398
399 HashMap* serialization_map_;
400 AssertNoAllocation* no_allocation_;
401 DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper);
402 };
403
404
405 // There can be only one serializer per V8 process.
406 STATIC_CLASS Serializer : public SerializerDeserializer {
407 public:
408 explicit Serializer(SnapshotByteSink* sink);
409 ~Serializer();
410 void VisitPointers(Object** start, Object** end);
411 // You can call this after serialization to find out how much space was used
412 // in each space.
CurrentAllocationAddress(int space)413 int CurrentAllocationAddress(int space) {
414 if (SpaceIsLarge(space)) return large_object_total_;
415 return fullness_[space];
416 }
417
Enable()418 RLYSTC void Enable() {
419 if (!serialization_enabled_) {
420 ASSERT(!too_late_to_enable_now_);
421 }
422 serialization_enabled_ = true;
423 }
424
Disable()425 RLYSTC void Disable() { serialization_enabled_ = false; }
426 // Call this when you have made use of the fact that there is no serialization
427 // going on.
TooLateToEnableNow()428 RLYSTC void TooLateToEnableNow() { too_late_to_enable_now_ = true; }
enabled()429 RLYSTC bool enabled() { return serialization_enabled_; }
address_mapper()430 SerializationAddressMapper* address_mapper() { return &address_mapper_; }
431 #ifdef DEBUG
432 virtual void Synchronize(const char* tag);
433 #endif
434
435 protected:
436 RLYSTC const int kInvalidRootIndex = -1;
437 virtual int RootIndex(HeapObject* heap_object) = 0;
438 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
439
440 class ObjectSerializer : public ObjectVisitor {
441 public:
ObjectSerializer(Serializer * serializer,Object * o,SnapshotByteSink * sink,HowToCode how_to_code,WhereToPoint where_to_point)442 ObjectSerializer(Serializer* serializer,
443 Object* o,
444 SnapshotByteSink* sink,
445 HowToCode how_to_code,
446 WhereToPoint where_to_point)
447 : serializer_(serializer),
448 object_(HeapObject::cast(o)),
449 sink_(sink),
450 reference_representation_(how_to_code + where_to_point),
451 bytes_processed_so_far_(0) { }
452 void Serialize();
453 void VisitPointers(Object** start, Object** end);
454 void VisitExternalReferences(Address* start, Address* end);
455 void VisitCodeTarget(RelocInfo* target);
456 void VisitCodeEntry(Address entry_address);
457 void VisitGlobalPropertyCell(RelocInfo* rinfo);
458 void VisitRuntimeEntry(RelocInfo* reloc);
459 // Used for seralizing the external strings that hold the natives source.
460 void VisitExternalAsciiString(
461 v8::String::ExternalAsciiStringResource** resource);
462 // We can't serialize a heap with external two byte strings.
VisitExternalTwoByteString(v8::String::ExternalStringResource ** resource)463 void VisitExternalTwoByteString(
464 v8::String::ExternalStringResource** resource) {
465 UNREACHABLE();
466 }
467
468 private:
469 void OutputRawData(Address up_to);
470
471 Serializer* serializer_;
472 HeapObject* object_;
473 SnapshotByteSink* sink_;
474 int reference_representation_;
475 int bytes_processed_so_far_;
476 };
477
478 virtual void SerializeObject(Object* o,
479 HowToCode how_to_code,
480 WhereToPoint where_to_point) = 0;
481 void SerializeReferenceToPreviousObject(
482 int space,
483 int address,
484 HowToCode how_to_code,
485 WhereToPoint where_to_point);
486 void InitializeAllocators();
487 // This will return the space for an object. If the object is in large
488 // object space it may return kLargeCode or kLargeFixedArray in order
489 // to indicate to the deserializer what kind of large object allocation
490 // to make.
491 RLYSTC int SpaceOfObject(HeapObject* object);
492 // This just returns the space of the object. It will return LO_SPACE
493 // for all large objects since you can't check the type of the object
494 // once the map has been used for the serialization address.
495 RLYSTC int SpaceOfAlreadySerializedObject(HeapObject* object);
496 int Allocate(int space, int size, bool* new_page_started);
EncodeExternalReference(Address addr)497 int EncodeExternalReference(Address addr) {
498 return external_reference_encoder_->Encode(addr);
499 }
500
501 // Keep track of the fullness of each space in order to generate
502 // relative addresses for back references. Large objects are
503 // just numbered sequentially since relative addresses make no
504 // sense in large object space.
505 int fullness_[LAST_SPACE + 1];
506 SnapshotByteSink* sink_;
507 int current_root_index_;
508 ExternalReferenceEncoder* external_reference_encoder_;
509 RLYSTC bool serialization_enabled_;
510 // Did we already make use of the fact that serialization was not enabled?
511 RLYSTC bool too_late_to_enable_now_;
512 int large_object_total_;
513 SerializationAddressMapper address_mapper_;
514
515 friend class ObjectSerializer;
516 friend class Deserializer;
517
518 DISALLOW_COPY_AND_ASSIGN(Serializer);
519 };
520
521
522 class PartialSerializer : public Serializer {
523 public:
PartialSerializer(Serializer * startup_snapshot_serializer,SnapshotByteSink * sink)524 PartialSerializer(Serializer* startup_snapshot_serializer,
525 SnapshotByteSink* sink)
526 : Serializer(sink),
527 startup_serializer_(startup_snapshot_serializer) {
528 }
529
530 // Serialize the objects reachable from a single object pointer.
531 virtual void Serialize(Object** o);
532 virtual void SerializeObject(Object* o,
533 HowToCode how_to_code,
534 WhereToPoint where_to_point);
535
536 protected:
537 virtual int RootIndex(HeapObject* o);
538 virtual int PartialSnapshotCacheIndex(HeapObject* o);
ShouldBeInThePartialSnapshotCache(HeapObject * o)539 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
540 // Scripts should be referred only through shared function infos. We can't
541 // allow them to be part of the partial snapshot because they contain a
542 // unique ID, and deserializing several partial snapshots containing script
543 // would cause dupes.
544 ASSERT(!o->IsScript());
545 return o->IsString() || o->IsSharedFunctionInfo() ||
546 o->IsHeapNumber() || o->IsCode() ||
547 o->map() == HEAP->fixed_cow_array_map();
548 }
549
550 private:
551 Serializer* startup_serializer_;
552 DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
553 };
554
555
556 class StartupSerializer : public Serializer {
557 public:
StartupSerializer(SnapshotByteSink * sink)558 explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) {
559 // Clear the cache of objects used by the partial snapshot. After the
560 // strong roots have been serialized we can create a partial snapshot
561 // which will repopulate the cache with objects neede by that partial
562 // snapshot.
563 Isolate::Current()->set_serialize_partial_snapshot_cache_length(0);
564 }
565 // Serialize the current state of the heap. The order is:
566 // 1) Strong references.
567 // 2) Partial snapshot cache.
568 // 3) Weak references (eg the symbol table).
569 virtual void SerializeStrongReferences();
570 virtual void SerializeObject(Object* o,
571 HowToCode how_to_code,
572 WhereToPoint where_to_point);
573 void SerializeWeakReferences();
Serialize()574 void Serialize() {
575 SerializeStrongReferences();
576 SerializeWeakReferences();
577 }
578
579 private:
RootIndex(HeapObject * o)580 virtual int RootIndex(HeapObject* o) { return kInvalidRootIndex; }
ShouldBeInThePartialSnapshotCache(HeapObject * o)581 virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
582 return false;
583 }
584 };
585
586
587 } } // namespace v8::internal
588
589 #endif // V8_SERIALIZE_H_
590