blob: 899e2e7a599f167dec01791a716ee1962a15ef02 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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"
Steve Block3ce2e202009-11-05 08:53:23 +000041#include "top.h"
Steve Blockd0582a62009-12-15 09:54:21 +000042#include "bootstrapper.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000043
44namespace v8 {
45namespace internal {
46
Steve Blockd0582a62009-12-15 09:54:21 +000047// Mapping objects to their location after deserialization.
48// This is used during building, but not at runtime by V8.
49class SerializationAddressMapper {
Steve Blocka7e24c12009-10-30 11:49:00 +000050 public:
Steve Blockd0582a62009-12-15 09:54:21 +000051 static bool IsMapped(HeapObject* obj) {
52 EnsureMapExists();
53 return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000054 }
55
Steve Blockd0582a62009-12-15 09:54:21 +000056 static int MappedTo(HeapObject* obj) {
57 ASSERT(IsMapped(obj));
58 return reinterpret_cast<intptr_t>(serialization_map_->Lookup(Key(obj),
59 Hash(obj),
60 false)->value);
Steve Blocka7e24c12009-10-30 11:49:00 +000061 }
62
Steve Blockd0582a62009-12-15 09:54:21 +000063 static void Map(HeapObject* obj, int to) {
64 EnsureMapExists();
65 ASSERT(!IsMapped(obj));
66 HashMap::Entry* entry =
67 serialization_map_->Lookup(Key(obj), Hash(obj), true);
68 entry->value = Value(to);
Steve Blocka7e24c12009-10-30 11:49:00 +000069 }
70
Steve Blockd0582a62009-12-15 09:54:21 +000071 static void Zap() {
72 if (serialization_map_ != NULL) {
73 delete serialization_map_;
74 }
75 serialization_map_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000076 }
Steve Blocka7e24c12009-10-30 11:49:00 +000077
78 private:
Steve Blockd0582a62009-12-15 09:54:21 +000079 static bool SerializationMatchFun(void* key1, void* key2) {
80 return key1 == key2;
Steve Blocka7e24c12009-10-30 11:49:00 +000081 }
Steve Blocka7e24c12009-10-30 11:49:00 +000082
Steve Blockd0582a62009-12-15 09:54:21 +000083 static uint32_t Hash(HeapObject* obj) {
84 return reinterpret_cast<intptr_t>(obj->address());
Steve Blocka7e24c12009-10-30 11:49:00 +000085 }
Steve Blocka7e24c12009-10-30 11:49:00 +000086
Steve Blockd0582a62009-12-15 09:54:21 +000087 static void* Key(HeapObject* obj) {
88 return reinterpret_cast<void*>(obj->address());
Steve Blocka7e24c12009-10-30 11:49:00 +000089 }
Steve Blocka7e24c12009-10-30 11:49:00 +000090
Steve Blockd0582a62009-12-15 09:54:21 +000091 static void* Value(int v) {
92 return reinterpret_cast<void*>(v);
93 }
Steve Blocka7e24c12009-10-30 11:49:00 +000094
Steve Blockd0582a62009-12-15 09:54:21 +000095 static void EnsureMapExists() {
96 if (serialization_map_ == NULL) {
97 serialization_map_ = new HashMap(&SerializationMatchFun);
Steve Blocka7e24c12009-10-30 11:49:00 +000098 }
Steve Blocka7e24c12009-10-30 11:49:00 +000099 }
Steve Blockd0582a62009-12-15 09:54:21 +0000100
101 static HashMap* serialization_map_;
102};
Steve Blocka7e24c12009-10-30 11:49:00 +0000103
104
Steve Blockd0582a62009-12-15 09:54:21 +0000105HashMap* SerializationAddressMapper::serialization_map_ = NULL;
106
107
108
Steve Blocka7e24c12009-10-30 11:49:00 +0000109
110// -----------------------------------------------------------------------------
111// Coding of external references.
112
113// The encoding of an external reference. The type is in the high word.
114// The id is in the low word.
115static uint32_t EncodeExternal(TypeCode type, uint16_t id) {
116 return static_cast<uint32_t>(type) << 16 | id;
117}
118
119
120static int* GetInternalPointer(StatsCounter* counter) {
121 // All counters refer to dummy_counter, if deserializing happens without
122 // setting up counters.
123 static int dummy_counter = 0;
124 return counter->Enabled() ? counter->GetInternalPointer() : &dummy_counter;
125}
126
127
128// ExternalReferenceTable is a helper class that defines the relationship
129// between external references and their encodings. It is used to build
130// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.
131class ExternalReferenceTable {
132 public:
133 static ExternalReferenceTable* instance() {
134 if (!instance_) instance_ = new ExternalReferenceTable();
135 return instance_;
136 }
137
138 int size() const { return refs_.length(); }
139
140 Address address(int i) { return refs_[i].address; }
141
142 uint32_t code(int i) { return refs_[i].code; }
143
144 const char* name(int i) { return refs_[i].name; }
145
146 int max_id(int code) { return max_id_[code]; }
147
148 private:
149 static ExternalReferenceTable* instance_;
150
151 ExternalReferenceTable() : refs_(64) { PopulateTable(); }
152 ~ExternalReferenceTable() { }
153
154 struct ExternalReferenceEntry {
155 Address address;
156 uint32_t code;
157 const char* name;
158 };
159
160 void PopulateTable();
161
162 // For a few types of references, we can get their address from their id.
163 void AddFromId(TypeCode type, uint16_t id, const char* name);
164
165 // For other types of references, the caller will figure out the address.
166 void Add(Address address, TypeCode type, uint16_t id, const char* name);
167
168 List<ExternalReferenceEntry> refs_;
169 int max_id_[kTypeCodeCount];
170};
171
172
173ExternalReferenceTable* ExternalReferenceTable::instance_ = NULL;
174
175
176void ExternalReferenceTable::AddFromId(TypeCode type,
177 uint16_t id,
178 const char* name) {
179 Address address;
180 switch (type) {
181 case C_BUILTIN: {
182 ExternalReference ref(static_cast<Builtins::CFunctionId>(id));
183 address = ref.address();
184 break;
185 }
186 case BUILTIN: {
187 ExternalReference ref(static_cast<Builtins::Name>(id));
188 address = ref.address();
189 break;
190 }
191 case RUNTIME_FUNCTION: {
192 ExternalReference ref(static_cast<Runtime::FunctionId>(id));
193 address = ref.address();
194 break;
195 }
196 case IC_UTILITY: {
197 ExternalReference ref(IC_Utility(static_cast<IC::UtilityId>(id)));
198 address = ref.address();
199 break;
200 }
201 default:
202 UNREACHABLE();
203 return;
204 }
205 Add(address, type, id, name);
206}
207
208
209void ExternalReferenceTable::Add(Address address,
210 TypeCode type,
211 uint16_t id,
212 const char* name) {
Steve Blockd0582a62009-12-15 09:54:21 +0000213 ASSERT_NE(NULL, address);
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 ExternalReferenceEntry entry;
215 entry.address = address;
216 entry.code = EncodeExternal(type, id);
217 entry.name = name;
Steve Blockd0582a62009-12-15 09:54:21 +0000218 ASSERT_NE(0, entry.code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000219 refs_.Add(entry);
220 if (id > max_id_[type]) max_id_[type] = id;
221}
222
223
224void ExternalReferenceTable::PopulateTable() {
225 for (int type_code = 0; type_code < kTypeCodeCount; type_code++) {
226 max_id_[type_code] = 0;
227 }
228
229 // The following populates all of the different type of external references
230 // into the ExternalReferenceTable.
231 //
232 // NOTE: This function was originally 100k of code. It has since been
233 // rewritten to be mostly table driven, as the callback macro style tends to
234 // very easily cause code bloat. Please be careful in the future when adding
235 // new references.
236
237 struct RefTableEntry {
238 TypeCode type;
239 uint16_t id;
240 const char* name;
241 };
242
243 static const RefTableEntry ref_table[] = {
244 // Builtins
245#define DEF_ENTRY_C(name) \
246 { C_BUILTIN, \
247 Builtins::c_##name, \
248 "Builtins::" #name },
249
250 BUILTIN_LIST_C(DEF_ENTRY_C)
251#undef DEF_ENTRY_C
252
253#define DEF_ENTRY_C(name) \
254 { BUILTIN, \
255 Builtins::name, \
256 "Builtins::" #name },
257#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name)
258
259 BUILTIN_LIST_C(DEF_ENTRY_C)
260 BUILTIN_LIST_A(DEF_ENTRY_A)
261 BUILTIN_LIST_DEBUG_A(DEF_ENTRY_A)
262#undef DEF_ENTRY_C
263#undef DEF_ENTRY_A
264
265 // Runtime functions
266#define RUNTIME_ENTRY(name, nargs, ressize) \
267 { RUNTIME_FUNCTION, \
268 Runtime::k##name, \
269 "Runtime::" #name },
270
271 RUNTIME_FUNCTION_LIST(RUNTIME_ENTRY)
272#undef RUNTIME_ENTRY
273
274 // IC utilities
275#define IC_ENTRY(name) \
276 { IC_UTILITY, \
277 IC::k##name, \
278 "IC::" #name },
279
280 IC_UTIL_LIST(IC_ENTRY)
281#undef IC_ENTRY
282 }; // end of ref_table[].
283
284 for (size_t i = 0; i < ARRAY_SIZE(ref_table); ++i) {
285 AddFromId(ref_table[i].type, ref_table[i].id, ref_table[i].name);
286 }
287
288#ifdef ENABLE_DEBUGGER_SUPPORT
289 // Debug addresses
290 Add(Debug_Address(Debug::k_after_break_target_address).address(),
291 DEBUG_ADDRESS,
292 Debug::k_after_break_target_address << kDebugIdShift,
293 "Debug::after_break_target_address()");
294 Add(Debug_Address(Debug::k_debug_break_return_address).address(),
295 DEBUG_ADDRESS,
296 Debug::k_debug_break_return_address << kDebugIdShift,
297 "Debug::debug_break_return_address()");
298 const char* debug_register_format = "Debug::register_address(%i)";
Steve Blockd0582a62009-12-15 09:54:21 +0000299 int dr_format_length = StrLength(debug_register_format);
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 for (int i = 0; i < kNumJSCallerSaved; ++i) {
301 Vector<char> name = Vector<char>::New(dr_format_length + 1);
302 OS::SNPrintF(name, debug_register_format, i);
303 Add(Debug_Address(Debug::k_register_address, i).address(),
304 DEBUG_ADDRESS,
305 Debug::k_register_address << kDebugIdShift | i,
306 name.start());
307 }
308#endif
309
310 // Stat counters
311 struct StatsRefTableEntry {
312 StatsCounter* counter;
313 uint16_t id;
314 const char* name;
315 };
316
317 static const StatsRefTableEntry stats_ref_table[] = {
318#define COUNTER_ENTRY(name, caption) \
319 { &Counters::name, \
320 Counters::k_##name, \
321 "Counters::" #name },
322
323 STATS_COUNTER_LIST_1(COUNTER_ENTRY)
324 STATS_COUNTER_LIST_2(COUNTER_ENTRY)
325#undef COUNTER_ENTRY
326 }; // end of stats_ref_table[].
327
328 for (size_t i = 0; i < ARRAY_SIZE(stats_ref_table); ++i) {
329 Add(reinterpret_cast<Address>(
330 GetInternalPointer(stats_ref_table[i].counter)),
331 STATS_COUNTER,
332 stats_ref_table[i].id,
333 stats_ref_table[i].name);
334 }
335
336 // Top addresses
Steve Block3ce2e202009-11-05 08:53:23 +0000337 const char* top_address_format = "Top::%s";
338
339 const char* AddressNames[] = {
340#define C(name) #name,
341 TOP_ADDRESS_LIST(C)
342 TOP_ADDRESS_LIST_PROF(C)
343 NULL
344#undef C
345 };
346
Steve Blockd0582a62009-12-15 09:54:21 +0000347 int top_format_length = StrLength(top_address_format) - 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 for (uint16_t i = 0; i < Top::k_top_address_count; ++i) {
Steve Block3ce2e202009-11-05 08:53:23 +0000349 const char* address_name = AddressNames[i];
350 Vector<char> name =
Steve Blockd0582a62009-12-15 09:54:21 +0000351 Vector<char>::New(top_format_length + StrLength(address_name) + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 const char* chars = name.start();
Steve Block3ce2e202009-11-05 08:53:23 +0000353 OS::SNPrintF(name, top_address_format, address_name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000354 Add(Top::get_address_from_id((Top::AddressId)i), TOP_ADDRESS, i, chars);
355 }
356
357 // Extensions
358 Add(FUNCTION_ADDR(GCExtension::GC), EXTENSION, 1,
359 "GCExtension::GC");
360
361 // Accessors
362#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
363 Add((Address)&Accessors::name, \
364 ACCESSOR, \
365 Accessors::k##name, \
366 "Accessors::" #name);
367
368 ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
369#undef ACCESSOR_DESCRIPTOR_DECLARATION
370
371 // Stub cache tables
372 Add(SCTableReference::keyReference(StubCache::kPrimary).address(),
373 STUB_CACHE_TABLE,
374 1,
375 "StubCache::primary_->key");
376 Add(SCTableReference::valueReference(StubCache::kPrimary).address(),
377 STUB_CACHE_TABLE,
378 2,
379 "StubCache::primary_->value");
380 Add(SCTableReference::keyReference(StubCache::kSecondary).address(),
381 STUB_CACHE_TABLE,
382 3,
383 "StubCache::secondary_->key");
384 Add(SCTableReference::valueReference(StubCache::kSecondary).address(),
385 STUB_CACHE_TABLE,
386 4,
387 "StubCache::secondary_->value");
388
389 // Runtime entries
390 Add(ExternalReference::perform_gc_function().address(),
391 RUNTIME_ENTRY,
392 1,
393 "Runtime::PerformGC");
394 Add(ExternalReference::random_positive_smi_function().address(),
395 RUNTIME_ENTRY,
396 2,
397 "V8::RandomPositiveSmi");
398
399 // Miscellaneous
400 Add(ExternalReference::builtin_passed_function().address(),
401 UNCLASSIFIED,
402 1,
403 "Builtins::builtin_passed_function");
404 Add(ExternalReference::the_hole_value_location().address(),
405 UNCLASSIFIED,
406 2,
407 "Factory::the_hole_value().location()");
408 Add(ExternalReference::roots_address().address(),
409 UNCLASSIFIED,
410 3,
411 "Heap::roots_address()");
Steve Blockd0582a62009-12-15 09:54:21 +0000412 Add(ExternalReference::address_of_stack_limit().address(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000413 UNCLASSIFIED,
414 4,
415 "StackGuard::address_of_jslimit()");
Steve Blockd0582a62009-12-15 09:54:21 +0000416 Add(ExternalReference::address_of_real_stack_limit().address(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 UNCLASSIFIED,
418 5,
Steve Blockd0582a62009-12-15 09:54:21 +0000419 "StackGuard::address_of_real_jslimit()");
420 Add(ExternalReference::address_of_regexp_stack_limit().address(),
421 UNCLASSIFIED,
422 6,
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 "RegExpStack::limit_address()");
424 Add(ExternalReference::new_space_start().address(),
425 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000426 7,
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 "Heap::NewSpaceStart()");
428 Add(ExternalReference::heap_always_allocate_scope_depth().address(),
429 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000430 8,
Steve Blocka7e24c12009-10-30 11:49:00 +0000431 "Heap::always_allocate_scope_depth()");
432 Add(ExternalReference::new_space_allocation_limit_address().address(),
433 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000434 9,
Steve Blocka7e24c12009-10-30 11:49:00 +0000435 "Heap::NewSpaceAllocationLimitAddress()");
436 Add(ExternalReference::new_space_allocation_top_address().address(),
437 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000438 10,
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 "Heap::NewSpaceAllocationTopAddress()");
440#ifdef ENABLE_DEBUGGER_SUPPORT
441 Add(ExternalReference::debug_break().address(),
442 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000443 11,
Steve Blocka7e24c12009-10-30 11:49:00 +0000444 "Debug::Break()");
445 Add(ExternalReference::debug_step_in_fp_address().address(),
446 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000447 12,
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 "Debug::step_in_fp_addr()");
449#endif
450 Add(ExternalReference::double_fp_operation(Token::ADD).address(),
451 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000452 13,
Steve Blocka7e24c12009-10-30 11:49:00 +0000453 "add_two_doubles");
454 Add(ExternalReference::double_fp_operation(Token::SUB).address(),
455 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000456 14,
Steve Blocka7e24c12009-10-30 11:49:00 +0000457 "sub_two_doubles");
458 Add(ExternalReference::double_fp_operation(Token::MUL).address(),
459 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000460 15,
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 "mul_two_doubles");
462 Add(ExternalReference::double_fp_operation(Token::DIV).address(),
463 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000464 16,
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 "div_two_doubles");
466 Add(ExternalReference::double_fp_operation(Token::MOD).address(),
467 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000468 17,
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 "mod_two_doubles");
470 Add(ExternalReference::compare_doubles().address(),
471 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000472 18,
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 "compare_doubles");
474#ifdef V8_NATIVE_REGEXP
475 Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
476 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000477 19,
Steve Blocka7e24c12009-10-30 11:49:00 +0000478 "NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
479 Add(ExternalReference::re_check_stack_guard_state().address(),
480 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000481 20,
Steve Blocka7e24c12009-10-30 11:49:00 +0000482 "RegExpMacroAssembler*::CheckStackGuardState()");
483 Add(ExternalReference::re_grow_stack().address(),
484 UNCLASSIFIED,
Steve Blockd0582a62009-12-15 09:54:21 +0000485 21,
Steve Blocka7e24c12009-10-30 11:49:00 +0000486 "NativeRegExpMacroAssembler::GrowStack()");
487#endif
488}
489
490
491ExternalReferenceEncoder::ExternalReferenceEncoder()
492 : encodings_(Match) {
493 ExternalReferenceTable* external_references =
494 ExternalReferenceTable::instance();
495 for (int i = 0; i < external_references->size(); ++i) {
496 Put(external_references->address(i), i);
497 }
498}
499
500
501uint32_t ExternalReferenceEncoder::Encode(Address key) const {
502 int index = IndexOf(key);
503 return index >=0 ? ExternalReferenceTable::instance()->code(index) : 0;
504}
505
506
507const char* ExternalReferenceEncoder::NameOfAddress(Address key) const {
508 int index = IndexOf(key);
509 return index >=0 ? ExternalReferenceTable::instance()->name(index) : NULL;
510}
511
512
513int ExternalReferenceEncoder::IndexOf(Address key) const {
514 if (key == NULL) return -1;
515 HashMap::Entry* entry =
516 const_cast<HashMap &>(encodings_).Lookup(key, Hash(key), false);
517 return entry == NULL
518 ? -1
519 : static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
520}
521
522
523void ExternalReferenceEncoder::Put(Address key, int index) {
524 HashMap::Entry* entry = encodings_.Lookup(key, Hash(key), true);
525 entry->value = reinterpret_cast<void *>(index);
526}
527
528
529ExternalReferenceDecoder::ExternalReferenceDecoder()
530 : encodings_(NewArray<Address*>(kTypeCodeCount)) {
531 ExternalReferenceTable* external_references =
532 ExternalReferenceTable::instance();
533 for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
534 int max = external_references->max_id(type) + 1;
535 encodings_[type] = NewArray<Address>(max + 1);
536 }
537 for (int i = 0; i < external_references->size(); ++i) {
538 Put(external_references->code(i), external_references->address(i));
539 }
540}
541
542
543ExternalReferenceDecoder::~ExternalReferenceDecoder() {
544 for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) {
545 DeleteArray(encodings_[type]);
546 }
547 DeleteArray(encodings_);
548}
549
550
Steve Blocka7e24c12009-10-30 11:49:00 +0000551bool Serializer::serialization_enabled_ = false;
Steve Blockd0582a62009-12-15 09:54:21 +0000552bool Serializer::too_late_to_enable_now_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000553
554
Steve Blockd0582a62009-12-15 09:54:21 +0000555Deserializer::Deserializer(SnapshotByteSource* source)
556 : source_(source),
557 external_reference_decoder_(NULL) {
558}
559
560
561// This routine both allocates a new object, and also keeps
562// track of where objects have been allocated so that we can
563// fix back references when deserializing.
564Address Deserializer::Allocate(int space_index, Space* space, int size) {
565 Address address;
566 if (!SpaceIsLarge(space_index)) {
567 ASSERT(!SpaceIsPaged(space_index) ||
568 size <= Page::kPageSize - Page::kObjectStartOffset);
569 Object* new_allocation;
570 if (space_index == NEW_SPACE) {
571 new_allocation = reinterpret_cast<NewSpace*>(space)->AllocateRaw(size);
572 } else {
573 new_allocation = reinterpret_cast<PagedSpace*>(space)->AllocateRaw(size);
574 }
575 HeapObject* new_object = HeapObject::cast(new_allocation);
576 ASSERT(!new_object->IsFailure());
577 address = new_object->address();
578 high_water_[space_index] = address + size;
579 } else {
580 ASSERT(SpaceIsLarge(space_index));
581 ASSERT(size > Page::kPageSize - Page::kObjectStartOffset);
582 LargeObjectSpace* lo_space = reinterpret_cast<LargeObjectSpace*>(space);
583 Object* new_allocation;
584 if (space_index == kLargeData) {
585 new_allocation = lo_space->AllocateRaw(size);
586 } else if (space_index == kLargeFixedArray) {
587 new_allocation = lo_space->AllocateRawFixedArray(size);
588 } else {
589 ASSERT_EQ(kLargeCode, space_index);
590 new_allocation = lo_space->AllocateRawCode(size);
591 }
592 ASSERT(!new_allocation->IsFailure());
593 HeapObject* new_object = HeapObject::cast(new_allocation);
594 // Record all large objects in the same space.
595 address = new_object->address();
596 high_water_[LO_SPACE] = address + size;
597 }
598 last_object_address_ = address;
599 return address;
600}
601
602
603// This returns the address of an object that has been described in the
604// snapshot as being offset bytes back in a particular space.
605HeapObject* Deserializer::GetAddressFromEnd(int space) {
606 int offset = source_->GetInt();
607 ASSERT(!SpaceIsLarge(space));
608 offset <<= kObjectAlignmentBits;
609 return HeapObject::FromAddress(high_water_[space] - offset);
610}
611
612
613// This returns the address of an object that has been described in the
614// snapshot as being offset bytes into a particular space.
615HeapObject* Deserializer::GetAddressFromStart(int space) {
616 int offset = source_->GetInt();
617 if (SpaceIsLarge(space)) {
618 // Large spaces have one object per 'page'.
619 return HeapObject::FromAddress(pages_[LO_SPACE][offset]);
620 }
621 offset <<= kObjectAlignmentBits;
622 if (space == NEW_SPACE) {
623 // New space has only one space - numbered 0.
624 return HeapObject::FromAddress(pages_[space][0] + offset);
625 }
626 ASSERT(SpaceIsPaged(space));
627 int page_of_pointee = offset >> Page::kPageSizeBits;
628 Address object_address = pages_[space][page_of_pointee] +
629 (offset & Page::kPageAlignmentMask);
630 return HeapObject::FromAddress(object_address);
631}
632
633
634void Deserializer::Deserialize() {
635 // Don't GC while deserializing - just expand the heap.
636 AlwaysAllocateScope always_allocate;
637 // Don't use the free lists while deserializing.
638 LinearAllocationScope allocate_linearly;
639 // No active threads.
640 ASSERT_EQ(NULL, ThreadState::FirstInUse());
641 // No active handles.
642 ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
643 ASSERT_EQ(NULL, external_reference_decoder_);
644 external_reference_decoder_ = new ExternalReferenceDecoder();
645 Heap::IterateRoots(this, VISIT_ONLY_STRONG);
646 ASSERT(source_->AtEOF());
647 delete external_reference_decoder_;
648 external_reference_decoder_ = NULL;
649}
650
651
652// This is called on the roots. It is the driver of the deserialization
653// process. It is also called on the body of each function.
654void Deserializer::VisitPointers(Object** start, Object** end) {
655 // The space must be new space. Any other space would cause ReadChunk to try
656 // to update the remembered using NULL as the address.
657 ReadChunk(start, end, NEW_SPACE, NULL);
658}
659
660
661// This routine writes the new object into the pointer provided and then
662// returns true if the new object was in young space and false otherwise.
663// The reason for this strange interface is that otherwise the object is
664// written very late, which means the ByteArray map is not set up by the
665// time we need to use it to mark the space at the end of a page free (by
666// making it into a byte array).
667void Deserializer::ReadObject(int space_number,
668 Space* space,
669 Object** write_back) {
670 int size = source_->GetInt() << kObjectAlignmentBits;
671 Address address = Allocate(space_number, space, size);
672 *write_back = HeapObject::FromAddress(address);
673 Object** current = reinterpret_cast<Object**>(address);
674 Object** limit = current + (size >> kPointerSizeLog2);
675 ReadChunk(current, limit, space_number, address);
676}
677
678
679#define ONE_CASE_PER_SPACE(base_tag) \
680 case (base_tag) + NEW_SPACE: /* NOLINT */ \
681 case (base_tag) + OLD_POINTER_SPACE: /* NOLINT */ \
682 case (base_tag) + OLD_DATA_SPACE: /* NOLINT */ \
683 case (base_tag) + CODE_SPACE: /* NOLINT */ \
684 case (base_tag) + MAP_SPACE: /* NOLINT */ \
685 case (base_tag) + CELL_SPACE: /* NOLINT */ \
686 case (base_tag) + kLargeData: /* NOLINT */ \
687 case (base_tag) + kLargeCode: /* NOLINT */ \
688 case (base_tag) + kLargeFixedArray: /* NOLINT */
689
690
691void Deserializer::ReadChunk(Object** current,
692 Object** limit,
693 int space,
694 Address address) {
695 while (current < limit) {
696 int data = source_->Get();
697 switch (data) {
698#define RAW_CASE(index, size) \
699 case RAW_DATA_SERIALIZATION + index: { \
700 byte* raw_data_out = reinterpret_cast<byte*>(current); \
701 source_->CopyRaw(raw_data_out, size); \
702 current = reinterpret_cast<Object**>(raw_data_out + size); \
703 break; \
704 }
705 COMMON_RAW_LENGTHS(RAW_CASE)
706#undef RAW_CASE
707 case RAW_DATA_SERIALIZATION: {
708 int size = source_->GetInt();
709 byte* raw_data_out = reinterpret_cast<byte*>(current);
710 source_->CopyRaw(raw_data_out, size);
711 current = reinterpret_cast<Object**>(raw_data_out + size);
712 break;
713 }
714 case OBJECT_SERIALIZATION + NEW_SPACE: {
715 ReadObject(NEW_SPACE, Heap::new_space(), current);
716 if (space != NEW_SPACE) {
717 Heap::RecordWrite(address, static_cast<int>(
718 reinterpret_cast<Address>(current) - address));
719 }
720 current++;
721 break;
722 }
723 case OBJECT_SERIALIZATION + OLD_DATA_SPACE:
724 ReadObject(OLD_DATA_SPACE, Heap::old_data_space(), current++);
725 break;
726 case OBJECT_SERIALIZATION + OLD_POINTER_SPACE:
727 ReadObject(OLD_POINTER_SPACE, Heap::old_pointer_space(), current++);
728 break;
729 case OBJECT_SERIALIZATION + MAP_SPACE:
730 ReadObject(MAP_SPACE, Heap::map_space(), current++);
731 break;
732 case OBJECT_SERIALIZATION + CODE_SPACE:
733 ReadObject(CODE_SPACE, Heap::code_space(), current++);
734 LOG(LogCodeObject(current[-1]));
735 break;
736 case OBJECT_SERIALIZATION + CELL_SPACE:
737 ReadObject(CELL_SPACE, Heap::cell_space(), current++);
738 break;
739 case OBJECT_SERIALIZATION + kLargeData:
740 ReadObject(kLargeData, Heap::lo_space(), current++);
741 break;
742 case OBJECT_SERIALIZATION + kLargeCode:
743 ReadObject(kLargeCode, Heap::lo_space(), current++);
744 LOG(LogCodeObject(current[-1]));
745 break;
746 case OBJECT_SERIALIZATION + kLargeFixedArray:
747 ReadObject(kLargeFixedArray, Heap::lo_space(), current++);
748 break;
749 case CODE_OBJECT_SERIALIZATION + kLargeCode: {
750 Object* new_code_object = NULL;
751 ReadObject(kLargeCode, Heap::lo_space(), &new_code_object);
752 Code* code_object = reinterpret_cast<Code*>(new_code_object);
753 LOG(LogCodeObject(code_object));
754 // Setting a branch/call to another code object from code.
755 Address location_of_branch_data = reinterpret_cast<Address>(current);
756 Assembler::set_target_at(location_of_branch_data,
757 code_object->instruction_start());
758 location_of_branch_data += Assembler::kCallTargetSize;
759 current = reinterpret_cast<Object**>(location_of_branch_data);
760 break;
761 }
762 case CODE_OBJECT_SERIALIZATION + CODE_SPACE: {
763 Object* new_code_object = NULL;
764 ReadObject(CODE_SPACE, Heap::code_space(), &new_code_object);
765 Code* code_object = reinterpret_cast<Code*>(new_code_object);
766 LOG(LogCodeObject(code_object));
767 // Setting a branch/call to another code object from code.
768 Address location_of_branch_data = reinterpret_cast<Address>(current);
769 Assembler::set_target_at(location_of_branch_data,
770 code_object->instruction_start());
771 location_of_branch_data += Assembler::kCallTargetSize;
772 current = reinterpret_cast<Object**>(location_of_branch_data);
773 break;
774 }
775 ONE_CASE_PER_SPACE(BACKREF_SERIALIZATION) {
776 // Write a backreference to an object we unpacked earlier.
777 int backref_space = (data & kSpaceMask);
778 if (backref_space == NEW_SPACE && space != NEW_SPACE) {
779 Heap::RecordWrite(address, static_cast<int>(
780 reinterpret_cast<Address>(current) - address));
781 }
782 *current++ = GetAddressFromEnd(backref_space);
783 break;
784 }
785 ONE_CASE_PER_SPACE(REFERENCE_SERIALIZATION) {
786 // Write a reference to an object we unpacked earlier.
787 int reference_space = (data & kSpaceMask);
788 if (reference_space == NEW_SPACE && space != NEW_SPACE) {
789 Heap::RecordWrite(address, static_cast<int>(
790 reinterpret_cast<Address>(current) - address));
791 }
792 *current++ = GetAddressFromStart(reference_space);
793 break;
794 }
795#define COMMON_REFS_CASE(index, reference_space, address) \
796 case REFERENCE_SERIALIZATION + index: { \
797 ASSERT(SpaceIsPaged(reference_space)); \
798 Address object_address = \
799 pages_[reference_space][0] + (address << kObjectAlignmentBits); \
800 *current++ = HeapObject::FromAddress(object_address); \
801 break; \
802 }
803 COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
804#undef COMMON_REFS_CASE
805 ONE_CASE_PER_SPACE(CODE_BACKREF_SERIALIZATION) {
806 int backref_space = (data & kSpaceMask);
807 // Can't use Code::cast because heap is not set up yet and assertions
808 // will fail.
809 Code* code_object =
810 reinterpret_cast<Code*>(GetAddressFromEnd(backref_space));
811 // Setting a branch/call to previously decoded code object from code.
812 Address location_of_branch_data = reinterpret_cast<Address>(current);
813 Assembler::set_target_at(location_of_branch_data,
814 code_object->instruction_start());
815 location_of_branch_data += Assembler::kCallTargetSize;
816 current = reinterpret_cast<Object**>(location_of_branch_data);
817 break;
818 }
819 ONE_CASE_PER_SPACE(CODE_REFERENCE_SERIALIZATION) {
820 int backref_space = (data & kSpaceMask);
821 // Can't use Code::cast because heap is not set up yet and assertions
822 // will fail.
823 Code* code_object =
824 reinterpret_cast<Code*>(GetAddressFromStart(backref_space));
825 // Setting a branch/call to previously decoded code object from code.
826 Address location_of_branch_data = reinterpret_cast<Address>(current);
827 Assembler::set_target_at(location_of_branch_data,
828 code_object->instruction_start());
829 location_of_branch_data += Assembler::kCallTargetSize;
830 current = reinterpret_cast<Object**>(location_of_branch_data);
831 break;
832 }
833 case EXTERNAL_REFERENCE_SERIALIZATION: {
834 int reference_id = source_->GetInt();
835 Address address = external_reference_decoder_->Decode(reference_id);
836 *current++ = reinterpret_cast<Object*>(address);
837 break;
838 }
839 case EXTERNAL_BRANCH_TARGET_SERIALIZATION: {
840 int reference_id = source_->GetInt();
841 Address address = external_reference_decoder_->Decode(reference_id);
842 Address location_of_branch_data = reinterpret_cast<Address>(current);
843 Assembler::set_external_target_at(location_of_branch_data, address);
844 location_of_branch_data += Assembler::kExternalTargetSize;
845 current = reinterpret_cast<Object**>(location_of_branch_data);
846 break;
847 }
848 case START_NEW_PAGE_SERIALIZATION: {
849 int space = source_->Get();
850 pages_[space].Add(last_object_address_);
851 break;
852 }
853 case NATIVES_STRING_RESOURCE: {
854 int index = source_->Get();
855 Vector<const char> source_vector = Natives::GetScriptSource(index);
856 NativesExternalStringResource* resource =
857 new NativesExternalStringResource(source_vector.start());
858 *current++ = reinterpret_cast<Object*>(resource);
859 break;
860 }
861 default:
862 UNREACHABLE();
863 }
864 }
865 ASSERT_EQ(current, limit);
866}
867
868
869void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
870 const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
871 for (int shift = max_shift; shift > 0; shift -= 7) {
872 if (integer >= static_cast<uintptr_t>(1u) << shift) {
873 Put(((integer >> shift) & 0x7f) | 0x80, "IntPart");
874 }
875 }
876 PutSection(integer & 0x7f, "IntLastPart");
877}
878
Steve Blocka7e24c12009-10-30 11:49:00 +0000879#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +0000880
881void Deserializer::Synchronize(const char* tag) {
882 int data = source_->Get();
883 // If this assert fails then that indicates that you have a mismatch between
884 // the number of GC roots when serializing and deserializing.
885 ASSERT_EQ(SYNCHRONIZE, data);
886 do {
887 int character = source_->Get();
888 if (character == 0) break;
889 if (FLAG_debug_serialization) {
890 PrintF("%c", character);
891 }
892 } while (true);
893 if (FLAG_debug_serialization) {
894 PrintF("\n");
895 }
896}
897
Steve Blocka7e24c12009-10-30 11:49:00 +0000898
899void Serializer::Synchronize(const char* tag) {
Steve Blockd0582a62009-12-15 09:54:21 +0000900 sink_->Put(SYNCHRONIZE, tag);
901 int character;
902 do {
903 character = *tag++;
904 sink_->PutSection(character, "TagCharacter");
905 } while (character != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000906}
Steve Blockd0582a62009-12-15 09:54:21 +0000907
Steve Blocka7e24c12009-10-30 11:49:00 +0000908#endif
909
Steve Blockd0582a62009-12-15 09:54:21 +0000910Serializer::Serializer(SnapshotByteSink* sink)
911 : sink_(sink),
912 current_root_index_(0),
913 external_reference_encoder_(NULL) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000914 for (int i = 0; i <= LAST_SPACE; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +0000915 fullness_[i] = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 }
917}
918
919
Steve Blocka7e24c12009-10-30 11:49:00 +0000920void Serializer::Serialize() {
921 // No active threads.
922 CHECK_EQ(NULL, ThreadState::FirstInUse());
923 // No active or weak handles.
924 CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
925 CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
Steve Blockd0582a62009-12-15 09:54:21 +0000926 CHECK_EQ(NULL, external_reference_encoder_);
927 // We don't support serializing installed extensions.
928 for (RegisteredExtension* ext = RegisteredExtension::first_extension();
929 ext != NULL;
930 ext = ext->next()) {
931 CHECK_NE(v8::INSTALLED, ext->state());
932 }
933 external_reference_encoder_ = new ExternalReferenceEncoder();
934 Heap::IterateRoots(this, VISIT_ONLY_STRONG);
935 delete external_reference_encoder_;
936 external_reference_encoder_ = NULL;
937 SerializationAddressMapper::Zap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000938}
939
940
Steve Blocka7e24c12009-10-30 11:49:00 +0000941void Serializer::VisitPointers(Object** start, Object** end) {
Steve Blockd0582a62009-12-15 09:54:21 +0000942 for (Object** current = start; current < end; current++) {
943 if ((*current)->IsSmi()) {
944 sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
945 sink_->PutInt(kPointerSize, "length");
946 for (int i = 0; i < kPointerSize; i++) {
947 sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
948 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000950 SerializeObject(*current, TAGGED_REPRESENTATION);
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 }
952 }
953}
954
955
Steve Blockd0582a62009-12-15 09:54:21 +0000956void Serializer::SerializeObject(
957 Object* o,
958 ReferenceRepresentation reference_representation) {
959 CHECK(o->IsHeapObject());
960 HeapObject* heap_object = HeapObject::cast(o);
961 if (SerializationAddressMapper::IsMapped(heap_object)) {
962 int space = SpaceOfAlreadySerializedObject(heap_object);
963 int address = SerializationAddressMapper::MappedTo(heap_object);
964 int offset = CurrentAllocationAddress(space) - address;
965 bool from_start = true;
966 if (SpaceIsPaged(space)) {
967 if ((CurrentAllocationAddress(space) >> Page::kPageSizeBits) ==
968 (address >> Page::kPageSizeBits)) {
969 from_start = false;
970 address = offset;
971 }
972 } else if (space == NEW_SPACE) {
973 if (offset < address) {
974 from_start = false;
975 address = offset;
976 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000977 }
Steve Blockd0582a62009-12-15 09:54:21 +0000978 // If we are actually dealing with real offsets (and not a numbering of
979 // all objects) then we should shift out the bits that are always 0.
980 if (!SpaceIsLarge(space)) address >>= kObjectAlignmentBits;
981 if (reference_representation == CODE_TARGET_REPRESENTATION) {
982 if (from_start) {
983 sink_->Put(CODE_REFERENCE_SERIALIZATION + space, "RefCodeSer");
984 sink_->PutInt(address, "address");
Steve Blocka7e24c12009-10-30 11:49:00 +0000985 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000986 sink_->Put(CODE_BACKREF_SERIALIZATION + space, "BackRefCodeSer");
987 sink_->PutInt(address, "address");
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 }
989 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000990 CHECK_EQ(TAGGED_REPRESENTATION, reference_representation);
991 if (from_start) {
992#define COMMON_REFS_CASE(tag, common_space, common_offset) \
993 if (space == common_space && address == common_offset) { \
994 sink_->PutSection(tag + REFERENCE_SERIALIZATION, "RefSer"); \
995 } else /* NOLINT */
996 COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
997#undef COMMON_REFS_CASE
998 { /* NOLINT */
999 sink_->Put(REFERENCE_SERIALIZATION + space, "RefSer");
1000 sink_->PutInt(address, "address");
Steve Blocka7e24c12009-10-30 11:49:00 +00001001 }
Steve Blockd0582a62009-12-15 09:54:21 +00001002 } else {
1003 sink_->Put(BACKREF_SERIALIZATION + space, "BackRefSer");
1004 sink_->PutInt(address, "address");
Steve Blocka7e24c12009-10-30 11:49:00 +00001005 }
Steve Blockd0582a62009-12-15 09:54:21 +00001006 }
1007 } else {
1008 // Object has not yet been serialized. Serialize it here.
1009 ObjectSerializer serializer(this,
1010 heap_object,
1011 sink_,
1012 reference_representation);
1013 serializer.Serialize();
1014 }
1015}
1016
1017
1018
1019void Serializer::ObjectSerializer::Serialize() {
1020 int space = Serializer::SpaceOfObject(object_);
1021 int size = object_->Size();
1022
1023 if (reference_representation_ == TAGGED_REPRESENTATION) {
1024 sink_->Put(OBJECT_SERIALIZATION + space, "ObjectSerialization");
1025 } else {
1026 CHECK_EQ(CODE_TARGET_REPRESENTATION, reference_representation_);
1027 sink_->Put(CODE_OBJECT_SERIALIZATION + space, "ObjectSerialization");
1028 }
1029 sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
1030
1031 // Mark this object as already serialized.
1032 bool start_new_page;
1033 SerializationAddressMapper::Map(
1034 object_,
1035 serializer_->Allocate(space, size, &start_new_page));
1036 if (start_new_page) {
1037 sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
1038 sink_->PutSection(space, "NewPageSpace");
1039 }
1040
1041 // Serialize the map (first word of the object).
1042 serializer_->SerializeObject(object_->map(), TAGGED_REPRESENTATION);
1043
1044 // Serialize the rest of the object.
1045 CHECK_EQ(0, bytes_processed_so_far_);
1046 bytes_processed_so_far_ = kPointerSize;
1047 object_->IterateBody(object_->map()->instance_type(), size, this);
1048 OutputRawData(object_->address() + size);
1049}
1050
1051
1052void Serializer::ObjectSerializer::VisitPointers(Object** start,
1053 Object** end) {
1054 Object** current = start;
1055 while (current < end) {
1056 while (current < end && (*current)->IsSmi()) current++;
1057 if (current < end) OutputRawData(reinterpret_cast<Address>(current));
1058
1059 while (current < end && !(*current)->IsSmi()) {
1060 serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
1061 bytes_processed_so_far_ += kPointerSize;
1062 current++;
1063 }
1064 }
1065}
1066
1067
1068void Serializer::ObjectSerializer::VisitExternalReferences(Address* start,
1069 Address* end) {
1070 Address references_start = reinterpret_cast<Address>(start);
1071 OutputRawData(references_start);
1072
1073 for (Address* current = start; current < end; current++) {
1074 sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "ExternalReference");
1075 int reference_id = serializer_->EncodeExternalReference(*current);
1076 sink_->PutInt(reference_id, "reference id");
1077 }
1078 bytes_processed_so_far_ += static_cast<int>((end - start) * kPointerSize);
1079}
1080
1081
1082void Serializer::ObjectSerializer::VisitRuntimeEntry(RelocInfo* rinfo) {
1083 Address target_start = rinfo->target_address_address();
1084 OutputRawData(target_start);
1085 Address target = rinfo->target_address();
1086 uint32_t encoding = serializer_->EncodeExternalReference(target);
1087 CHECK(target == NULL ? encoding == 0 : encoding != 0);
1088 sink_->Put(EXTERNAL_BRANCH_TARGET_SERIALIZATION, "ExternalReference");
1089 sink_->PutInt(encoding, "reference id");
1090 bytes_processed_so_far_ += Assembler::kExternalTargetSize;
1091}
1092
1093
1094void Serializer::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
1095 CHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
1096 Address target_start = rinfo->target_address_address();
1097 OutputRawData(target_start);
1098 Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1099 serializer_->SerializeObject(target, CODE_TARGET_REPRESENTATION);
1100 bytes_processed_so_far_ += Assembler::kCallTargetSize;
1101}
1102
1103
1104void Serializer::ObjectSerializer::VisitExternalAsciiString(
1105 v8::String::ExternalAsciiStringResource** resource_pointer) {
1106 Address references_start = reinterpret_cast<Address>(resource_pointer);
1107 OutputRawData(references_start);
1108 for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
1109 Object* source = Heap::natives_source_cache()->get(i);
1110 if (!source->IsUndefined()) {
1111 ExternalAsciiString* string = ExternalAsciiString::cast(source);
1112 typedef v8::String::ExternalAsciiStringResource Resource;
1113 Resource* resource = string->resource();
1114 if (resource == *resource_pointer) {
1115 sink_->Put(NATIVES_STRING_RESOURCE, "NativesStringResource");
1116 sink_->PutSection(i, "NativesStringResourceEnd");
1117 bytes_processed_so_far_ += sizeof(resource);
1118 return;
1119 }
1120 }
1121 }
1122 // One of the strings in the natives cache should match the resource. We
1123 // can't serialize any other kinds of external strings.
1124 UNREACHABLE();
1125}
1126
1127
1128void Serializer::ObjectSerializer::OutputRawData(Address up_to) {
1129 Address object_start = object_->address();
1130 int up_to_offset = static_cast<int>(up_to - object_start);
1131 int skipped = up_to_offset - bytes_processed_so_far_;
1132 // This assert will fail if the reloc info gives us the target_address_address
1133 // locations in a non-ascending order. Luckily that doesn't happen.
1134 ASSERT(skipped >= 0);
1135 if (skipped != 0) {
1136 Address base = object_start + bytes_processed_so_far_;
1137#define RAW_CASE(index, length) \
1138 if (skipped == length) { \
1139 sink_->PutSection(RAW_DATA_SERIALIZATION + index, "RawDataFixed"); \
1140 } else /* NOLINT */
1141 COMMON_RAW_LENGTHS(RAW_CASE)
1142#undef RAW_CASE
1143 { /* NOLINT */
1144 sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
1145 sink_->PutInt(skipped, "length");
1146 }
1147 for (int i = 0; i < skipped; i++) {
1148 unsigned int data = base[i];
1149 sink_->PutSection(data, "Byte");
1150 }
1151 bytes_processed_so_far_ += skipped;
1152 }
1153}
1154
1155
1156int Serializer::SpaceOfObject(HeapObject* object) {
1157 for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
1158 AllocationSpace s = static_cast<AllocationSpace>(i);
1159 if (Heap::InSpace(object, s)) {
1160 if (i == LO_SPACE) {
1161 if (object->IsCode()) {
1162 return kLargeCode;
1163 } else if (object->IsFixedArray()) {
1164 return kLargeFixedArray;
1165 } else {
1166 return kLargeData;
1167 }
1168 }
1169 return i;
1170 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001171 }
1172 UNREACHABLE();
Steve Blockd0582a62009-12-15 09:54:21 +00001173 return 0;
1174}
1175
1176
1177int Serializer::SpaceOfAlreadySerializedObject(HeapObject* object) {
1178 for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
1179 AllocationSpace s = static_cast<AllocationSpace>(i);
1180 if (Heap::InSpace(object, s)) {
1181 return i;
1182 }
1183 }
1184 UNREACHABLE();
1185 return 0;
1186}
1187
1188
1189int Serializer::Allocate(int space, int size, bool* new_page) {
1190 CHECK(space >= 0 && space < kNumberOfSpaces);
1191 if (SpaceIsLarge(space)) {
1192 // In large object space we merely number the objects instead of trying to
1193 // determine some sort of address.
1194 *new_page = true;
1195 return fullness_[LO_SPACE]++;
1196 }
1197 *new_page = false;
1198 if (fullness_[space] == 0) {
1199 *new_page = true;
1200 }
1201 if (SpaceIsPaged(space)) {
1202 // Paged spaces are a little special. We encode their addresses as if the
1203 // pages were all contiguous and each page were filled up in the range
1204 // 0 - Page::kObjectAreaSize. In practice the pages may not be contiguous
1205 // and allocation does not start at offset 0 in the page, but this scheme
1206 // means the deserializer can get the page number quickly by shifting the
1207 // serialized address.
1208 CHECK(IsPowerOf2(Page::kPageSize));
1209 int used_in_this_page = (fullness_[space] & (Page::kPageSize - 1));
1210 CHECK(size <= Page::kObjectAreaSize);
1211 if (used_in_this_page + size > Page::kObjectAreaSize) {
1212 *new_page = true;
1213 fullness_[space] = RoundUp(fullness_[space], Page::kPageSize);
1214 }
1215 }
1216 int allocation_address = fullness_[space];
1217 fullness_[space] = allocation_address + size;
1218 return allocation_address;
Steve Blocka7e24c12009-10-30 11:49:00 +00001219}
1220
1221
1222} } // namespace v8::internal