serialize.cc revision 3ce2e2076e8e3e60cf1810eec160ea2d8557e9e7
1// Copyright 2006-2008 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#include "v8.h"
29
30#include "accessors.h"
31#include "api.h"
32#include "execution.h"
33#include "global-handles.h"
34#include "ic-inl.h"
35#include "natives.h"
36#include "platform.h"
37#include "runtime.h"
38#include "serialize.h"
39#include "stub-cache.h"
40#include "v8threads.h"
41#include "top.h"
42
43namespace v8 {
44namespace internal {
45
46// 32-bit encoding: a RelativeAddress must be able to fit in a
47// pointer: it is encoded as an Address with (from LS to MS bits):
48// - 2 bits identifying this as a HeapObject.
49// - 4 bits to encode the AllocationSpace (including special values for
50//   code and fixed arrays in LO space)
51// - 27 bits identifying a word in the space, in one of three formats:
52// - paged spaces: 16 bits of page number, 11 bits of word offset in page
53// - NEW space:    27 bits of word offset
54// - LO space:     27 bits of page number
55
56const int kSpaceShift = kHeapObjectTagSize;
57const int kSpaceBits = 4;
58const int kSpaceMask = (1 << kSpaceBits) - 1;
59
60const int kOffsetShift = kSpaceShift + kSpaceBits;
61const int kOffsetBits = 11;
62const int kOffsetMask = (1 << kOffsetBits) - 1;
63
64const int kPageShift = kOffsetShift + kOffsetBits;
65const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);
66const int kPageMask = (1 << kPageBits) - 1;
67
68const int kPageAndOffsetShift = kOffsetShift;
69const int kPageAndOffsetBits = kPageBits + kOffsetBits;
70const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1;
71
72// These values are special allocation space tags used for
73// serialization.
74// Mark the pages executable on platforms that support it.
75const int kLargeCode = LAST_SPACE + 1;
76// Allocate extra remembered-set bits.
77const int kLargeFixedArray = LAST_SPACE + 2;
78
79
80static inline AllocationSpace GetSpace(Address addr) {
81  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
82  int space_number = (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
83  if (space_number > LAST_SPACE) space_number = LO_SPACE;
84  return static_cast<AllocationSpace>(space_number);
85}
86
87
88static inline bool IsLargeExecutableObject(Address addr) {
89  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
90  const int space_number =
91      (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
92  return (space_number == kLargeCode);
93}
94
95
96static inline bool IsLargeFixedArray(Address addr) {
97  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
98  const int space_number =
99      (static_cast<int>(encoded >> kSpaceShift) & kSpaceMask);
100  return (space_number == kLargeFixedArray);
101}
102
103
104static inline int PageIndex(Address addr) {
105  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
106  return static_cast<int>(encoded >> kPageShift) & kPageMask;
107}
108
109
110static inline int PageOffset(Address addr) {
111  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
112  const int offset = static_cast<int>(encoded >> kOffsetShift) & kOffsetMask;
113  return offset << kObjectAlignmentBits;
114}
115
116
117static inline int NewSpaceOffset(Address addr) {
118  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
119  const int page_offset =
120      static_cast<int>(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;
121  return page_offset << kObjectAlignmentBits;
122}
123
124
125static inline int LargeObjectIndex(Address addr) {
126  const intptr_t encoded = reinterpret_cast<intptr_t>(addr);
127  return static_cast<int>(encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;
128}
129
130
131// A RelativeAddress encodes a heap address that is independent of
132// the actual memory addresses in real heap. The general case (for the
133// OLD, CODE and MAP spaces) is as a (space id, page number, page offset)
134// triple. The NEW space has page number == 0, because there are no
135// pages. The LARGE_OBJECT space has page offset = 0, since there is
136// exactly one object per page.  RelativeAddresses are encodable as
137// Addresses, so that they can replace the map() pointers of
138// HeapObjects. The encoded Addresses are also encoded as HeapObjects
139// and allow for marking (is_marked() see mark(), clear_mark()...) as
140// used by the Mark-Compact collector.
141
142class RelativeAddress {
143 public:
144  RelativeAddress(AllocationSpace space,
145                  int page_index,
146                  int page_offset)
147  : space_(space), page_index_(page_index), page_offset_(page_offset)  {
148    // Assert that the space encoding (plus the two pseudo-spaces for
149    // special large objects) fits in the available bits.
150    ASSERT(((LAST_SPACE + 2) & ~kSpaceMask) == 0);
151    ASSERT(space <= LAST_SPACE && space >= 0);
152  }
153
154  // Return the encoding of 'this' as an Address. Decode with constructor.
155  Address Encode() const;
156
157  AllocationSpace space() const {
158    if (space_ > LAST_SPACE) return LO_SPACE;
159    return static_cast<AllocationSpace>(space_);
160  }
161  int page_index() const { return page_index_; }
162  int page_offset() const { return page_offset_; }
163
164  bool in_paged_space() const {
165    return space_ == CODE_SPACE ||
166           space_ == OLD_POINTER_SPACE ||
167           space_ == OLD_DATA_SPACE ||
168           space_ == MAP_SPACE ||
169           space_ == CELL_SPACE;
170  }
171
172  void next_address(int offset) { page_offset_ += offset; }
173  void next_page(int init_offset = 0) {
174    page_index_++;
175    page_offset_ = init_offset;
176  }
177
178#ifdef DEBUG
179  void Verify();
180#endif
181
182  void set_to_large_code_object() {
183    ASSERT(space_ == LO_SPACE);
184    space_ = kLargeCode;
185  }
186  void set_to_large_fixed_array() {
187    ASSERT(space_ == LO_SPACE);
188    space_ = kLargeFixedArray;
189  }
190
191
192 private:
193  int space_;
194  int page_index_;
195  int page_offset_;
196};
197
198
199Address RelativeAddress::Encode() const {
200  ASSERT(page_index_ >= 0);
201  int word_offset = 0;
202  int result = 0;
203  switch (space_) {
204    case MAP_SPACE:
205    case CELL_SPACE:
206    case OLD_POINTER_SPACE:
207    case OLD_DATA_SPACE:
208    case CODE_SPACE:
209      ASSERT_EQ(0, page_index_ & ~kPageMask);
210      word_offset = page_offset_ >> kObjectAlignmentBits;
211      ASSERT_EQ(0, word_offset & ~kOffsetMask);
212      result = (page_index_ << kPageShift) | (word_offset << kOffsetShift);
213      break;
214    case NEW_SPACE:
215      ASSERT_EQ(0, page_index_);
216      word_offset = page_offset_ >> kObjectAlignmentBits;
217      ASSERT_EQ(0, word_offset & ~kPageAndOffsetMask);
218      result = word_offset << kPageAndOffsetShift;
219      break;
220    case LO_SPACE:
221    case kLargeCode:
222    case kLargeFixedArray:
223      ASSERT_EQ(0, page_offset_);
224      ASSERT_EQ(0, page_index_ & ~kPageAndOffsetMask);
225      result = page_index_ << kPageAndOffsetShift;
226      break;
227  }
228  // OR in AllocationSpace and kHeapObjectTag
229  ASSERT_EQ(0, space_ & ~kSpaceMask);
230  result |= (space_ << kSpaceShift) | kHeapObjectTag;
231  return reinterpret_cast<Address>(result);
232}
233
234
235#ifdef DEBUG
236void RelativeAddress::Verify() {
237  ASSERT(page_offset_ >= 0 && page_index_ >= 0);
238  switch (space_) {
239    case MAP_SPACE:
240    case CELL_SPACE:
241    case OLD_POINTER_SPACE:
242    case OLD_DATA_SPACE:
243    case CODE_SPACE:
244      ASSERT(Page::kObjectStartOffset <= page_offset_ &&
245             page_offset_ <= Page::kPageSize);
246      break;
247    case NEW_SPACE:
248      ASSERT(page_index_ == 0);
249      break;
250    case LO_SPACE:
251    case kLargeCode:
252    case kLargeFixedArray:
253      ASSERT(page_offset_ == 0);
254      break;
255  }
256}
257#endif
258
259enum GCTreatment {
260  DataObject,     // Object that cannot contain a reference to new space.
261  PointerObject,  // Object that can contain a reference to new space.
262  CodeObject      // Object that contains executable code.
263};
264
265// A SimulatedHeapSpace simulates the allocation of objects in a page in
266// the heap. It uses linear allocation - that is, it doesn't simulate the
267// use of a free list. This simulated
268// allocation must exactly match that done by Heap.
269
270class SimulatedHeapSpace {
271 public:
272  // The default constructor initializes to an invalid state.
273  SimulatedHeapSpace(): current_(LAST_SPACE, -1, -1) {}
274
275  // Sets 'this' to the first address in 'space' that would be
276  // returned by allocation in an empty heap.
277  void InitEmptyHeap(AllocationSpace space);
278
279  // Sets 'this' to the next address in 'space' that would be returned
280  // by allocation in the current heap. Intended only for testing
281  // serialization and deserialization in the current address space.
282  void InitCurrentHeap(AllocationSpace space);
283
284  // Returns the RelativeAddress where the next
285  // object of 'size' bytes will be allocated, and updates 'this' to
286  // point to the next free address beyond that object.
287  RelativeAddress Allocate(int size, GCTreatment special_gc_treatment);
288
289 private:
290  RelativeAddress current_;
291};
292
293
294void SimulatedHeapSpace::InitEmptyHeap(AllocationSpace space) {
295  switch (space) {
296    case MAP_SPACE:
297    case CELL_SPACE:
298    case OLD_POINTER_SPACE:
299    case OLD_DATA_SPACE:
300    case CODE_SPACE:
301      current_ = RelativeAddress(space, 0, Page::kObjectStartOffset);
302      break;
303    case NEW_SPACE:
304    case LO_SPACE:
305      current_ = RelativeAddress(space, 0, 0);
306      break;
307  }
308}
309
310
311void SimulatedHeapSpace::InitCurrentHeap(AllocationSpace space) {
312  switch (space) {
313    case MAP_SPACE:
314    case CELL_SPACE:
315    case OLD_POINTER_SPACE:
316    case OLD_DATA_SPACE:
317    case CODE_SPACE: {
318      PagedSpace* ps;
319      if (space == MAP_SPACE) {
320        ps = Heap::map_space();
321      } else if (space == CELL_SPACE) {
322        ps = Heap::cell_space();
323      } else if (space == OLD_POINTER_SPACE) {
324        ps = Heap::old_pointer_space();
325      } else if (space == OLD_DATA_SPACE) {
326        ps = Heap::old_data_space();
327      } else {
328        ASSERT(space == CODE_SPACE);
329        ps = Heap::code_space();
330      }
331      Address top = ps->top();
332      Page* top_page = Page::FromAllocationTop(top);
333      int page_index = 0;
334      PageIterator it(ps, PageIterator::PAGES_IN_USE);
335      while (it.has_next()) {
336        if (it.next() == top_page) break;
337        page_index++;
338      }
339      current_ = RelativeAddress(space,
340                                 page_index,
341                                 top_page->Offset(top));
342      break;
343    }
344    case NEW_SPACE:
345      current_ = RelativeAddress(space,
346                                 0,
347                                 Heap::NewSpaceTop() - Heap::NewSpaceStart());
348      break;
349    case LO_SPACE:
350      int page_index = 0;
351      for (LargeObjectIterator it(Heap::lo_space()); it.has_next(); it.next()) {
352        page_index++;
353      }
354      current_ = RelativeAddress(space, page_index, 0);
355      break;
356  }
357}
358
359
360RelativeAddress SimulatedHeapSpace::Allocate(int size,
361                                             GCTreatment special_gc_treatment) {
362#ifdef DEBUG
363  current_.Verify();
364#endif
365  int alloc_size = OBJECT_SIZE_ALIGN(size);
366  if (current_.in_paged_space() &&
367      current_.page_offset() + alloc_size > Page::kPageSize) {
368    ASSERT(alloc_size <= Page::kMaxHeapObjectSize);
369    current_.next_page(Page::kObjectStartOffset);
370  }
371  RelativeAddress result = current_;
372  if (current_.space() == LO_SPACE) {
373    current_.next_page();
374    if (special_gc_treatment == CodeObject) {
375      result.set_to_large_code_object();
376    } else if (special_gc_treatment == PointerObject) {
377      result.set_to_large_fixed_array();
378    }
379  } else {
380    current_.next_address(alloc_size);
381  }
382#ifdef DEBUG
383  current_.Verify();
384  result.Verify();
385#endif
386  return result;
387}
388
389// -----------------------------------------------------------------------------
390// Coding of external references.
391
392// The encoding of an external reference. The type is in the high word.
393// The id is in the low word.
394static uint32_t EncodeExternal(TypeCode type, uint16_t id) {
395  return static_cast<uint32_t>(type) << 16 | id;
396}
397
398
399static int* GetInternalPointer(StatsCounter* counter) {
400  // All counters refer to dummy_counter, if deserializing happens without
401  // setting up counters.
402  static int dummy_counter = 0;
403  return counter->Enabled() ? counter->GetInternalPointer() : &dummy_counter;
404}
405
406
407// ExternalReferenceTable is a helper class that defines the relationship
408// between external references and their encodings. It is used to build
409// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
410class ExternalReferenceTable {
411 public:
412  static ExternalReferenceTable* instance() {
413    if (!instance_) instance_ = new ExternalReferenceTable();
414    return instance_;
415  }
416
417  int size() const { return refs_.length(); }
418
419  Address address(int i) { return refs_[i].address; }
420
421  uint32_t code(int i) { return refs_[i].code; }
422
423  const char* name(int i) { return refs_[i].name; }
424
425  int max_id(int code) { return max_id_[code]; }
426
427 private:
428  static ExternalReferenceTable* instance_;
429
430  ExternalReferenceTable() : refs_(64) { PopulateTable(); }
431  ~ExternalReferenceTable() { }
432
433  struct ExternalReferenceEntry {
434    Address address;
435    uint32_t code;
436    const char* name;
437  };
438
439  void PopulateTable();
440
441  // For a few types of references, we can get their address from their id.
442  void AddFromId(TypeCode type, uint16_t id, const char* name);
443
444  // For other types of references, the caller will figure out the address.
445  void Add(Address address, TypeCode type, uint16_t id, const char* name);
446
447  List<ExternalReferenceEntry> refs_;
448  int max_id_[kTypeCodeCount];
449};
450
451
452ExternalReferenceTable* ExternalReferenceTable::instance_ = NULL;
453
454
455void ExternalReferenceTable::AddFromId(TypeCode type,
456                                       uint16_t id,
457                                       const char* name) {
458  Address address;
459  switch (type) {
460    case C_BUILTIN: {
461      ExternalReference ref(static_cast<Builtins::CFunctionId>(id));
462      address = ref.address();
463      break;
464    }
465    case BUILTIN: {
466      ExternalReference ref(static_cast<Builtins::Name>(id));
467      address = ref.address();
468      break;
469    }
470    case RUNTIME_FUNCTION: {
471      ExternalReference ref(static_cast<Runtime::FunctionId>(id));
472      address = ref.address();
473      break;
474    }
475    case IC_UTILITY: {
476      ExternalReference ref(IC_Utility(static_cast<IC::UtilityId>(id)));
477      address = ref.address();
478      break;
479    }
480    default:
481      UNREACHABLE();
482      return;
483  }
484  Add(address, type, id, name);
485}
486
487
488void ExternalReferenceTable::Add(Address address,
489                                 TypeCode type,
490                                 uint16_t id,
491                                 const char* name) {
492  CHECK_NE(NULL, address);
493  ExternalReferenceEntry entry;
494  entry.address = address;
495  entry.code = EncodeExternal(type, id);
496  entry.name = name;
497  CHECK_NE(0, entry.code);
498  refs_.Add(entry);
499  if (id > max_id_[type]) max_id_[type] = id;
500}
501
502
503void ExternalReferenceTable::PopulateTable() {
504  for (int type_code = 0; type_code < kTypeCodeCount; type_code++) {
505    max_id_[type_code] = 0;
506  }
507
508  // The following populates all of the different type of external references
509  // into the ExternalReferenceTable.
510  //
511  // NOTE: This function was originally 100k of code.  It has since been
512  // rewritten to be mostly table driven, as the callback macro style tends to
513  // very easily cause code bloat.  Please be careful in the future when adding
514  // new references.
515
516  struct RefTableEntry {
517    TypeCode type;
518    uint16_t id;
519    const char* name;
520  };
521
522  static const RefTableEntry ref_table[] = {
523  // Builtins
524#define DEF_ENTRY_C(name) \
525  { C_BUILTIN, \
526    Builtins::c_##name, \
527    "Builtins::" #name },
528
529  BUILTIN_LIST_C(DEF_ENTRY_C)
530#undef DEF_ENTRY_C
531
532#define DEF_ENTRY_C(name) \
533  { BUILTIN, \
534    Builtins::name, \
535    "Builtins::" #name },
536#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name)
537
538  BUILTIN_LIST_C(DEF_ENTRY_C)
539  BUILTIN_LIST_A(DEF_ENTRY_A)
540  BUILTIN_LIST_DEBUG_A(DEF_ENTRY_A)
541#undef DEF_ENTRY_C
542#undef DEF_ENTRY_A
543
544  // Runtime functions
545#define RUNTIME_ENTRY(name, nargs, ressize) \
546  { RUNTIME_FUNCTION, \
547    Runtime::k##name, \
548    "Runtime::" #name },
549
550  RUNTIME_FUNCTION_LIST(RUNTIME_ENTRY)
551#undef RUNTIME_ENTRY
552
553  // IC utilities
554#define IC_ENTRY(name) \
555  { IC_UTILITY, \
556    IC::k##name, \
557    "IC::" #name },
558
559  IC_UTIL_LIST(IC_ENTRY)
560#undef IC_ENTRY
561  };  // end of ref_table[].
562
563  for (size_t i = 0; i < ARRAY_SIZE(ref_table); ++i) {
564    AddFromId(ref_table[i].type, ref_table[i].id, ref_table[i].name);
565  }
566
567#ifdef ENABLE_DEBUGGER_SUPPORT
568  // Debug addresses
569  Add(Debug_Address(Debug::k_after_break_target_address).address(),
570      DEBUG_ADDRESS,
571      Debug::k_after_break_target_address << kDebugIdShift,
572      "Debug::after_break_target_address()");
573  Add(Debug_Address(Debug::k_debug_break_return_address).address(),
574      DEBUG_ADDRESS,
575      Debug::k_debug_break_return_address << kDebugIdShift,
576      "Debug::debug_break_return_address()");
577  const char* debug_register_format = "Debug::register_address(%i)";
578  size_t dr_format_length = strlen(debug_register_format);
579  for (int i = 0; i < kNumJSCallerSaved; ++i) {
580    Vector<char> name = Vector<char>::New(dr_format_length + 1);
581    OS::SNPrintF(name, debug_register_format, i);
582    Add(Debug_Address(Debug::k_register_address, i).address(),
583        DEBUG_ADDRESS,
584        Debug::k_register_address << kDebugIdShift | i,
585        name.start());
586  }
587#endif
588
589  // Stat counters
590  struct StatsRefTableEntry {
591    StatsCounter* counter;
592    uint16_t id;
593    const char* name;
594  };
595
596  static const StatsRefTableEntry stats_ref_table[] = {
597#define COUNTER_ENTRY(name, caption) \
598  { &Counters::name, \
599    Counters::k_##name, \
600    "Counters::" #name },
601
602  STATS_COUNTER_LIST_1(COUNTER_ENTRY)
603  STATS_COUNTER_LIST_2(COUNTER_ENTRY)
604#undef COUNTER_ENTRY
605  };  // end of stats_ref_table[].
606
607  for (size_t i = 0; i < ARRAY_SIZE(stats_ref_table); ++i) {
608    Add(reinterpret_cast<Address>(
609            GetInternalPointer(stats_ref_table[i].counter)),
610        STATS_COUNTER,
611        stats_ref_table[i].id,
612        stats_ref_table[i].name);
613  }
614
615  // Top addresses
616  const char* top_address_format = "Top::%s";
617
618  const char* AddressNames[] = {
619#define C(name) #name,
620    TOP_ADDRESS_LIST(C)
621    TOP_ADDRESS_LIST_PROF(C)
622    NULL
623#undef C
624  };
625
626  size_t top_format_length = strlen(top_address_format) - 2;
627  for (uint16_t i = 0; i < Top::k_top_address_count; ++i) {
628    const char* address_name = AddressNames[i];
629    Vector<char> name =
630        Vector<char>::New(top_format_length + strlen(address_name) + 1);
631    const char* chars = name.start();
632    OS::SNPrintF(name, top_address_format, address_name);
633    Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
634  }
635
636  // Extensions
637  Add(FUNCTION_ADDR(GCExtension::GC), EXTENSION, 1,
638      "GCExtension::GC");
639
640  // Accessors
641#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
642  Add((Address)&Accessors::name, \
643      ACCESSOR, \
644      Accessors::k##name, \
645      "Accessors::" #name);
646
647  ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
648#undef ACCESSOR_DESCRIPTOR_DECLARATION
649
650  // Stub cache tables
651  Add(SCTableReference::keyReference(StubCache::kPrimary).address(),
652      STUB_CACHE_TABLE,
653      1,
654      "StubCache::primary_->key");
655  Add(SCTableReference::valueReference(StubCache::kPrimary).address(),
656      STUB_CACHE_TABLE,
657      2,
658      "StubCache::primary_->value");
659  Add(SCTableReference::keyReference(StubCache::kSecondary).address(),
660      STUB_CACHE_TABLE,
661      3,
662      "StubCache::secondary_->key");
663  Add(SCTableReference::valueReference(StubCache::kSecondary).address(),
664      STUB_CACHE_TABLE,
665      4,
666      "StubCache::secondary_->value");
667
668  // Runtime entries
669  Add(ExternalReference::perform_gc_function().address(),
670      RUNTIME_ENTRY,
671      1,
672      "Runtime::PerformGC");
673  Add(ExternalReference::random_positive_smi_function().address(),
674      RUNTIME_ENTRY,
675      2,
676      "V8::RandomPositiveSmi");
677
678  // Miscellaneous
679  Add(ExternalReference::builtin_passed_function().address(),
680      UNCLASSIFIED,
681      1,
682      "Builtins::builtin_passed_function");
683  Add(ExternalReference::the_hole_value_location().address(),
684      UNCLASSIFIED,
685      2,
686      "Factory::the_hole_value().location()");
687  Add(ExternalReference::roots_address().address(),
688      UNCLASSIFIED,
689      3,
690      "Heap::roots_address()");
691  Add(ExternalReference::address_of_stack_guard_limit().address(),
692      UNCLASSIFIED,
693      4,
694      "StackGuard::address_of_jslimit()");
695  Add(ExternalReference::address_of_regexp_stack_limit().address(),
696      UNCLASSIFIED,
697      5,
698      "RegExpStack::limit_address()");
699  Add(ExternalReference::new_space_start().address(),
700      UNCLASSIFIED,
701      6,
702      "Heap::NewSpaceStart()");
703  Add(ExternalReference::heap_always_allocate_scope_depth().address(),
704      UNCLASSIFIED,
705      7,
706      "Heap::always_allocate_scope_depth()");
707  Add(ExternalReference::new_space_allocation_limit_address().address(),
708      UNCLASSIFIED,
709      8,
710      "Heap::NewSpaceAllocationLimitAddress()");
711  Add(ExternalReference::new_space_allocation_top_address().address(),
712      UNCLASSIFIED,
713      9,
714      "Heap::NewSpaceAllocationTopAddress()");
715#ifdef ENABLE_DEBUGGER_SUPPORT
716  Add(ExternalReference::debug_break().address(),
717      UNCLASSIFIED,
718      10,
719      "Debug::Break()");
720  Add(ExternalReference::debug_step_in_fp_address().address(),
721      UNCLASSIFIED,
722      11,
723      "Debug::step_in_fp_addr()");
724#endif
725  Add(ExternalReference::double_fp_operation(Token::ADD).address(),
726      UNCLASSIFIED,
727      12,
728      "add_two_doubles");
729  Add(ExternalReference::double_fp_operation(Token::SUB).address(),
730      UNCLASSIFIED,
731      13,
732      "sub_two_doubles");
733  Add(ExternalReference::double_fp_operation(Token::MUL).address(),
734      UNCLASSIFIED,
735      14,
736      "mul_two_doubles");
737  Add(ExternalReference::double_fp_operation(Token::DIV).address(),
738      UNCLASSIFIED,
739      15,
740      "div_two_doubles");
741  Add(ExternalReference::double_fp_operation(Token::MOD).address(),
742      UNCLASSIFIED,
743      16,
744      "mod_two_doubles");
745  Add(ExternalReference::compare_doubles().address(),
746      UNCLASSIFIED,
747      17,
748      "compare_doubles");
749#ifdef V8_NATIVE_REGEXP
750  Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
751      UNCLASSIFIED,
752      18,
753      "NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
754  Add(ExternalReference::re_check_stack_guard_state().address(),
755      UNCLASSIFIED,
756      19,
757      "RegExpMacroAssembler*::CheckStackGuardState()");
758  Add(ExternalReference::re_grow_stack().address(),
759      UNCLASSIFIED,
760      20,
761      "NativeRegExpMacroAssembler::GrowStack()");
762#endif
763}
764
765
766ExternalReferenceEncoder::ExternalReferenceEncoder()
767    : encodings_(Match) {
768  ExternalReferenceTable* external_references =
769      ExternalReferenceTable::instance();
770  for (int i = 0; i < external_references->size(); ++i) {
771    Put(external_references->address(i), i);
772  }
773}
774
775
776uint32_t ExternalReferenceEncoder::Encode(Address key) const {
777  int index = IndexOf(key);
778  return index >=0 ? ExternalReferenceTable::instance()->code(index) : 0;
779}
780
781
782const char* ExternalReferenceEncoder::NameOfAddress(Address key) const {
783  int index = IndexOf(key);
784  return index >=0 ? ExternalReferenceTable::instance()->name(index) : NULL;
785}
786
787
788int ExternalReferenceEncoder::IndexOf(Address key) const {
789  if (key == NULL) return -1;
790  HashMap::Entry* entry =
791      const_cast<HashMap &>(encodings_).Lookup(key, Hash(key), false);
792  return entry == NULL
793      ? -1
794      : static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
795}
796
797
798void ExternalReferenceEncoder::Put(Address key, int index) {
799  HashMap::Entry* entry = encodings_.Lookup(key, Hash(key), true);
800  entry->value = reinterpret_cast<void *>(index);
801}
802
803
804ExternalReferenceDecoder::ExternalReferenceDecoder()
805  : encodings_(NewArray<Address*>(kTypeCodeCount)) {
806  ExternalReferenceTable* external_references =
807      ExternalReferenceTable::instance();
808  for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
809    int max = external_references->max_id(type) + 1;
810    encodings_[type] = NewArray<Address>(max + 1);
811  }
812  for (int i = 0; i < external_references->size(); ++i) {
813    Put(external_references->code(i), external_references->address(i));
814  }
815}
816
817
818ExternalReferenceDecoder::~ExternalReferenceDecoder() {
819  for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
820    DeleteArray(encodings_[type]);
821  }
822  DeleteArray(encodings_);
823}
824
825
826//------------------------------------------------------------------------------
827// Implementation of Serializer
828
829
830// Helper class to write the bytes of the serialized heap.
831
832class SnapshotWriter {
833 public:
834  SnapshotWriter() {
835    len_ = 0;
836    max_ = 8 << 10;  // 8K initial size
837    str_ = NewArray<byte>(max_);
838  }
839
840  ~SnapshotWriter() {
841    DeleteArray(str_);
842  }
843
844  void GetBytes(byte** str, int* len) {
845    *str = NewArray<byte>(len_);
846    memcpy(*str, str_, len_);
847    *len = len_;
848  }
849
850  void Reserve(int bytes, int pos);
851
852  void PutC(char c) {
853    InsertC(c, len_);
854  }
855
856  void PutInt(int i) {
857    InsertInt(i, len_);
858  }
859
860  void PutAddress(Address p) {
861    PutBytes(reinterpret_cast<byte*>(&p), sizeof(p));
862  }
863
864  void PutBytes(const byte* a, int size) {
865    InsertBytes(a, len_, size);
866  }
867
868  void PutString(const char* s) {
869    InsertString(s, len_);
870  }
871
872  int InsertC(char c, int pos) {
873    Reserve(1, pos);
874    str_[pos] = c;
875    len_++;
876    return pos + 1;
877  }
878
879  int InsertInt(int i, int pos) {
880    return InsertBytes(reinterpret_cast<byte*>(&i), pos, sizeof(i));
881  }
882
883  int InsertBytes(const byte* a, int pos, int size) {
884    Reserve(size, pos);
885    memcpy(&str_[pos], a, size);
886    len_ += size;
887    return pos + size;
888  }
889
890  int InsertString(const char* s, int pos);
891
892  int length() { return len_; }
893
894  Address position() { return reinterpret_cast<Address>(&str_[len_]); }
895
896 private:
897  byte* str_;  // the snapshot
898  int len_;   // the current length of str_
899  int max_;   // the allocated size of str_
900};
901
902
903void SnapshotWriter::Reserve(int bytes, int pos) {
904  CHECK(0 <= pos && pos <= len_);
905  while (len_ + bytes >= max_) {
906    max_ *= 2;
907    byte* old = str_;
908    str_ = NewArray<byte>(max_);
909    memcpy(str_, old, len_);
910    DeleteArray(old);
911  }
912  if (pos < len_) {
913    byte* old = str_;
914    str_ = NewArray<byte>(max_);
915    memcpy(str_, old, pos);
916    memcpy(str_ + pos + bytes, old + pos, len_ - pos);
917    DeleteArray(old);
918  }
919}
920
921int SnapshotWriter::InsertString(const char* s, int pos) {
922  int size = strlen(s);
923  pos = InsertC('[', pos);
924  pos = InsertInt(size, pos);
925  pos = InsertC(']', pos);
926  return InsertBytes(reinterpret_cast<const byte*>(s), pos, size);
927}
928
929
930class ReferenceUpdater: public ObjectVisitor {
931 public:
932  ReferenceUpdater(HeapObject* obj, Serializer* serializer)
933    : obj_address_(obj->address()),
934      serializer_(serializer),
935      reference_encoder_(serializer->reference_encoder_),
936      offsets_(8),
937      addresses_(8),
938      offsets_32_bit_(0),
939      data_32_bit_(0) {
940  }
941
942  virtual void VisitPointers(Object** start, Object** end) {
943    for (Object** p = start; p < end; ++p) {
944      if ((*p)->IsHeapObject()) {
945        offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
946        Address a = serializer_->GetSavedAddress(HeapObject::cast(*p));
947        addresses_.Add(a);
948      }
949    }
950  }
951
952  virtual void VisitCodeTarget(RelocInfo* rinfo) {
953    ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
954    Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
955    Address encoded_target = serializer_->GetSavedAddress(target);
956    // All calls and jumps are to code objects that encode into 32 bits.
957    offsets_32_bit_.Add(rinfo->target_address_address() - obj_address_);
958    uint32_t small_target =
959        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(encoded_target));
960    ASSERT(reinterpret_cast<uintptr_t>(encoded_target) == small_target);
961    data_32_bit_.Add(small_target);
962  }
963
964
965  virtual void VisitExternalReferences(Address* start, Address* end) {
966    for (Address* p = start; p < end; ++p) {
967      uint32_t code = reference_encoder_->Encode(*p);
968      CHECK(*p == NULL ? code == 0 : code != 0);
969      offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
970      addresses_.Add(reinterpret_cast<Address>(code));
971    }
972  }
973
974  virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
975    Address target = rinfo->target_address();
976    uint32_t encoding = reference_encoder_->Encode(target);
977    CHECK(target == NULL ? encoding == 0 : encoding != 0);
978    offsets_.Add(rinfo->target_address_address() - obj_address_);
979    addresses_.Add(reinterpret_cast<Address>(encoding));
980  }
981
982  void Update(Address start_address) {
983    for (int i = 0; i < offsets_.length(); i++) {
984      memcpy(start_address + offsets_[i], &addresses_[i], sizeof(Address));
985    }
986    for (int i = 0; i < offsets_32_bit_.length(); i++) {
987      memcpy(start_address + offsets_32_bit_[i], &data_32_bit_[i],
988             sizeof(uint32_t));
989    }
990  }
991
992 private:
993  Address obj_address_;
994  Serializer* serializer_;
995  ExternalReferenceEncoder* reference_encoder_;
996  List<int> offsets_;
997  List<Address> addresses_;
998  // Some updates are 32-bit even on a 64-bit platform.
999  // We keep a separate list of them on 64-bit platforms.
1000  List<int> offsets_32_bit_;
1001  List<uint32_t> data_32_bit_;
1002};
1003
1004
1005// Helper functions for a map of encoded heap object addresses.
1006static uint32_t HeapObjectHash(HeapObject* key) {
1007  uint32_t low32bits = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key));
1008  return low32bits >> 2;
1009}
1010
1011
1012static bool MatchHeapObject(void* key1, void* key2) {
1013  return key1 == key2;
1014}
1015
1016
1017Serializer::Serializer()
1018  : global_handles_(4),
1019    saved_addresses_(MatchHeapObject) {
1020  root_ = true;
1021  roots_ = 0;
1022  objects_ = 0;
1023  reference_encoder_ = NULL;
1024  writer_ = new SnapshotWriter();
1025  for (int i = 0; i <= LAST_SPACE; i++) {
1026    allocator_[i] = new SimulatedHeapSpace();
1027  }
1028}
1029
1030
1031Serializer::~Serializer() {
1032  for (int i = 0; i <= LAST_SPACE; i++) {
1033    delete allocator_[i];
1034  }
1035  if (reference_encoder_) delete reference_encoder_;
1036  delete writer_;
1037}
1038
1039
1040bool Serializer::serialization_enabled_ = false;
1041
1042
1043#ifdef DEBUG
1044static const int kMaxTagLength = 32;
1045
1046void Serializer::Synchronize(const char* tag) {
1047  if (FLAG_debug_serialization) {
1048    int length = strlen(tag);
1049    ASSERT(length <= kMaxTagLength);
1050    writer_->PutC('S');
1051    writer_->PutInt(length);
1052    writer_->PutBytes(reinterpret_cast<const byte*>(tag), length);
1053  }
1054}
1055#endif
1056
1057
1058void Serializer::InitializeAllocators() {
1059  for (int i = 0; i <= LAST_SPACE; i++) {
1060    allocator_[i]->InitEmptyHeap(static_cast<AllocationSpace>(i));
1061  }
1062}
1063
1064
1065bool Serializer::IsVisited(HeapObject* obj) {
1066  HashMap::Entry* entry =
1067    saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
1068  return entry != NULL;
1069}
1070
1071
1072Address Serializer::GetSavedAddress(HeapObject* obj) {
1073  HashMap::Entry* entry =
1074    saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
1075  ASSERT(entry != NULL);
1076  return reinterpret_cast<Address>(entry->value);
1077}
1078
1079
1080void Serializer::SaveAddress(HeapObject* obj, Address addr) {
1081  HashMap::Entry* entry =
1082    saved_addresses_.Lookup(obj, HeapObjectHash(obj), true);
1083  entry->value = addr;
1084}
1085
1086
1087void Serializer::Serialize() {
1088  // No active threads.
1089  CHECK_EQ(NULL, ThreadState::FirstInUse());
1090  // No active or weak handles.
1091  CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
1092  CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
1093  // We need a counter function during serialization to resolve the
1094  // references to counters in the code on the heap.
1095  CHECK(StatsTable::HasCounterFunction());
1096  CHECK(enabled());
1097  InitializeAllocators();
1098  reference_encoder_ = new ExternalReferenceEncoder();
1099  PutHeader();
1100  Heap::IterateRoots(this);
1101  PutLog();
1102  PutContextStack();
1103  Disable();
1104}
1105
1106
1107void Serializer::Finalize(byte** str, int* len) {
1108  writer_->GetBytes(str, len);
1109}
1110
1111
1112// Serialize objects by writing them into the stream.
1113
1114void Serializer::VisitPointers(Object** start, Object** end) {
1115  bool root = root_;
1116  root_ = false;
1117  for (Object** p = start; p < end; ++p) {
1118    bool serialized;
1119    Address a = Encode(*p, &serialized);
1120    if (root) {
1121      roots_++;
1122      // If the object was not just serialized,
1123      // write its encoded address instead.
1124      if (!serialized) PutEncodedAddress(a);
1125    }
1126  }
1127  root_ = root;
1128}
1129
1130
1131void Serializer::VisitCodeTarget(RelocInfo* rinfo) {
1132  ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
1133  Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1134  bool serialized;
1135  Encode(target, &serialized);
1136}
1137
1138
1139class GlobalHandlesRetriever: public ObjectVisitor {
1140 public:
1141  explicit GlobalHandlesRetriever(List<Object**>* handles)
1142  : global_handles_(handles) {}
1143
1144  virtual void VisitPointers(Object** start, Object** end) {
1145    for (; start != end; ++start) {
1146      global_handles_->Add(start);
1147    }
1148  }
1149
1150 private:
1151  List<Object**>* global_handles_;
1152};
1153
1154
1155void Serializer::PutFlags() {
1156  writer_->PutC('F');
1157  List<const char*>* argv = FlagList::argv();
1158  writer_->PutInt(argv->length());
1159  writer_->PutC('[');
1160  for (int i = 0; i < argv->length(); i++) {
1161    if (i > 0) writer_->PutC('|');
1162    writer_->PutString((*argv)[i]);
1163    DeleteArray((*argv)[i]);
1164  }
1165  writer_->PutC(']');
1166  flags_end_ = writer_->length();
1167  delete argv;
1168}
1169
1170
1171void Serializer::PutHeader() {
1172  PutFlags();
1173  writer_->PutC('D');
1174#ifdef DEBUG
1175  writer_->PutC(FLAG_debug_serialization ? '1' : '0');
1176#else
1177  writer_->PutC('0');
1178#endif
1179#ifdef V8_NATIVE_REGEXP
1180  writer_->PutC('N');
1181#else  // Interpreted regexp
1182  writer_->PutC('I');
1183#endif
1184  // Write sizes of paged memory spaces. Allocate extra space for the old
1185  // and code spaces, because objects in new space will be promoted to them.
1186  writer_->PutC('S');
1187  writer_->PutC('[');
1188  writer_->PutInt(Heap::old_pointer_space()->Size() +
1189                  Heap::new_space()->Size());
1190  writer_->PutC('|');
1191  writer_->PutInt(Heap::old_data_space()->Size() + Heap::new_space()->Size());
1192  writer_->PutC('|');
1193  writer_->PutInt(Heap::code_space()->Size() + Heap::new_space()->Size());
1194  writer_->PutC('|');
1195  writer_->PutInt(Heap::map_space()->Size());
1196  writer_->PutC('|');
1197  writer_->PutInt(Heap::cell_space()->Size());
1198  writer_->PutC(']');
1199  // Write global handles.
1200  writer_->PutC('G');
1201  writer_->PutC('[');
1202  GlobalHandlesRetriever ghr(&global_handles_);
1203  GlobalHandles::IterateRoots(&ghr);
1204  for (int i = 0; i < global_handles_.length(); i++) {
1205    writer_->PutC('N');
1206  }
1207  writer_->PutC(']');
1208}
1209
1210
1211void Serializer::PutLog() {
1212#ifdef ENABLE_LOGGING_AND_PROFILING
1213  if (FLAG_log_code) {
1214    Logger::TearDown();
1215    int pos = writer_->InsertC('L', flags_end_);
1216    bool exists;
1217    Vector<const char> log = ReadFile(FLAG_logfile, &exists);
1218    writer_->InsertString(log.start(), pos);
1219    log.Dispose();
1220  }
1221#endif
1222}
1223
1224
1225static int IndexOf(const List<Object**>& list, Object** element) {
1226  for (int i = 0; i < list.length(); i++) {
1227    if (list[i] == element) return i;
1228  }
1229  return -1;
1230}
1231
1232
1233void Serializer::PutGlobalHandleStack(const List<Handle<Object> >& stack) {
1234  writer_->PutC('[');
1235  writer_->PutInt(stack.length());
1236  for (int i = stack.length() - 1; i >= 0; i--) {
1237    writer_->PutC('|');
1238    int gh_index = IndexOf(global_handles_, stack[i].location());
1239    CHECK_GE(gh_index, 0);
1240    writer_->PutInt(gh_index);
1241  }
1242  writer_->PutC(']');
1243}
1244
1245
1246void Serializer::PutContextStack() {
1247  List<Context*> contexts(2);
1248  while (HandleScopeImplementer::instance()->HasSavedContexts()) {
1249    Context* context =
1250      HandleScopeImplementer::instance()->RestoreContext();
1251    contexts.Add(context);
1252  }
1253  for (int i = contexts.length() - 1; i >= 0; i--) {
1254    HandleScopeImplementer::instance()->SaveContext(contexts[i]);
1255  }
1256  writer_->PutC('C');
1257  writer_->PutC('[');
1258  writer_->PutInt(contexts.length());
1259  if (!contexts.is_empty()) {
1260    Object** start = reinterpret_cast<Object**>(&contexts.first());
1261    VisitPointers(start, start + contexts.length());
1262  }
1263  writer_->PutC(']');
1264}
1265
1266void Serializer::PutEncodedAddress(Address addr) {
1267  writer_->PutC('P');
1268  writer_->PutAddress(addr);
1269}
1270
1271
1272Address Serializer::Encode(Object* o, bool* serialized) {
1273  *serialized = false;
1274  if (o->IsSmi()) {
1275    return reinterpret_cast<Address>(o);
1276  } else {
1277    HeapObject* obj = HeapObject::cast(o);
1278    if (IsVisited(obj)) {
1279      return GetSavedAddress(obj);
1280    } else {
1281      // First visit: serialize the object.
1282      *serialized = true;
1283      return PutObject(obj);
1284    }
1285  }
1286}
1287
1288
1289Address Serializer::PutObject(HeapObject* obj) {
1290  Map* map = obj->map();
1291  InstanceType type = map->instance_type();
1292  int size = obj->SizeFromMap(map);
1293
1294  // Simulate the allocation of obj to predict where it will be
1295  // allocated during deserialization.
1296  Address addr = Allocate(obj).Encode();
1297
1298  SaveAddress(obj, addr);
1299
1300  if (type == CODE_TYPE) {
1301    LOG(CodeMoveEvent(obj->address(), addr));
1302  }
1303
1304  // Write out the object prologue: type, size, and simulated address of obj.
1305  writer_->PutC('[');
1306  CHECK_EQ(0, static_cast<int>(size & kObjectAlignmentMask));
1307  writer_->PutInt(type);
1308  writer_->PutInt(size >> kObjectAlignmentBits);
1309  PutEncodedAddress(addr);  // encodes AllocationSpace
1310
1311  // Visit all the pointers in the object other than the map. This
1312  // will recursively serialize any as-yet-unvisited objects.
1313  obj->Iterate(this);
1314
1315  // Mark end of recursively embedded objects, start of object body.
1316  writer_->PutC('|');
1317  // Write out the raw contents of the object. No compression, but
1318  // fast to deserialize.
1319  writer_->PutBytes(obj->address(), size);
1320  // Update pointers and external references in the written object.
1321  ReferenceUpdater updater(obj, this);
1322  obj->Iterate(&updater);
1323  updater.Update(writer_->position() - size);
1324
1325#ifdef DEBUG
1326  if (FLAG_debug_serialization) {
1327    // Write out the object epilogue to catch synchronization errors.
1328    PutEncodedAddress(addr);
1329    writer_->PutC(']');
1330  }
1331#endif
1332
1333  objects_++;
1334  return addr;
1335}
1336
1337
1338RelativeAddress Serializer::Allocate(HeapObject* obj) {
1339  // Find out which AllocationSpace 'obj' is in.
1340  AllocationSpace s;
1341  bool found = false;
1342  for (int i = FIRST_SPACE; !found && i <= LAST_SPACE; i++) {
1343    s = static_cast<AllocationSpace>(i);
1344    found = Heap::InSpace(obj, s);
1345  }
1346  CHECK(found);
1347  int size = obj->Size();
1348  if (s == NEW_SPACE) {
1349    if (size > Heap::MaxObjectSizeInPagedSpace()) {
1350      s = LO_SPACE;
1351    } else {
1352      OldSpace* space = Heap::TargetSpace(obj);
1353      ASSERT(space == Heap::old_pointer_space() ||
1354             space == Heap::old_data_space());
1355      s = (space == Heap::old_pointer_space()) ?
1356          OLD_POINTER_SPACE :
1357          OLD_DATA_SPACE;
1358    }
1359  }
1360  GCTreatment gc_treatment = DataObject;
1361  if (obj->IsFixedArray()) gc_treatment = PointerObject;
1362  else if (obj->IsCode()) gc_treatment = CodeObject;
1363  return allocator_[s]->Allocate(size, gc_treatment);
1364}
1365
1366
1367//------------------------------------------------------------------------------
1368// Implementation of Deserializer
1369
1370
1371static const int kInitArraySize = 32;
1372
1373
1374Deserializer::Deserializer(const byte* str, int len)
1375  : reader_(str, len),
1376    map_pages_(kInitArraySize),
1377    cell_pages_(kInitArraySize),
1378    old_pointer_pages_(kInitArraySize),
1379    old_data_pages_(kInitArraySize),
1380    code_pages_(kInitArraySize),
1381    large_objects_(kInitArraySize),
1382    global_handles_(4) {
1383  root_ = true;
1384  roots_ = 0;
1385  objects_ = 0;
1386  reference_decoder_ = NULL;
1387#ifdef DEBUG
1388  expect_debug_information_ = false;
1389#endif
1390}
1391
1392
1393Deserializer::~Deserializer() {
1394  if (reference_decoder_) delete reference_decoder_;
1395}
1396
1397
1398void Deserializer::ExpectEncodedAddress(Address expected) {
1399  Address a = GetEncodedAddress();
1400  USE(a);
1401  ASSERT(a == expected);
1402}
1403
1404
1405#ifdef DEBUG
1406void Deserializer::Synchronize(const char* tag) {
1407  if (expect_debug_information_) {
1408    char buf[kMaxTagLength];
1409    reader_.ExpectC('S');
1410    int length = reader_.GetInt();
1411    ASSERT(length <= kMaxTagLength);
1412    reader_.GetBytes(reinterpret_cast<Address>(buf), length);
1413    ASSERT_EQ(strlen(tag), length);
1414    ASSERT(strncmp(tag, buf, length) == 0);
1415  }
1416}
1417#endif
1418
1419
1420void Deserializer::Deserialize() {
1421  // No active threads.
1422  ASSERT_EQ(NULL, ThreadState::FirstInUse());
1423  // No active handles.
1424  ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
1425  reference_decoder_ = new ExternalReferenceDecoder();
1426  // By setting linear allocation only, we forbid the use of free list
1427  // allocation which is not predicted by SimulatedAddress.
1428  GetHeader();
1429  Heap::IterateRoots(this);
1430  GetContextStack();
1431}
1432
1433
1434void Deserializer::VisitPointers(Object** start, Object** end) {
1435  bool root = root_;
1436  root_ = false;
1437  for (Object** p = start; p < end; ++p) {
1438    if (root) {
1439      roots_++;
1440      // Read the next object or pointer from the stream
1441      // pointer in the stream.
1442      int c = reader_.GetC();
1443      if (c == '[') {
1444        *p = GetObject();  // embedded object
1445      } else {
1446        ASSERT(c == 'P');  // pointer to previously serialized object
1447        *p = Resolve(reader_.GetAddress());
1448      }
1449    } else {
1450      // A pointer internal to a HeapObject that we've already
1451      // read: resolve it to a true address (or Smi)
1452      *p = Resolve(reinterpret_cast<Address>(*p));
1453    }
1454  }
1455  root_ = root;
1456}
1457
1458
1459void Deserializer::VisitCodeTarget(RelocInfo* rinfo) {
1460  ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
1461  // On all platforms, the encoded code object address is only 32 bits.
1462  Address encoded_address = reinterpret_cast<Address>(Memory::uint32_at(
1463      reinterpret_cast<Address>(rinfo->target_object_address())));
1464  Code* target_object = reinterpret_cast<Code*>(Resolve(encoded_address));
1465  rinfo->set_target_address(target_object->instruction_start());
1466}
1467
1468
1469void Deserializer::VisitExternalReferences(Address* start, Address* end) {
1470  for (Address* p = start; p < end; ++p) {
1471    uint32_t code = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(*p));
1472    *p = reference_decoder_->Decode(code);
1473  }
1474}
1475
1476
1477void Deserializer::VisitRuntimeEntry(RelocInfo* rinfo) {
1478  uint32_t* pc = reinterpret_cast<uint32_t*>(rinfo->target_address_address());
1479  uint32_t encoding = *pc;
1480  Address target = reference_decoder_->Decode(encoding);
1481  rinfo->set_target_address(target);
1482}
1483
1484
1485void Deserializer::GetFlags() {
1486  reader_.ExpectC('F');
1487  int argc = reader_.GetInt() + 1;
1488  char** argv = NewArray<char*>(argc);
1489  reader_.ExpectC('[');
1490  for (int i = 1; i < argc; i++) {
1491    if (i > 1) reader_.ExpectC('|');
1492    argv[i] = reader_.GetString();
1493  }
1494  reader_.ExpectC(']');
1495  has_log_ = false;
1496  for (int i = 1; i < argc; i++) {
1497    if (strcmp("--log_code", argv[i]) == 0) {
1498      has_log_ = true;
1499    } else if (strcmp("--nouse_ic", argv[i]) == 0) {
1500      FLAG_use_ic = false;
1501    } else if (strcmp("--debug_code", argv[i]) == 0) {
1502      FLAG_debug_code = true;
1503    } else if (strcmp("--nolazy", argv[i]) == 0) {
1504      FLAG_lazy = false;
1505    }
1506    DeleteArray(argv[i]);
1507  }
1508
1509  DeleteArray(argv);
1510}
1511
1512
1513void Deserializer::GetLog() {
1514  if (has_log_) {
1515    reader_.ExpectC('L');
1516    char* snapshot_log = reader_.GetString();
1517#ifdef ENABLE_LOGGING_AND_PROFILING
1518    if (FLAG_log_code) {
1519      LOG(Preamble(snapshot_log));
1520    }
1521#endif
1522    DeleteArray(snapshot_log);
1523  }
1524}
1525
1526
1527static void InitPagedSpace(PagedSpace* space,
1528                           int capacity,
1529                           List<Page*>* page_list) {
1530  if (!space->EnsureCapacity(capacity)) {
1531    V8::FatalProcessOutOfMemory("InitPagedSpace");
1532  }
1533  PageIterator it(space, PageIterator::ALL_PAGES);
1534  while (it.has_next()) page_list->Add(it.next());
1535}
1536
1537
1538void Deserializer::GetHeader() {
1539  reader_.ExpectC('D');
1540#ifdef DEBUG
1541  expect_debug_information_ = reader_.GetC() == '1';
1542#else
1543  // In release mode, don't attempt to read a snapshot containing
1544  // synchronization tags.
1545  if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags.");
1546#endif
1547#ifdef V8_NATIVE_REGEXP
1548  reader_.ExpectC('N');
1549#else  // Interpreted regexp.
1550  reader_.ExpectC('I');
1551#endif
1552  // Ensure sufficient capacity in paged memory spaces to avoid growth
1553  // during deserialization.
1554  reader_.ExpectC('S');
1555  reader_.ExpectC('[');
1556  InitPagedSpace(Heap::old_pointer_space(),
1557                 reader_.GetInt(),
1558                 &old_pointer_pages_);
1559  reader_.ExpectC('|');
1560  InitPagedSpace(Heap::old_data_space(), reader_.GetInt(), &old_data_pages_);
1561  reader_.ExpectC('|');
1562  InitPagedSpace(Heap::code_space(), reader_.GetInt(), &code_pages_);
1563  reader_.ExpectC('|');
1564  InitPagedSpace(Heap::map_space(), reader_.GetInt(), &map_pages_);
1565  reader_.ExpectC('|');
1566  InitPagedSpace(Heap::cell_space(), reader_.GetInt(), &cell_pages_);
1567  reader_.ExpectC(']');
1568  // Create placeholders for global handles later to be fill during
1569  // IterateRoots.
1570  reader_.ExpectC('G');
1571  reader_.ExpectC('[');
1572  int c = reader_.GetC();
1573  while (c != ']') {
1574    ASSERT(c == 'N');
1575    global_handles_.Add(GlobalHandles::Create(NULL).location());
1576    c = reader_.GetC();
1577  }
1578}
1579
1580
1581void Deserializer::GetGlobalHandleStack(List<Handle<Object> >* stack) {
1582  reader_.ExpectC('[');
1583  int length = reader_.GetInt();
1584  for (int i = 0; i < length; i++) {
1585    reader_.ExpectC('|');
1586    int gh_index = reader_.GetInt();
1587    stack->Add(global_handles_[gh_index]);
1588  }
1589  reader_.ExpectC(']');
1590}
1591
1592
1593void Deserializer::GetContextStack() {
1594  reader_.ExpectC('C');
1595  CHECK_EQ(reader_.GetC(), '[');
1596  int count = reader_.GetInt();
1597  List<Context*> entered_contexts(count);
1598  if (count > 0) {
1599    Object** start = reinterpret_cast<Object**>(&entered_contexts.first());
1600    VisitPointers(start, start + count);
1601  }
1602  reader_.ExpectC(']');
1603  for (int i = 0; i < count; i++) {
1604    HandleScopeImplementer::instance()->SaveContext(entered_contexts[i]);
1605  }
1606}
1607
1608
1609Address Deserializer::GetEncodedAddress() {
1610  reader_.ExpectC('P');
1611  return reader_.GetAddress();
1612}
1613
1614
1615Object* Deserializer::GetObject() {
1616  // Read the prologue: type, size and encoded address.
1617  InstanceType type = static_cast<InstanceType>(reader_.GetInt());
1618  int size = reader_.GetInt() << kObjectAlignmentBits;
1619  Address a = GetEncodedAddress();
1620
1621  // Get a raw object of the right size in the right space.
1622  AllocationSpace space = GetSpace(a);
1623  Object* o;
1624  if (IsLargeExecutableObject(a)) {
1625    o = Heap::lo_space()->AllocateRawCode(size);
1626  } else if (IsLargeFixedArray(a)) {
1627    o = Heap::lo_space()->AllocateRawFixedArray(size);
1628  } else {
1629    AllocationSpace retry_space = (space == NEW_SPACE)
1630        ? Heap::TargetSpaceId(type)
1631        : space;
1632    o = Heap::AllocateRaw(size, space, retry_space);
1633  }
1634  ASSERT(!o->IsFailure());
1635  // Check that the simulation of heap allocation was correct.
1636  ASSERT(o == Resolve(a));
1637
1638  // Read any recursively embedded objects.
1639  int c = reader_.GetC();
1640  while (c == '[') {
1641    GetObject();
1642    c = reader_.GetC();
1643  }
1644  ASSERT(c == '|');
1645
1646  HeapObject* obj = reinterpret_cast<HeapObject*>(o);
1647  // Read the uninterpreted contents of the object after the map
1648  reader_.GetBytes(obj->address(), size);
1649#ifdef DEBUG
1650  if (expect_debug_information_) {
1651    // Read in the epilogue to check that we're still synchronized
1652    ExpectEncodedAddress(a);
1653    reader_.ExpectC(']');
1654  }
1655#endif
1656
1657  // Resolve the encoded pointers we just read in.
1658  // Same as obj->Iterate(this), but doesn't rely on the map pointer being set.
1659  VisitPointer(reinterpret_cast<Object**>(obj->address()));
1660  obj->IterateBody(type, size, this);
1661
1662  if (type == CODE_TYPE) {
1663    LOG(CodeMoveEvent(a, obj->address()));
1664  }
1665  objects_++;
1666  return o;
1667}
1668
1669
1670static inline Object* ResolvePaged(int page_index,
1671                                   int page_offset,
1672                                   PagedSpace* space,
1673                                   List<Page*>* page_list) {
1674  ASSERT(page_index < page_list->length());
1675  Address address = (*page_list)[page_index]->OffsetToAddress(page_offset);
1676  return HeapObject::FromAddress(address);
1677}
1678
1679
1680template<typename T>
1681void ConcatReversed(List<T>* target, const List<T>& source) {
1682  for (int i = source.length() - 1; i >= 0; i--) {
1683    target->Add(source[i]);
1684  }
1685}
1686
1687
1688Object* Deserializer::Resolve(Address encoded) {
1689  Object* o = reinterpret_cast<Object*>(encoded);
1690  if (o->IsSmi()) return o;
1691
1692  // Encoded addresses of HeapObjects always have 'HeapObject' tags.
1693  ASSERT(o->IsHeapObject());
1694  switch (GetSpace(encoded)) {
1695    // For Map space and Old space, we cache the known Pages in map_pages,
1696    // old_pointer_pages and old_data_pages. Even though MapSpace keeps a list
1697    // of page addresses, we don't rely on it since GetObject uses AllocateRaw,
1698    // and that appears not to update the page list.
1699    case MAP_SPACE:
1700      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1701                          Heap::map_space(), &map_pages_);
1702    case CELL_SPACE:
1703      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1704                          Heap::cell_space(), &cell_pages_);
1705    case OLD_POINTER_SPACE:
1706      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1707                          Heap::old_pointer_space(), &old_pointer_pages_);
1708    case OLD_DATA_SPACE:
1709      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1710                          Heap::old_data_space(), &old_data_pages_);
1711    case CODE_SPACE:
1712      return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1713                          Heap::code_space(), &code_pages_);
1714    case NEW_SPACE:
1715      return HeapObject::FromAddress(Heap::NewSpaceStart() +
1716                                     NewSpaceOffset(encoded));
1717    case LO_SPACE:
1718      // Cache the known large_objects, allocated one per 'page'
1719      int index = LargeObjectIndex(encoded);
1720      if (index >= large_objects_.length()) {
1721        int new_object_count =
1722          Heap::lo_space()->PageCount() - large_objects_.length();
1723        List<Object*> new_objects(new_object_count);
1724        LargeObjectIterator it(Heap::lo_space());
1725        for (int i = 0; i < new_object_count; i++) {
1726          new_objects.Add(it.next());
1727        }
1728#ifdef DEBUG
1729        for (int i = large_objects_.length() - 1; i >= 0; i--) {
1730          ASSERT(it.next() == large_objects_[i]);
1731        }
1732#endif
1733        ConcatReversed(&large_objects_, new_objects);
1734        ASSERT(index < large_objects_.length());
1735      }
1736      return large_objects_[index];  // s.page_offset() is ignored.
1737  }
1738  UNREACHABLE();
1739  return NULL;
1740}
1741
1742
1743} }  // namespace v8::internal
1744