blob: 359d627262703be997ec712009aca0fe696f98ba [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#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
42namespace v8 { namespace internal {
43
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044// Encoding: a RelativeAddress must be able to fit in a pointer:
45// it is encoded as an Address with (from MS to LS bits):
46// 27 bits identifying a word in the space, in one of three formats:
47// - MAP and OLD spaces: 16 bits of page number, 11 bits of word offset in page
48// - NEW space: 27 bits of word offset
49// - LO space: 27 bits of page number
ager@chromium.org9258b6b2008-09-11 09:11:10 +000050// 3 bits to encode the AllocationSpace (special values for code in LO space)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051// 2 bits identifying this as a HeapObject
52
53const int kSpaceShift = kHeapObjectTagSize;
54const int kSpaceBits = kSpaceTagSize;
55const int kSpaceMask = kSpaceTagMask;
56
ager@chromium.org9258b6b2008-09-11 09:11:10 +000057// These value are used instead of space numbers when serializing/
58// deserializing. They indicate an object that is in large object space, but
59// should be treated specially.
60// Make the pages executable on platforms that support it:
61const int kLOSpaceExecutable = LAST_SPACE + 1;
62// Reserve space for write barrier bits (for objects that can contain
63// references to new space):
64const int kLOSpacePointer = LAST_SPACE + 2;
65
66
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067const int kOffsetShift = kSpaceShift + kSpaceBits;
68const int kOffsetBits = 11;
69const int kOffsetMask = (1 << kOffsetBits) - 1;
70
71const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);
72const int kPageShift = kOffsetShift + kOffsetBits;
73const int kPageMask = (1 << kPageBits) - 1;
74
75const int kPageAndOffsetShift = kOffsetShift;
76const int kPageAndOffsetBits = kPageBits + kOffsetBits;
77const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1;
78
79
ager@chromium.org9258b6b2008-09-11 09:11:10 +000080static inline AllocationSpace GetSpace(Address addr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081 const int encoded = reinterpret_cast<int>(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000082 int space_number = ((encoded >> kSpaceShift) & kSpaceMask);
83 if (space_number == kLOSpaceExecutable) space_number = LO_SPACE;
84 else if (space_number == kLOSpacePointer) space_number = LO_SPACE;
85 return static_cast<AllocationSpace>(space_number);
86}
87
88
89static inline bool IsLargeExecutableObject(Address addr) {
90 const int encoded = reinterpret_cast<int>(addr);
91 const int space_number = ((encoded >> kSpaceShift) & kSpaceMask);
92 if (space_number == kLOSpaceExecutable) return true;
93 return false;
94}
95
96
97static inline bool IsLargeFixedArray(Address addr) {
98 const int encoded = reinterpret_cast<int>(addr);
99 const int space_number = ((encoded >> kSpaceShift) & kSpaceMask);
100 if (space_number == kLOSpacePointer) return true;
101 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102}
103
104
105static inline int PageIndex(Address addr) {
106 const int encoded = reinterpret_cast<int>(addr);
107 return (encoded >> kPageShift) & kPageMask;
108}
109
110
111static inline int PageOffset(Address addr) {
112 const int encoded = reinterpret_cast<int>(addr);
113 return ((encoded >> kOffsetShift) & kOffsetMask) << kObjectAlignmentBits;
114}
115
116
117static inline int NewSpaceOffset(Address addr) {
118 const int encoded = reinterpret_cast<int>(addr);
119 return ((encoded >> kPageAndOffsetShift) & kPageAndOffsetMask) <<
120 kObjectAlignmentBits;
121}
122
123
124static inline int LargeObjectIndex(Address addr) {
125 const int encoded = reinterpret_cast<int>(addr);
126 return (encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;
127}
128
129
130// A RelativeAddress encodes a heap address that is independent of
131// the actual memory addresses in real heap. The general case (for the
132// OLD, CODE and MAP spaces) is as a (space id, page number, page offset)
133// triple. The NEW space has page number == 0, because there are no
134// pages. The LARGE_OBJECT space has page offset = 0, since there is
135// exactly one object per page. RelativeAddresses are encodable as
136// Addresses, so that they can replace the map() pointers of
137// HeapObjects. The encoded Addresses are also encoded as HeapObjects
138// and allow for marking (is_marked() see mark(), clear_mark()...) as
139// used by the Mark-Compact collector.
140
141class RelativeAddress {
142 public:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000143 RelativeAddress(AllocationSpace space,
144 int page_index,
145 int page_offset)
146 : space_(space), page_index_(page_index), page_offset_(page_offset) {
147 ASSERT(space <= LAST_SPACE && space >= 0);
148 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149
150 // Return the encoding of 'this' as an Address. Decode with constructor.
151 Address Encode() const;
152
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000153 AllocationSpace space() const {
154 if (space_ == kLOSpaceExecutable) return LO_SPACE;
155 if (space_ == kLOSpacePointer) return LO_SPACE;
156 return static_cast<AllocationSpace>(space_);
157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 int page_index() const { return page_index_; }
159 int page_offset() const { return page_offset_; }
160
161 bool in_paged_space() const {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000162 return space_ == CODE_SPACE ||
163 space_ == OLD_POINTER_SPACE ||
164 space_ == OLD_DATA_SPACE ||
165 space_ == MAP_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 }
167
168 void next_address(int offset) { page_offset_ += offset; }
169 void next_page(int init_offset = 0) {
170 page_index_++;
171 page_offset_ = init_offset;
172 }
173
174#ifdef DEBUG
175 void Verify();
176#endif
177
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000178 void set_to_large_code_object() {
179 ASSERT(space_ == LO_SPACE);
180 space_ = kLOSpaceExecutable;
181 }
182 void set_to_large_fixed_array() {
183 ASSERT(space_ == LO_SPACE);
184 space_ = kLOSpacePointer;
185 }
186
187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188 private:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000189 int space_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190 int page_index_;
191 int page_offset_;
192};
193
194
195Address RelativeAddress::Encode() const {
196 ASSERT(page_index_ >= 0);
197 int word_offset = 0;
198 int result = 0;
199 switch (space_) {
200 case MAP_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000201 case OLD_POINTER_SPACE:
202 case OLD_DATA_SPACE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 case CODE_SPACE:
204 ASSERT_EQ(0, page_index_ & ~kPageMask);
205 word_offset = page_offset_ >> kObjectAlignmentBits;
206 ASSERT_EQ(0, word_offset & ~kOffsetMask);
207 result = (page_index_ << kPageShift) | (word_offset << kOffsetShift);
208 break;
209 case NEW_SPACE:
210 ASSERT_EQ(0, page_index_);
211 word_offset = page_offset_ >> kObjectAlignmentBits;
212 ASSERT_EQ(0, word_offset & ~kPageAndOffsetMask);
213 result = word_offset << kPageAndOffsetShift;
214 break;
215 case LO_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000216 case kLOSpaceExecutable:
217 case kLOSpacePointer:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 ASSERT_EQ(0, page_offset_);
219 ASSERT_EQ(0, page_index_ & ~kPageAndOffsetMask);
220 result = page_index_ << kPageAndOffsetShift;
221 break;
222 }
223 // OR in AllocationSpace and kHeapObjectTag
224 ASSERT_EQ(0, space_ & ~kSpaceMask);
225 result |= (space_ << kSpaceShift) | kHeapObjectTag;
226 return reinterpret_cast<Address>(result);
227}
228
229
230#ifdef DEBUG
231void RelativeAddress::Verify() {
232 ASSERT(page_offset_ >= 0 && page_index_ >= 0);
233 switch (space_) {
234 case MAP_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000235 case OLD_POINTER_SPACE:
236 case OLD_DATA_SPACE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 case CODE_SPACE:
238 ASSERT(Page::kObjectStartOffset <= page_offset_ &&
239 page_offset_ <= Page::kPageSize);
240 break;
241 case NEW_SPACE:
242 ASSERT(page_index_ == 0);
243 break;
244 case LO_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000245 case kLOSpaceExecutable:
246 case kLOSpacePointer:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 ASSERT(page_offset_ == 0);
248 break;
249 }
250}
251#endif
252
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000253enum GCTreatment {
254 DataObject, // Object that cannot contain a reference to new space.
255 PointerObject, // Object that can contain a reference to new space.
256 CodeObject // Object that contains executable code.
257};
258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000259// A SimulatedHeapSpace simulates the allocation of objects in a page in
260// the heap. It uses linear allocation - that is, it doesn't simulate the
261// use of a free list. This simulated
262// allocation must exactly match that done by Heap.
263
264class SimulatedHeapSpace {
265 public:
266 // The default constructor initializes to an invalid state.
267 SimulatedHeapSpace(): current_(LAST_SPACE, -1, -1) {}
268
269 // Sets 'this' to the first address in 'space' that would be
270 // returned by allocation in an empty heap.
271 void InitEmptyHeap(AllocationSpace space);
272
273 // Sets 'this' to the next address in 'space' that would be returned
274 // by allocation in the current heap. Intended only for testing
275 // serialization and deserialization in the current address space.
276 void InitCurrentHeap(AllocationSpace space);
277
278 // Returns the RelativeAddress where the next
279 // object of 'size' bytes will be allocated, and updates 'this' to
280 // point to the next free address beyond that object.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000281 RelativeAddress Allocate(int size, GCTreatment special_gc_treatment);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282
283 private:
284 RelativeAddress current_;
285};
286
287
288void SimulatedHeapSpace::InitEmptyHeap(AllocationSpace space) {
289 switch (space) {
290 case MAP_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000291 case OLD_POINTER_SPACE:
292 case OLD_DATA_SPACE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293 case CODE_SPACE:
294 current_ = RelativeAddress(space, 0, Page::kObjectStartOffset);
295 break;
296 case NEW_SPACE:
297 case LO_SPACE:
298 current_ = RelativeAddress(space, 0, 0);
299 break;
300 }
301}
302
303
304void SimulatedHeapSpace::InitCurrentHeap(AllocationSpace space) {
305 switch (space) {
306 case MAP_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000307 case OLD_POINTER_SPACE:
308 case OLD_DATA_SPACE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309 case CODE_SPACE: {
310 PagedSpace* ps;
311 if (space == MAP_SPACE) {
312 ps = Heap::map_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000313 } else if (space == OLD_POINTER_SPACE) {
314 ps = Heap::old_pointer_space();
315 } else if (space == OLD_DATA_SPACE) {
316 ps = Heap::old_data_space();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 } else {
318 ASSERT(space == CODE_SPACE);
319 ps = Heap::code_space();
320 }
321 Address top = ps->top();
322 Page* top_page = Page::FromAllocationTop(top);
323 int page_index = 0;
324 PageIterator it(ps, PageIterator::PAGES_IN_USE);
325 while (it.has_next()) {
326 if (it.next() == top_page) break;
327 page_index++;
328 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000329 current_ = RelativeAddress(space,
330 page_index,
331 top_page->Offset(top));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 break;
333 }
334 case NEW_SPACE:
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000335 current_ = RelativeAddress(space,
336 0,
337 Heap::NewSpaceTop() - Heap::NewSpaceStart());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 break;
339 case LO_SPACE:
340 int page_index = 0;
341 for (LargeObjectIterator it(Heap::lo_space()); it.has_next(); it.next()) {
342 page_index++;
343 }
344 current_ = RelativeAddress(space, page_index, 0);
345 break;
346 }
347}
348
349
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000350RelativeAddress SimulatedHeapSpace::Allocate(int size,
351 GCTreatment special_gc_treatment) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352#ifdef DEBUG
353 current_.Verify();
354#endif
355 int alloc_size = OBJECT_SIZE_ALIGN(size);
356 if (current_.in_paged_space() &&
357 current_.page_offset() + alloc_size > Page::kPageSize) {
358 ASSERT(alloc_size <= Page::kMaxHeapObjectSize);
359 current_.next_page(Page::kObjectStartOffset);
360 }
361 RelativeAddress result = current_;
362 if (current_.space() == LO_SPACE) {
363 current_.next_page();
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000364 if (special_gc_treatment == CodeObject) {
365 result.set_to_large_code_object();
366 } else if (special_gc_treatment == PointerObject) {
367 result.set_to_large_fixed_array();
368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 } else {
370 current_.next_address(alloc_size);
371 }
372#ifdef DEBUG
373 current_.Verify();
374 result.Verify();
375#endif
376 return result;
377}
378
379// -----------------------------------------------------------------------------
380// Coding of external references.
381
382// The encoding of an external reference. The type is in the high word.
383// The id is in the low word.
384static uint32_t EncodeExternal(TypeCode type, uint16_t id) {
385 return static_cast<uint32_t>(type) << 16 | id;
386}
387
388
389static int* GetInternalPointer(StatsCounter* counter) {
390 // All counters refer to dummy_counter, if deserializing happens without
391 // setting up counters.
392 static int dummy_counter = 0;
393 return counter->Enabled() ? counter->GetInternalPointer() : &dummy_counter;
394}
395
396
397// ExternalReferenceTable is a helper class that defines the relationship
398// between external references and their encodings. It is used to build
399// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
400class ExternalReferenceTable {
401 public:
402 static ExternalReferenceTable* instance() {
403 if (!instance_) instance_ = new ExternalReferenceTable();
404 return instance_;
405 }
406
407 int size() const { return refs_.length(); }
408
409 Address address(int i) { return refs_[i].address; }
410
411 uint32_t code(int i) { return refs_[i].code; }
412
413 const char* name(int i) { return refs_[i].name; }
414
415 int max_id(int code) { return max_id_[code]; }
416
417 private:
418 static ExternalReferenceTable* instance_;
419
420 ExternalReferenceTable();
421
422 struct ExternalReferenceEntry {
423 Address address;
424 uint32_t code;
425 const char* name;
426 };
427
428 void Add(Address address, TypeCode type, uint16_t id, const char* name) {
429 CHECK_NE(NULL, address);
430 ExternalReferenceEntry entry;
431 entry.address = address;
432 entry.code = EncodeExternal(type, id);
433 entry.name = name;
434 CHECK_NE(0, entry.code);
435 refs_.Add(entry);
436 if (id > max_id_[type]) max_id_[type] = id;
437 }
438
439 List<ExternalReferenceEntry> refs_;
440 int max_id_[kTypeCodeCount];
441};
442
443
444ExternalReferenceTable* ExternalReferenceTable::instance_ = NULL;
445
446
447ExternalReferenceTable::ExternalReferenceTable() : refs_(64) {
448 for (int type_code = 0; type_code < kTypeCodeCount; type_code++) {
449 max_id_[type_code] = 0;
450 }
451
452 // Define all entries in the table.
453
454 // Builtins
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000455#define DEF_ENTRY_C(name) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 Add(Builtins::c_function_address(Builtins::c_##name), \
457 C_BUILTIN, \
458 Builtins::c_##name, \
459 "Builtins::" #name);
460
461 BUILTIN_LIST_C(DEF_ENTRY_C)
462#undef DEF_ENTRY_C
463
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000464#define DEF_ENTRY_C(name) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000465 Add(Builtins::builtin_address(Builtins::name), \
466 BUILTIN, \
467 Builtins::name, \
468 "Builtins::" #name);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000469#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
471 BUILTIN_LIST_C(DEF_ENTRY_C)
472 BUILTIN_LIST_A(DEF_ENTRY_A)
473#undef DEF_ENTRY_C
474#undef DEF_ENTRY_A
475
476 // Runtime functions
477#define RUNTIME_ENTRY(name, nargs) \
478 Add(Runtime::FunctionForId(Runtime::k##name)->entry, \
479 RUNTIME_FUNCTION, \
480 Runtime::k##name, \
481 "Runtime::" #name);
482
483 RUNTIME_FUNCTION_LIST(RUNTIME_ENTRY)
484#undef RUNTIME_ENTRY
485
486 // IC utilities
487#define IC_ENTRY(name) \
488 Add(IC::AddressFromUtilityId(IC::k##name), \
489 IC_UTILITY, \
490 IC::k##name, \
491 "IC::" #name);
492
493 IC_UTIL_LIST(IC_ENTRY)
494#undef IC_ENTRY
495
496 // Debug addresses
497 Add(Debug_Address(Debug::k_after_break_target_address).address(),
498 DEBUG_ADDRESS,
499 Debug::k_after_break_target_address << kDebugIdShift,
500 "Debug::after_break_target_address()");
501 Add(Debug_Address(Debug::k_debug_break_return_address).address(),
502 DEBUG_ADDRESS,
503 Debug::k_debug_break_return_address << kDebugIdShift,
504 "Debug::debug_break_return_address()");
505 const char* debug_register_format = "Debug::register_address(%i)";
506 size_t dr_format_length = strlen(debug_register_format);
507 for (int i = 0; i < kNumJSCallerSaved; ++i) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000508 Vector<char> name = Vector<char>::New(dr_format_length + 1);
509 OS::SNPrintF(name, debug_register_format, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 Add(Debug_Address(Debug::k_register_address, i).address(),
511 DEBUG_ADDRESS,
512 Debug::k_register_address << kDebugIdShift | i,
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000513 name.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514 }
515
516 // Stat counters
517#define COUNTER_ENTRY(name, caption) \
518 Add(reinterpret_cast<Address>(GetInternalPointer(&Counters::name)), \
519 STATS_COUNTER, \
520 Counters::k_##name, \
521 "Counters::" #name);
522
523 STATS_COUNTER_LIST_1(COUNTER_ENTRY)
524 STATS_COUNTER_LIST_2(COUNTER_ENTRY)
525#undef COUNTER_ENTRY
526
527 // Top addresses
528 const char* top_address_format = "Top::get_address_from_id(%i)";
529 size_t top_format_length = strlen(top_address_format);
530 for (uint16_t i = 0; i < Top::k_top_address_count; ++i) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000531 Vector<char> name = Vector<char>::New(top_format_length + 1);
532 const char* chars = name.start();
533 OS::SNPrintF(name, top_address_format, i);
534 Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535 }
536
537 // Extensions
538 Add(FUNCTION_ADDR(GCExtension::GC), EXTENSION, 1,
539 "GCExtension::GC");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540
541 // Accessors
542#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
543 Add((Address)&Accessors::name, \
544 ACCESSOR, \
545 Accessors::k##name, \
546 "Accessors::" #name);
547
548 ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
549#undef ACCESSOR_DESCRIPTOR_DECLARATION
550
551 // Stub cache tables
552 Add(SCTableReference::keyReference(StubCache::kPrimary).address(),
553 STUB_CACHE_TABLE,
554 1,
555 "StubCache::primary_->key");
556 Add(SCTableReference::valueReference(StubCache::kPrimary).address(),
557 STUB_CACHE_TABLE,
558 2,
559 "StubCache::primary_->value");
560 Add(SCTableReference::keyReference(StubCache::kSecondary).address(),
561 STUB_CACHE_TABLE,
562 3,
563 "StubCache::secondary_->key");
564 Add(SCTableReference::valueReference(StubCache::kSecondary).address(),
565 STUB_CACHE_TABLE,
566 4,
567 "StubCache::secondary_->value");
568
569 // Runtime entries
570 Add(FUNCTION_ADDR(Runtime::PerformGC),
571 RUNTIME_ENTRY,
572 1,
573 "Runtime::PerformGC");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574
575 // Miscellaneous
576 Add(ExternalReference::builtin_passed_function().address(),
577 UNCLASSIFIED,
578 1,
579 "Builtins::builtin_passed_function");
580 Add(ExternalReference::the_hole_value_location().address(),
581 UNCLASSIFIED,
582 2,
583 "Factory::the_hole_value().location()");
584 Add(ExternalReference::address_of_stack_guard_limit().address(),
585 UNCLASSIFIED,
586 3,
587 "StackGuard::address_of_limit()");
588 Add(ExternalReference::debug_break().address(),
589 UNCLASSIFIED,
590 4,
591 "Debug::Break()");
592 Add(ExternalReference::new_space_start().address(),
593 UNCLASSIFIED,
594 5,
595 "Heap::NewSpaceStart()");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000596 Add(ExternalReference::heap_always_allocate_scope_depth().address(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597 UNCLASSIFIED,
598 6,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000599 "Heap::always_allocate_scope_depth()");
600 Add(ExternalReference::new_space_allocation_limit_address().address(),
601 UNCLASSIFIED,
602 7,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603 "Heap::NewSpaceAllocationLimitAddress()");
604 Add(ExternalReference::new_space_allocation_top_address().address(),
605 UNCLASSIFIED,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000606 8,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 "Heap::NewSpaceAllocationTopAddress()");
608 Add(ExternalReference::debug_step_in_fp_address().address(),
609 UNCLASSIFIED,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000610 9,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 "Debug::step_in_fp_addr()");
612}
613
614
615ExternalReferenceEncoder::ExternalReferenceEncoder()
616 : encodings_(Match) {
617 ExternalReferenceTable* external_references =
618 ExternalReferenceTable::instance();
619 for (int i = 0; i < external_references->size(); ++i) {
620 Put(external_references->address(i), i);
621 }
622}
623
624
625uint32_t ExternalReferenceEncoder::Encode(Address key) const {
626 int index = IndexOf(key);
627 return index >=0 ? ExternalReferenceTable::instance()->code(index) : 0;
628}
629
630
631const char* ExternalReferenceEncoder::NameOfAddress(Address key) const {
632 int index = IndexOf(key);
633 return index >=0 ? ExternalReferenceTable::instance()->name(index) : NULL;
634}
635
636
637int ExternalReferenceEncoder::IndexOf(Address key) const {
638 if (key == NULL) return -1;
639 HashMap::Entry* entry =
640 const_cast<HashMap &>(encodings_).Lookup(key, Hash(key), false);
641 return entry == NULL ? -1 : reinterpret_cast<int>(entry->value);
642}
643
644
645void ExternalReferenceEncoder::Put(Address key, int index) {
646 HashMap::Entry* entry = encodings_.Lookup(key, Hash(key), true);
647 entry->value = reinterpret_cast<void *>(index);
648}
649
650
651ExternalReferenceDecoder::ExternalReferenceDecoder()
652 : encodings_(NewArray<Address*>(kTypeCodeCount)) {
653 ExternalReferenceTable* external_references =
654 ExternalReferenceTable::instance();
655 for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
656 int max = external_references->max_id(type) + 1;
657 encodings_[type] = NewArray<Address>(max + 1);
658 }
659 for (int i = 0; i < external_references->size(); ++i) {
660 Put(external_references->code(i), external_references->address(i));
661 }
662}
663
664
665ExternalReferenceDecoder::~ExternalReferenceDecoder() {
666 for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
667 DeleteArray(encodings_[type]);
668 }
669 DeleteArray(encodings_);
670}
671
672
673//------------------------------------------------------------------------------
674// Implementation of Serializer
675
676
677// Helper class to write the bytes of the serialized heap.
678
679class SnapshotWriter {
680 public:
681 SnapshotWriter() {
682 len_ = 0;
683 max_ = 8 << 10; // 8K initial size
684 str_ = NewArray<char>(max_);
685 }
686
687 ~SnapshotWriter() {
688 DeleteArray(str_);
689 }
690
691 void GetString(char** str, int* len) {
692 *str = NewArray<char>(len_);
693 memcpy(*str, str_, len_);
694 *len = len_;
695 }
696
697 void Reserve(int bytes, int pos);
698
699 void PutC(char c) {
700 InsertC(c, len_);
701 }
702
703 void PutInt(int i) {
704 InsertInt(i, len_);
705 }
706
707 void PutBytes(const byte* a, int size) {
708 InsertBytes(a, len_, size);
709 }
710
711 void PutString(const char* s) {
712 InsertString(s, len_);
713 }
714
715 int InsertC(char c, int pos) {
716 Reserve(1, pos);
717 str_[pos] = c;
718 len_++;
719 return pos + 1;
720 }
721
722 int InsertInt(int i, int pos) {
723 return InsertBytes(reinterpret_cast<byte*>(&i), pos, sizeof(i));
724 }
725
726 int InsertBytes(const byte* a, int pos, int size) {
727 Reserve(size, pos);
728 memcpy(&str_[pos], a, size);
729 len_ += size;
730 return pos + size;
731 }
732
733 int InsertString(const char* s, int pos);
734
735 int length() { return len_; }
736
kasper.lund7276f142008-07-30 08:49:36 +0000737 Address position() { return reinterpret_cast<Address>(&str_[len_]); }
738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739 private:
740 char* str_; // the snapshot
741 int len_; // the curent length of str_
742 int max_; // the allocated size of str_
743};
744
745
746void SnapshotWriter::Reserve(int bytes, int pos) {
747 CHECK(0 <= pos && pos <= len_);
748 while (len_ + bytes >= max_) {
749 max_ *= 2;
750 char* old = str_;
751 str_ = NewArray<char>(max_);
752 memcpy(str_, old, len_);
753 DeleteArray(old);
754 }
755 if (pos < len_) {
756 char* old = str_;
757 str_ = NewArray<char>(max_);
758 memcpy(str_, old, pos);
759 memcpy(str_ + pos + bytes, old + pos, len_ - pos);
760 DeleteArray(old);
761 }
762}
763
764int SnapshotWriter::InsertString(const char* s, int pos) {
765 int size = strlen(s);
766 pos = InsertC('[', pos);
767 pos = InsertInt(size, pos);
768 pos = InsertC(']', pos);
769 return InsertBytes(reinterpret_cast<const byte*>(s), pos, size);
770}
771
772
kasper.lund7276f142008-07-30 08:49:36 +0000773class ReferenceUpdater: public ObjectVisitor {
774 public:
775 ReferenceUpdater(HeapObject* obj, Serializer* serializer)
776 : obj_address_(obj->address()),
777 serializer_(serializer),
778 reference_encoder_(serializer->reference_encoder_),
779 offsets_(8),
780 addresses_(8) {
781 }
782
783 virtual void VisitPointers(Object** start, Object** end) {
784 for (Object** p = start; p < end; ++p) {
785 if ((*p)->IsHeapObject()) {
786 offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
787 Address a = serializer_->GetSavedAddress(HeapObject::cast(*p));
788 addresses_.Add(a);
789 }
790 }
791 }
792
793 virtual void VisitExternalReferences(Address* start, Address* end) {
794 for (Address* p = start; p < end; ++p) {
795 uint32_t code = reference_encoder_->Encode(*p);
796 CHECK(*p == NULL ? code == 0 : code != 0);
797 offsets_.Add(reinterpret_cast<Address>(p) - obj_address_);
798 addresses_.Add(reinterpret_cast<Address>(code));
799 }
800 }
801
802 virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
803 Address target = rinfo->target_address();
804 uint32_t encoding = reference_encoder_->Encode(target);
805 CHECK(target == NULL ? encoding == 0 : encoding != 0);
806 offsets_.Add(reinterpret_cast<Address>(rinfo->pc()) - obj_address_);
807 addresses_.Add(reinterpret_cast<Address>(encoding));
808 }
809
810 void Update(Address start_address) {
811 for (int i = 0; i < offsets_.length(); i++) {
812 Address* p = reinterpret_cast<Address*>(start_address + offsets_[i]);
813 *p = addresses_[i];
814 }
815 }
816
817 private:
818 Address obj_address_;
819 Serializer* serializer_;
820 ExternalReferenceEncoder* reference_encoder_;
821 List<int> offsets_;
822 List<Address> addresses_;
823};
824
825
826// Helper functions for a map of encoded heap object addresses.
827static uint32_t HeapObjectHash(HeapObject* key) {
828 return reinterpret_cast<uint32_t>(key) >> 2;
829}
830
831
832static bool MatchHeapObject(void* key1, void* key2) {
833 return key1 == key2;
834}
835
836
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837Serializer::Serializer()
kasper.lund7276f142008-07-30 08:49:36 +0000838 : global_handles_(4),
839 saved_addresses_(MatchHeapObject) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 root_ = true;
841 roots_ = 0;
842 objects_ = 0;
843 reference_encoder_ = NULL;
844 writer_ = new SnapshotWriter();
845 for (int i = 0; i <= LAST_SPACE; i++) {
846 allocator_[i] = new SimulatedHeapSpace();
847 }
848}
849
850
851Serializer::~Serializer() {
852 for (int i = 0; i <= LAST_SPACE; i++) {
853 delete allocator_[i];
854 }
855 if (reference_encoder_) delete reference_encoder_;
856 delete writer_;
857}
858
859
860bool Serializer::serialization_enabled_ = true;
861
862
863#ifdef DEBUG
864static const int kMaxTagLength = 32;
865
866void Serializer::Synchronize(const char* tag) {
867 if (FLAG_debug_serialization) {
868 int length = strlen(tag);
869 ASSERT(length <= kMaxTagLength);
870 writer_->PutC('S');
871 writer_->PutInt(length);
872 writer_->PutBytes(reinterpret_cast<const byte*>(tag), length);
873 }
874}
875#endif
876
877
878void Serializer::InitializeAllocators() {
879 for (int i = 0; i <= LAST_SPACE; i++) {
880 allocator_[i]->InitEmptyHeap(static_cast<AllocationSpace>(i));
881 }
882}
883
884
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000885bool Serializer::IsVisited(HeapObject* obj) {
kasper.lund7276f142008-07-30 08:49:36 +0000886 HashMap::Entry* entry =
887 saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
888 return entry != NULL;
889}
890
891
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000892Address Serializer::GetSavedAddress(HeapObject* obj) {
kasper.lund7276f142008-07-30 08:49:36 +0000893 HashMap::Entry* entry
894 = saved_addresses_.Lookup(obj, HeapObjectHash(obj), false);
895 ASSERT(entry != NULL);
896 return reinterpret_cast<Address>(entry->value);
897}
898
899
900void Serializer::SaveAddress(HeapObject* obj, Address addr) {
901 HashMap::Entry* entry =
902 saved_addresses_.Lookup(obj, HeapObjectHash(obj), true);
903 entry->value = addr;
904}
905
906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907void Serializer::Serialize() {
908 // No active threads.
909 CHECK_EQ(NULL, ThreadState::FirstInUse());
910 // No active or weak handles.
911 CHECK(HandleScopeImplementer::instance()->Blocks()->is_empty());
912 CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
913 // We need a counter function during serialization to resolve the
914 // references to counters in the code on the heap.
915 CHECK(StatsTable::HasCounterFunction());
916 CHECK(enabled());
917 InitializeAllocators();
918 reference_encoder_ = new ExternalReferenceEncoder();
919 PutHeader();
920 Heap::IterateRoots(this);
921 PutLog();
922 PutContextStack();
923 disable();
924}
925
926
927void Serializer::Finalize(char** str, int* len) {
928 writer_->GetString(str, len);
929}
930
931
kasper.lund7276f142008-07-30 08:49:36 +0000932// Serialize objects by writing them into the stream.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933
934void Serializer::VisitPointers(Object** start, Object** end) {
935 bool root = root_;
936 root_ = false;
937 for (Object** p = start; p < end; ++p) {
938 bool serialized;
kasper.lund7276f142008-07-30 08:49:36 +0000939 Address a = Encode(*p, &serialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940 if (root) {
941 roots_++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 // If the object was not just serialized,
943 // write its encoded address instead.
944 if (!serialized) PutEncodedAddress(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000945 }
946 }
947 root_ = root;
948}
949
950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951class GlobalHandlesRetriever: public ObjectVisitor {
952 public:
953 explicit GlobalHandlesRetriever(List<Object**>* handles)
954 : global_handles_(handles) {}
955
956 virtual void VisitPointers(Object** start, Object** end) {
957 for (; start != end; ++start) {
958 global_handles_->Add(start);
959 }
960 }
961
962 private:
963 List<Object**>* global_handles_;
964};
965
966
967void Serializer::PutFlags() {
968 writer_->PutC('F');
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000969 List<const char*>* argv = FlagList::argv();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 writer_->PutInt(argv->length());
971 writer_->PutC('[');
972 for (int i = 0; i < argv->length(); i++) {
973 if (i > 0) writer_->PutC('|');
974 writer_->PutString((*argv)[i]);
975 DeleteArray((*argv)[i]);
976 }
977 writer_->PutC(']');
978 flags_end_ = writer_->length();
979 delete argv;
980}
981
982
983void Serializer::PutHeader() {
984 PutFlags();
985 writer_->PutC('D');
986#ifdef DEBUG
987 writer_->PutC(FLAG_debug_serialization ? '1' : '0');
988#else
989 writer_->PutC('0');
990#endif
kasper.lund7276f142008-07-30 08:49:36 +0000991 // Write sizes of paged memory spaces. Allocate extra space for the old
992 // and code spaces, because objects in new space will be promoted to them.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 writer_->PutC('S');
994 writer_->PutC('[');
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000995 writer_->PutInt(Heap::old_pointer_space()->Size() +
996 Heap::new_space()->Size());
997 writer_->PutC('|');
998 writer_->PutInt(Heap::old_data_space()->Size() + Heap::new_space()->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 writer_->PutC('|');
kasper.lund7276f142008-07-30 08:49:36 +00001000 writer_->PutInt(Heap::code_space()->Size() + Heap::new_space()->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 writer_->PutC('|');
1002 writer_->PutInt(Heap::map_space()->Size());
1003 writer_->PutC(']');
1004 // Write global handles.
1005 writer_->PutC('G');
1006 writer_->PutC('[');
1007 GlobalHandlesRetriever ghr(&global_handles_);
1008 GlobalHandles::IterateRoots(&ghr);
1009 for (int i = 0; i < global_handles_.length(); i++) {
1010 writer_->PutC('N');
1011 }
1012 writer_->PutC(']');
1013}
1014
1015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016void Serializer::PutLog() {
1017#ifdef ENABLE_LOGGING_AND_PROFILING
1018 if (FLAG_log_code) {
1019 Logger::TearDown();
1020 int pos = writer_->InsertC('L', flags_end_);
1021 bool exists;
1022 Vector<const char> log = ReadFile(FLAG_logfile, &exists);
1023 writer_->InsertString(log.start(), pos);
1024 log.Dispose();
1025 }
1026#endif
1027}
1028
1029
1030static int IndexOf(const List<Object**>& list, Object** element) {
1031 for (int i = 0; i < list.length(); i++) {
1032 if (list[i] == element) return i;
1033 }
1034 return -1;
1035}
1036
1037
1038void Serializer::PutGlobalHandleStack(const List<Handle<Object> >& stack) {
1039 writer_->PutC('[');
1040 writer_->PutInt(stack.length());
1041 for (int i = stack.length() - 1; i >= 0; i--) {
1042 writer_->PutC('|');
1043 int gh_index = IndexOf(global_handles_, stack[i].location());
1044 CHECK_GE(gh_index, 0);
1045 writer_->PutInt(gh_index);
1046 }
1047 writer_->PutC(']');
1048}
1049
1050
1051void Serializer::PutContextStack() {
kasper.lund44510672008-07-25 07:37:58 +00001052 List<Handle<Object> > contexts(2);
1053 while (HandleScopeImplementer::instance()->HasSavedContexts()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 Handle<Object> context =
kasper.lund44510672008-07-25 07:37:58 +00001055 HandleScopeImplementer::instance()->RestoreContext();
1056 contexts.Add(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 }
kasper.lund7276f142008-07-30 08:49:36 +00001058 for (int i = contexts.length() - 1; i >= 0; i--) {
1059 HandleScopeImplementer::instance()->SaveContext(contexts[i]);
1060 }
kasper.lund44510672008-07-25 07:37:58 +00001061 PutGlobalHandleStack(contexts);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
1065void Serializer::PutEncodedAddress(Address addr) {
1066 writer_->PutC('P');
1067 writer_->PutInt(reinterpret_cast<int>(addr));
1068}
1069
1070
1071Address Serializer::Encode(Object* o, bool* serialized) {
1072 *serialized = false;
1073 if (o->IsSmi()) {
1074 return reinterpret_cast<Address>(o);
1075 } else {
1076 HeapObject* obj = HeapObject::cast(o);
kasper.lund7276f142008-07-30 08:49:36 +00001077 if (IsVisited(obj)) {
1078 return GetSavedAddress(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079 } else {
1080 // First visit: serialize the object.
1081 *serialized = true;
1082 return PutObject(obj);
1083 }
1084 }
1085}
1086
1087
1088Address Serializer::PutObject(HeapObject* obj) {
1089 Map* map = obj->map();
1090 InstanceType type = map->instance_type();
1091 int size = obj->SizeFromMap(map);
1092
1093 // Simulate the allocation of obj to predict where it will be
1094 // allocated during deserialization.
1095 Address addr = Allocate(obj).Encode();
1096
kasper.lund7276f142008-07-30 08:49:36 +00001097 SaveAddress(obj, addr);
1098
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099 if (type == CODE_TYPE) {
1100 Code* code = Code::cast(obj);
1101 // Ensure Code objects contain Object pointers, not Addresses.
1102 code->ConvertICTargetsFromAddressToObject();
1103 LOG(CodeMoveEvent(code->address(), addr));
1104 }
1105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 // Write out the object prologue: type, size, and simulated address of obj.
1107 writer_->PutC('[');
1108 CHECK_EQ(0, size & kObjectAlignmentMask);
1109 writer_->PutInt(type);
1110 writer_->PutInt(size >> kObjectAlignmentBits);
1111 PutEncodedAddress(addr); // encodes AllocationSpace
1112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 // Visit all the pointers in the object other than the map. This
kasper.lund7276f142008-07-30 08:49:36 +00001114 // will recursively serialize any as-yet-unvisited objects.
mads.s.ager31e71382008-08-13 09:32:07 +00001115 obj->Iterate(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116
1117 // Mark end of recursively embedded objects, start of object body.
1118 writer_->PutC('|');
mads.s.ager31e71382008-08-13 09:32:07 +00001119 // Write out the raw contents of the object. No compression, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 // fast to deserialize.
mads.s.ager31e71382008-08-13 09:32:07 +00001121 writer_->PutBytes(obj->address(), size);
1122 // Update pointers and external references in the written object.
kasper.lund7276f142008-07-30 08:49:36 +00001123 ReferenceUpdater updater(obj, this);
mads.s.ager31e71382008-08-13 09:32:07 +00001124 obj->Iterate(&updater);
kasper.lund7276f142008-07-30 08:49:36 +00001125 updater.Update(writer_->position() - size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126
1127#ifdef DEBUG
1128 if (FLAG_debug_serialization) {
1129 // Write out the object epilogue to catch synchronization errors.
1130 PutEncodedAddress(addr);
1131 writer_->PutC(']');
1132 }
1133#endif
1134
kasper.lund7276f142008-07-30 08:49:36 +00001135 if (type == CODE_TYPE) {
1136 Code* code = Code::cast(obj);
1137 // Convert relocations from Object* to Address in Code objects
1138 code->ConvertICTargetsFromObjectToAddress();
1139 }
1140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 objects_++;
1142 return addr;
1143}
1144
1145
1146RelativeAddress Serializer::Allocate(HeapObject* obj) {
1147 // Find out which AllocationSpace 'obj' is in.
1148 AllocationSpace s;
1149 bool found = false;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001150 for (int i = FIRST_SPACE; !found && i <= LAST_SPACE; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 s = static_cast<AllocationSpace>(i);
1152 found = Heap::InSpace(obj, s);
1153 }
1154 CHECK(found);
kasper.lund7276f142008-07-30 08:49:36 +00001155 if (s == NEW_SPACE) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001156 Space* space = Heap::TargetSpace(obj);
1157 ASSERT(space == Heap::old_pointer_space() ||
1158 space == Heap::old_data_space());
1159 s = (space == Heap::old_pointer_space()) ?
1160 OLD_POINTER_SPACE :
1161 OLD_DATA_SPACE;
kasper.lund7276f142008-07-30 08:49:36 +00001162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 int size = obj->Size();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001164 GCTreatment gc_treatment = DataObject;
1165 if (obj->IsFixedArray()) gc_treatment = PointerObject;
1166 else if (obj->IsCode()) gc_treatment = CodeObject;
1167 return allocator_[s]->Allocate(size, gc_treatment);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168}
1169
1170
1171//------------------------------------------------------------------------------
1172// Implementation of Deserializer
1173
1174
1175static const int kInitArraySize = 32;
1176
1177
kasper.lund44510672008-07-25 07:37:58 +00001178Deserializer::Deserializer(const char* str, int len)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 : reader_(str, len),
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001180 map_pages_(kInitArraySize),
1181 old_pointer_pages_(kInitArraySize),
1182 old_data_pages_(kInitArraySize),
1183 code_pages_(kInitArraySize),
1184 large_objects_(kInitArraySize),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 global_handles_(4) {
1186 root_ = true;
1187 roots_ = 0;
1188 objects_ = 0;
1189 reference_decoder_ = NULL;
1190#ifdef DEBUG
1191 expect_debug_information_ = false;
1192#endif
1193}
1194
1195
1196Deserializer::~Deserializer() {
1197 if (reference_decoder_) delete reference_decoder_;
1198}
1199
1200
1201void Deserializer::ExpectEncodedAddress(Address expected) {
1202 Address a = GetEncodedAddress();
1203 USE(a);
1204 ASSERT(a == expected);
1205}
1206
1207
1208#ifdef DEBUG
1209void Deserializer::Synchronize(const char* tag) {
1210 if (expect_debug_information_) {
1211 char buf[kMaxTagLength];
1212 reader_.ExpectC('S');
1213 int length = reader_.GetInt();
1214 ASSERT(length <= kMaxTagLength);
1215 reader_.GetBytes(reinterpret_cast<Address>(buf), length);
1216 ASSERT_EQ(strlen(tag), length);
1217 ASSERT(strncmp(tag, buf, length) == 0);
1218 }
1219}
1220#endif
1221
1222
1223void Deserializer::Deserialize() {
1224 // No active threads.
1225 ASSERT_EQ(NULL, ThreadState::FirstInUse());
1226 // No active handles.
1227 ASSERT(HandleScopeImplementer::instance()->Blocks()->is_empty());
1228 reference_decoder_ = new ExternalReferenceDecoder();
1229 // By setting linear allocation only, we forbid the use of free list
1230 // allocation which is not predicted by SimulatedAddress.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 GetHeader();
1232 Heap::IterateRoots(this);
1233 GetContextStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234}
1235
1236
1237void Deserializer::VisitPointers(Object** start, Object** end) {
1238 bool root = root_;
1239 root_ = false;
1240 for (Object** p = start; p < end; ++p) {
1241 if (root) {
1242 roots_++;
1243 // Read the next object or pointer from the stream
1244 // pointer in the stream.
1245 int c = reader_.GetC();
1246 if (c == '[') {
1247 *p = GetObject(); // embedded object
1248 } else {
1249 ASSERT(c == 'P'); // pointer to previously serialized object
1250 *p = Resolve(reinterpret_cast<Address>(reader_.GetInt()));
1251 }
1252 } else {
1253 // A pointer internal to a HeapObject that we've already
1254 // read: resolve it to a true address (or Smi)
1255 *p = Resolve(reinterpret_cast<Address>(*p));
1256 }
1257 }
1258 root_ = root;
1259}
1260
1261
1262void Deserializer::VisitExternalReferences(Address* start, Address* end) {
1263 for (Address* p = start; p < end; ++p) {
1264 uint32_t code = reinterpret_cast<uint32_t>(*p);
1265 *p = reference_decoder_->Decode(code);
1266 }
1267}
1268
1269
1270void Deserializer::VisitRuntimeEntry(RelocInfo* rinfo) {
1271 uint32_t* pc = reinterpret_cast<uint32_t*>(rinfo->pc());
1272 uint32_t encoding = *pc;
1273 Address target = reference_decoder_->Decode(encoding);
1274 rinfo->set_target_address(target);
1275}
1276
1277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278void Deserializer::GetFlags() {
1279 reader_.ExpectC('F');
1280 int argc = reader_.GetInt() + 1;
1281 char** argv = NewArray<char*>(argc);
1282 reader_.ExpectC('[');
1283 for (int i = 1; i < argc; i++) {
1284 if (i > 1) reader_.ExpectC('|');
1285 argv[i] = reader_.GetString();
1286 }
1287 reader_.ExpectC(']');
1288 has_log_ = false;
1289 for (int i = 1; i < argc; i++) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001290 if (strcmp("--log_code", argv[i]) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 has_log_ = true;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001292 } else if (strcmp("--nouse_ic", argv[i]) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 FLAG_use_ic = false;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001294 } else if (strcmp("--debug_code", argv[i]) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 FLAG_debug_code = true;
1296 } else if (strcmp("--nolazy", argv[i]) == 0) {
1297 FLAG_lazy = false;
1298 }
1299 DeleteArray(argv[i]);
1300 }
1301
1302 DeleteArray(argv);
1303}
1304
1305
1306void Deserializer::GetLog() {
1307 if (has_log_) {
1308 reader_.ExpectC('L');
1309 char* snapshot_log = reader_.GetString();
1310#ifdef ENABLE_LOGGING_AND_PROFILING
1311 if (FLAG_log_code) {
1312 LOG(Preamble(snapshot_log));
1313 }
1314#endif
1315 DeleteArray(snapshot_log);
1316 }
1317}
1318
1319
1320static void InitPagedSpace(PagedSpace* space,
1321 int capacity,
1322 List<Page*>* page_list) {
1323 space->EnsureCapacity(capacity);
1324 // TODO(1240712): PagedSpace::EnsureCapacity can return false due to
1325 // a failure to allocate from the OS to expand the space.
1326 PageIterator it(space, PageIterator::ALL_PAGES);
1327 while (it.has_next()) page_list->Add(it.next());
1328}
1329
1330
1331void Deserializer::GetHeader() {
1332 reader_.ExpectC('D');
1333#ifdef DEBUG
1334 expect_debug_information_ = reader_.GetC() == '1';
1335#else
1336 // In release mode, don't attempt to read a snapshot containing
1337 // synchronization tags.
1338 if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags.");
1339#endif
1340 // Ensure sufficient capacity in paged memory spaces to avoid growth
1341 // during deserialization.
1342 reader_.ExpectC('S');
1343 reader_.ExpectC('[');
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001344 InitPagedSpace(Heap::old_pointer_space(),
1345 reader_.GetInt(),
1346 &old_pointer_pages_);
1347 reader_.ExpectC('|');
1348 InitPagedSpace(Heap::old_data_space(), reader_.GetInt(), &old_data_pages_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 reader_.ExpectC('|');
1350 InitPagedSpace(Heap::code_space(), reader_.GetInt(), &code_pages_);
1351 reader_.ExpectC('|');
1352 InitPagedSpace(Heap::map_space(), reader_.GetInt(), &map_pages_);
1353 reader_.ExpectC(']');
1354 // Create placeholders for global handles later to be fill during
1355 // IterateRoots.
1356 reader_.ExpectC('G');
1357 reader_.ExpectC('[');
1358 int c = reader_.GetC();
1359 while (c != ']') {
1360 ASSERT(c == 'N');
1361 global_handles_.Add(GlobalHandles::Create(NULL).location());
1362 c = reader_.GetC();
1363 }
1364}
1365
1366
1367void Deserializer::GetGlobalHandleStack(List<Handle<Object> >* stack) {
1368 reader_.ExpectC('[');
1369 int length = reader_.GetInt();
1370 for (int i = 0; i < length; i++) {
1371 reader_.ExpectC('|');
1372 int gh_index = reader_.GetInt();
1373 stack->Add(global_handles_[gh_index]);
1374 }
1375 reader_.ExpectC(']');
1376}
1377
1378
1379void Deserializer::GetContextStack() {
1380 List<Handle<Object> > entered_contexts(2);
1381 GetGlobalHandleStack(&entered_contexts);
1382 for (int i = 0; i < entered_contexts.length(); i++) {
kasper.lund44510672008-07-25 07:37:58 +00001383 HandleScopeImplementer::instance()->SaveContext(entered_contexts[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385}
1386
1387
1388Address Deserializer::GetEncodedAddress() {
1389 reader_.ExpectC('P');
1390 return reinterpret_cast<Address>(reader_.GetInt());
1391}
1392
1393
1394Object* Deserializer::GetObject() {
1395 // Read the prologue: type, size and encoded address.
1396 InstanceType type = static_cast<InstanceType>(reader_.GetInt());
1397 int size = reader_.GetInt() << kObjectAlignmentBits;
1398 Address a = GetEncodedAddress();
1399
1400 // Get a raw object of the right size in the right space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001401 AllocationSpace space = GetSpace(a);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001402 Object* o;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001403 if (IsLargeExecutableObject(a)) {
1404 o = Heap::lo_space()->AllocateRawCode(size);
1405 } else if (IsLargeFixedArray(a)) {
1406 o = Heap::lo_space()->AllocateRawFixedArray(size);
1407 } else {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001408 AllocationSpace retry_space = (space == NEW_SPACE)
1409 ? Heap::TargetSpaceId(type)
1410 : space;
1411 o = Heap::AllocateRaw(size, space, retry_space);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001412 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 ASSERT(!o->IsFailure());
1414 // Check that the simulation of heap allocation was correct.
1415 ASSERT(o == Resolve(a));
1416
1417 // Read any recursively embedded objects.
1418 int c = reader_.GetC();
1419 while (c == '[') {
1420 GetObject();
1421 c = reader_.GetC();
1422 }
1423 ASSERT(c == '|');
1424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 HeapObject* obj = reinterpret_cast<HeapObject*>(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 // Read the uninterpreted contents of the object after the map
mads.s.ager31e71382008-08-13 09:32:07 +00001427 reader_.GetBytes(obj->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428#ifdef DEBUG
1429 if (expect_debug_information_) {
1430 // Read in the epilogue to check that we're still synchronized
1431 ExpectEncodedAddress(a);
1432 reader_.ExpectC(']');
1433 }
1434#endif
1435
mads.s.ager31e71382008-08-13 09:32:07 +00001436 // Resolve the encoded pointers we just read in.
1437 // Same as obj->Iterate(this), but doesn't rely on the map pointer being set.
1438 VisitPointer(reinterpret_cast<Object**>(obj->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439 obj->IterateBody(type, size, this);
1440
1441 if (type == CODE_TYPE) {
1442 Code* code = Code::cast(obj);
1443 // Convert relocations from Object* to Address in Code objects
1444 code->ConvertICTargetsFromObjectToAddress();
1445 LOG(CodeMoveEvent(a, code->address()));
1446 }
1447 objects_++;
1448 return o;
1449}
1450
1451
1452static inline Object* ResolvePaged(int page_index,
1453 int page_offset,
1454 PagedSpace* space,
1455 List<Page*>* page_list) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 ASSERT(page_index < page_list->length());
1457 Address address = (*page_list)[page_index]->OffsetToAddress(page_offset);
1458 return HeapObject::FromAddress(address);
1459}
1460
1461
1462template<typename T>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001463void ConcatReversed(List<T>* target, const List<T>& source) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 for (int i = source.length() - 1; i >= 0; i--) {
1465 target->Add(source[i]);
1466 }
1467}
1468
1469
1470Object* Deserializer::Resolve(Address encoded) {
1471 Object* o = reinterpret_cast<Object*>(encoded);
1472 if (o->IsSmi()) return o;
1473
1474 // Encoded addresses of HeapObjects always have 'HeapObject' tags.
1475 ASSERT(o->IsHeapObject());
1476
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001477 switch (GetSpace(encoded)) {
1478 // For Map space and Old space, we cache the known Pages in map_pages,
1479 // old_pointer_pages and old_data_pages. Even though MapSpace keeps a list
1480 // of page addresses, we don't rely on it since GetObject uses AllocateRaw,
1481 // and that appears not to update the page list.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 case MAP_SPACE:
1483 return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1484 Heap::map_space(), &map_pages_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001485 case OLD_POINTER_SPACE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001487 Heap::old_pointer_space(), &old_pointer_pages_);
1488 case OLD_DATA_SPACE:
1489 return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1490 Heap::old_data_space(), &old_data_pages_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 case CODE_SPACE:
1492 return ResolvePaged(PageIndex(encoded), PageOffset(encoded),
1493 Heap::code_space(), &code_pages_);
1494 case NEW_SPACE:
1495 return HeapObject::FromAddress(Heap::NewSpaceStart() +
1496 NewSpaceOffset(encoded));
1497 case LO_SPACE:
1498 // Cache the known large_objects, allocated one per 'page'
1499 int index = LargeObjectIndex(encoded);
1500 if (index >= large_objects_.length()) {
1501 int new_object_count =
1502 Heap::lo_space()->PageCount() - large_objects_.length();
1503 List<Object*> new_objects(new_object_count);
1504 LargeObjectIterator it(Heap::lo_space());
1505 for (int i = 0; i < new_object_count; i++) {
1506 new_objects.Add(it.next());
1507 }
1508#ifdef DEBUG
1509 for (int i = large_objects_.length() - 1; i >= 0; i--) {
1510 ASSERT(it.next() == large_objects_[i]);
1511 }
1512#endif
1513 ConcatReversed(&large_objects_, new_objects);
1514 ASSERT(index < large_objects_.length());
1515 }
1516 return large_objects_[index]; // s.page_offset() is ignored.
1517 }
1518 UNREACHABLE();
1519 return NULL;
1520}
1521
1522
1523} } // namespace v8::internal