Index: src/serialize.cc |
diff --git a/src/serialize.cc b/src/serialize.cc |
index 5e6de03f63dd53ab4be51f08908084b0b309e3b8..c9e656637385a9f8f9e62560d70093646b04b60e 100644 |
--- a/src/serialize.cc |
+++ b/src/serialize.cc |
@@ -481,6 +481,25 @@ ExternalReferenceDecoder::~ExternalReferenceDecoder() { |
} |
+RootIndexMap::RootIndexMap(Isolate* isolate) { |
+ map_ = new HashMap(HashMap::PointersMatch); |
+ Object** root_array = isolate->heap()->roots_array_start(); |
+ for (int i = 0; i < Heap::kStrongRootListLength; i++) { |
+ Object* root = root_array[i]; |
+ if (root->IsHeapObject() && !isolate->heap()->InNewSpace(root)) { |
+ HeapObject* heap_object = HeapObject::cast(root); |
+ if (LookupEntry(map_, heap_object, false) != NULL) { |
+ // Some root values are initialized to the empty FixedArray(); |
+ // Do not add them to the map. |
+ DCHECK_EQ(isolate->heap()->empty_fixed_array(), heap_object); |
+ } else { |
+ SetValue(LookupEntry(map_, heap_object, true), i); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
class CodeAddressMap: public CodeEventLogger { |
public: |
explicit CodeAddressMap(Isolate* isolate) |
@@ -1237,7 +1256,7 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink) |
: isolate_(isolate), |
sink_(sink), |
external_reference_encoder_(new ExternalReferenceEncoder(isolate)), |
- root_index_wave_front_(0), |
+ root_index_map_(isolate), |
code_address_map_(NULL), |
seen_large_objects_index_(0) { |
// The serializer is meant to be used only to generate initial heap images |
@@ -1267,6 +1286,27 @@ void StartupSerializer::SerializeStrongReferences() { |
} |
+void StartupSerializer::VisitPointers(Object** start, Object** end) { |
+ for (Object** current = start; current < end; current++) { |
+ if (start == isolate()->heap()->roots_array_start()) { |
+ root_index_wave_front_ = |
+ Max(root_index_wave_front_, static_cast<intptr_t>(current - start)); |
+ } |
+ if (ShouldBeSkipped(current)) { |
+ sink_->Put(kSkip, "Skip"); |
+ sink_->PutInt(kPointerSize, "SkipOneWord"); |
+ } else if ((*current)->IsSmi()) { |
+ sink_->Put(kRawData + 1, "Smi"); |
+ for (int i = 0; i < kPointerSize; i++) { |
+ sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte"); |
+ } |
+ } else { |
+ SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject, 0); |
+ } |
+ } |
+} |
+ |
+ |
void PartialSerializer::Serialize(Object** object) { |
this->VisitPointer(object); |
Pad(); |
@@ -1282,23 +1322,14 @@ bool Serializer::ShouldBeSkipped(Object** current) { |
void Serializer::VisitPointers(Object** start, Object** end) { |
- Isolate* isolate = this->isolate();; |
- |
for (Object** current = start; current < end; current++) { |
- if (start == isolate->heap()->roots_array_start()) { |
- root_index_wave_front_ = |
- Max(root_index_wave_front_, static_cast<intptr_t>(current - start)); |
- } |
- if (ShouldBeSkipped(current)) { |
- sink_->Put(kSkip, "Skip"); |
- sink_->PutInt(kPointerSize, "SkipOneWord"); |
- } else if ((*current)->IsSmi()) { |
+ if ((*current)->IsSmi()) { |
sink_->Put(kRawData + 1, "Smi"); |
for (int i = 0; i < kPointerSize; i++) { |
sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte"); |
} |
} else { |
- SerializeObject(*current, kPlain, kStartOfObject, 0); |
+ SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject, 0); |
} |
} |
} |
@@ -1368,29 +1399,14 @@ int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) { |
} |
-int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) { |
- Heap* heap = isolate()->heap(); |
- if (heap->InNewSpace(heap_object)) return kInvalidRootIndex; |
- for (int i = 0; i < root_index_wave_front_; i++) { |
- Object* root = heap->roots_array_start()[i]; |
- if (!root->IsSmi() && root == heap_object) { |
- return i; |
- } |
- } |
- return kInvalidRootIndex; |
-} |
- |
- |
// Encode the location of an already deserialized object in order to write its |
// location into a later object. We can encode the location as an offset from |
// the start of the deserialized objects or as an offset backwards from the |
// current allocation pointer. |
-void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, |
- HowToCode how_to_code, |
- WhereToPoint where_to_point, |
- int skip) { |
- int space = SpaceOfObject(heap_object); |
- |
+void Serializer::SerializeBackReference(BackReference back_reference, |
+ HowToCode how_to_code, |
+ WhereToPoint where_to_point, int skip) { |
+ AllocationSpace space = back_reference.space(); |
if (skip == 0) { |
sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer"); |
} else { |
@@ -1399,50 +1415,39 @@ void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, |
sink_->PutInt(skip, "BackRefSkipDistance"); |
} |
- if (space == LO_SPACE) { |
- int index = address_mapper_.MappedTo(heap_object); |
- sink_->PutInt(index, "large object index"); |
- } else { |
- uint32_t existing_allocation = address_mapper_.MappedTo(heap_object); |
- // Shift out the bits that are always 0. |
- existing_allocation >>= kObjectAlignmentBits; |
- sink_->PutInt(existing_allocation, "allocation"); |
- } |
+ sink_->PutInt(back_reference.reference(), |
+ (space == LO_SPACE) ? "large object index" : "allocation"); |
} |
-void StartupSerializer::SerializeObject( |
- Object* o, |
- HowToCode how_to_code, |
- WhereToPoint where_to_point, |
- int skip) { |
- CHECK(o->IsHeapObject()); |
- HeapObject* heap_object = HeapObject::cast(o); |
- DCHECK(!heap_object->IsJSFunction()); |
+void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, |
+ WhereToPoint where_to_point, int skip) { |
+ DCHECK(!obj->IsJSFunction()); |
- int root_index; |
- if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) { |
- PutRoot(root_index, heap_object, how_to_code, where_to_point, skip); |
+ int root_index = root_index_map_.Lookup(obj); |
+ // We can only encode roots as such if it has already been serialized. |
+ // That applies to root indices below the wave front. |
+ if (root_index != RootIndexMap::kInvalidRootIndex && |
+ root_index < root_index_wave_front_) { |
+ PutRoot(root_index, obj, how_to_code, where_to_point, skip); |
return; |
} |
- if (address_mapper_.IsMapped(heap_object)) { |
- SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, |
- skip); |
- } else { |
- if (skip != 0) { |
- sink_->Put(kSkip, "FlushPendingSkip"); |
- sink_->PutInt(skip, "SkipDistance"); |
- } |
+ BackReference back_reference = back_reference_map_.Lookup(obj); |
+ if (back_reference.is_valid()) { |
+ SerializeBackReference(back_reference, how_to_code, where_to_point, skip); |
+ return; |
+ } |
- // Object has not yet been serialized. Serialize it here. |
- ObjectSerializer object_serializer(this, |
- heap_object, |
- sink_, |
- how_to_code, |
- where_to_point); |
- object_serializer.Serialize(); |
+ if (skip != 0) { |
+ sink_->Put(kSkip, "FlushPendingSkip"); |
+ sink_->PutInt(skip, "SkipDistance"); |
} |
+ |
+ // Object has not yet been serialized. Serialize it here. |
+ ObjectSerializer object_serializer(this, obj, sink_, how_to_code, |
+ where_to_point); |
+ object_serializer.Serialize(); |
} |
@@ -1487,34 +1492,27 @@ void Serializer::PutRoot(int root_index, |
} |
-void PartialSerializer::SerializeObject( |
- Object* o, |
- HowToCode how_to_code, |
- WhereToPoint where_to_point, |
- int skip) { |
- CHECK(o->IsHeapObject()); |
- HeapObject* heap_object = HeapObject::cast(o); |
- |
- if (heap_object->IsMap()) { |
+void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, |
+ WhereToPoint where_to_point, int skip) { |
+ if (obj->IsMap()) { |
// The code-caches link to context-specific code objects, which |
// the startup and context serializes cannot currently handle. |
- DCHECK(Map::cast(heap_object)->code_cache() == |
- heap_object->GetHeap()->empty_fixed_array()); |
+ DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array()); |
} |
- int root_index; |
- if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) { |
- PutRoot(root_index, heap_object, how_to_code, where_to_point, skip); |
+ int root_index = root_index_map_.Lookup(obj); |
+ if (root_index != RootIndexMap::kInvalidRootIndex) { |
+ PutRoot(root_index, obj, how_to_code, where_to_point, skip); |
return; |
} |
- if (ShouldBeInThePartialSnapshotCache(heap_object)) { |
+ if (ShouldBeInThePartialSnapshotCache(obj)) { |
if (skip != 0) { |
sink_->Put(kSkip, "SkipFromSerializeObject"); |
sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); |
} |
- int cache_index = PartialSnapshotCacheIndex(heap_object); |
+ int cache_index = PartialSnapshotCacheIndex(obj); |
sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point, |
"PartialSnapshotCache"); |
sink_->PutInt(cache_index, "partial_snapshot_cache_index"); |
@@ -1524,32 +1522,29 @@ void PartialSerializer::SerializeObject( |
// Pointers from the partial snapshot to the objects in the startup snapshot |
// should go through the root array or through the partial snapshot cache. |
// If this is not the case you may have to add something to the root array. |
- DCHECK(!startup_serializer_->address_mapper()->IsMapped(heap_object)); |
+ DCHECK(!startup_serializer_->back_reference_map()->Lookup(obj).is_valid()); |
// All the internalized strings that the partial snapshot needs should be |
// either in the root table or in the partial snapshot cache. |
- DCHECK(!heap_object->IsInternalizedString()); |
+ DCHECK(!obj->IsInternalizedString()); |
- if (address_mapper_.IsMapped(heap_object)) { |
- SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, |
- skip); |
- } else { |
- if (skip != 0) { |
- sink_->Put(kSkip, "SkipFromSerializeObject"); |
- sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); |
- } |
- // Object has not yet been serialized. Serialize it here. |
- ObjectSerializer serializer(this, |
- heap_object, |
- sink_, |
- how_to_code, |
- where_to_point); |
- serializer.Serialize(); |
+ BackReference back_reference = back_reference_map_.Lookup(obj); |
+ if (back_reference.is_valid()) { |
+ SerializeBackReference(back_reference, how_to_code, where_to_point, skip); |
+ return; |
} |
+ |
+ if (skip != 0) { |
+ sink_->Put(kSkip, "SkipFromSerializeObject"); |
+ sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); |
+ } |
+ // Object has not yet been serialized. Serialize it here. |
+ ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point); |
+ serializer.Serialize(); |
} |
-void Serializer::ObjectSerializer::SerializePrologue(int space, int size, |
- Map* map) { |
+void Serializer::ObjectSerializer::SerializePrologue(AllocationSpace space, |
+ int size, Map* map) { |
sink_->Put(kNewObject + reference_representation_ + space, |
"ObjectSerialization"); |
sink_->PutInt(size >> kObjectAlignmentBits, "Size in words"); |
@@ -1564,18 +1559,18 @@ void Serializer::ObjectSerializer::SerializePrologue(int space, int size, |
} |
// Mark this object as already serialized. |
+ BackReference back_reference; |
if (space == LO_SPACE) { |
if (object_->IsCode()) { |
sink_->Put(EXECUTABLE, "executable large object"); |
} else { |
sink_->Put(NOT_EXECUTABLE, "not executable large object"); |
} |
- int index = serializer_->AllocateLargeObject(size); |
- serializer_->address_mapper()->AddMapping(object_, index); |
+ back_reference = serializer_->AllocateLargeObject(size); |
} else { |
- int allocation = serializer_->Allocate(space, size); |
- serializer_->address_mapper()->AddMapping(object_, allocation); |
+ back_reference = serializer_->Allocate(space, size); |
} |
+ serializer_->back_reference_map()->Add(object_, back_reference); |
// Serialize the map (first word of the object). |
serializer_->SerializeObject(map, kPlain, kStartOfObject, 0); |
@@ -1605,7 +1600,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() { |
ExternalTwoByteString::cast(string)->resource()->data()); |
} |
- int space = |
+ AllocationSpace space = |
(size > Page::kMaxRegularHeapObjectSize) ? LO_SPACE : OLD_DATA_SPACE; |
SerializePrologue(space, size, map); |
@@ -1670,12 +1665,11 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start, |
while (current < end && !(*current)->IsSmi()) { |
HeapObject* current_contents = HeapObject::cast(*current); |
- int root_index = serializer_->RootIndex(current_contents, kPlain); |
+ int root_index = serializer_->root_index_map()->Lookup(current_contents); |
// Repeats are not subject to the write barrier so there are only some |
// objects that can be used in a repeat encoding. These are the early |
// ones in the root array that are never in new space. |
Erik Corry
2014/10/23 12:57:15
I think now this is _all_ the entries in the root
|
- if (current != start && |
- root_index != kInvalidRootIndex && |
+ if (current != start && root_index != RootIndexMap::kInvalidRootIndex && |
root_index < kRootArrayNumberOfConstantEncodings && |
current_contents == current[-1]) { |
DCHECK(!serializer_->isolate()->heap()->InNewSpace(current_contents)); |
@@ -1711,7 +1705,8 @@ void Serializer::ObjectSerializer::VisitEmbeddedPointer(RelocInfo* rinfo) { |
kCanReturnSkipInsteadOfSkipping); |
HowToCode how_to_code = rinfo->IsCodedSpecially() ? kFromCode : kPlain; |
Object* object = rinfo->target_object(); |
- serializer_->SerializeObject(object, how_to_code, kStartOfObject, skip); |
+ serializer_->SerializeObject(HeapObject::cast(object), how_to_code, |
+ kStartOfObject, skip); |
bytes_processed_so_far_ += rinfo->target_address_size(); |
} |
@@ -1887,32 +1882,31 @@ int Serializer::ObjectSerializer::OutputRawData( |
} |
-int Serializer::SpaceOfObject(HeapObject* object) { |
+AllocationSpace Serializer::SpaceOfObject(HeapObject* object) { |
for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) { |
AllocationSpace s = static_cast<AllocationSpace>(i); |
if (object->GetHeap()->InSpace(object, s)) { |
DCHECK(i < kNumberOfSpaces); |
- return i; |
+ return s; |
} |
} |
UNREACHABLE(); |
- return 0; |
+ return INVALID_SPACE; |
} |
-uint32_t Serializer::AllocateLargeObject(int size) { |
+BackReference Serializer::AllocateLargeObject(int size) { |
// Large objects are allocated one-by-one when deserializing. We do not |
// have to keep track of multiple chunks. |
pending_chunk_[LO_SPACE] += size; |
- return seen_large_objects_index_++; |
+ return BackReference(LO_SPACE, 0, seen_large_objects_index_++); |
} |
-uint32_t Serializer::Allocate(int space, int size) { |
+BackReference Serializer::Allocate(AllocationSpace space, int size) { |
CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces); |
DCHECK(size > 0 && size < Page::kMaxRegularHeapObjectSize); |
uint32_t new_chunk_size = pending_chunk_[space] + size; |
- uint32_t allocation; |
if (new_chunk_size > static_cast<uint32_t>(Page::kMaxRegularHeapObjectSize)) { |
// The new chunk size would not fit onto a single page. Complete the |
// current chunk and start a new one. |
@@ -1920,12 +1914,9 @@ uint32_t Serializer::Allocate(int space, int size) { |
pending_chunk_[space] = 0; |
new_chunk_size = size; |
} |
- // For back-referencing, each allocation is encoded as a combination |
- // of chunk index and offset inside the chunk. |
- allocation = ChunkIndexBits::encode(completed_chunks_[space].length()) | |
- OffsetBits::encode(pending_chunk_[space]); |
+ uint32_t offset = pending_chunk_[space]; |
pending_chunk_[space] = new_chunk_size; |
- return allocation; |
+ return BackReference(space, completed_chunks_[space].length(), offset); |
} |
@@ -1979,6 +1970,13 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, |
cs.Pad(); |
cs.FinalizeAllocation(); |
+ for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { |
+ // Fail if any chunk index exceeds the limit. |
+ if (cs.FinalAllocationChunks(i).length() > BackReference::kMaxChunkIndex) { |
+ return NULL; |
+ } |
+ } |
+ |
SerializedCodeData data(&payload, &cs); |
ScriptData* script_data = data.GetScriptData(); |
@@ -1992,27 +1990,25 @@ ScriptData* CodeSerializer::Serialize(Isolate* isolate, |
} |
-void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, |
+void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, |
WhereToPoint where_to_point, int skip) { |
- HeapObject* heap_object = HeapObject::cast(o); |
- |
- int root_index; |
- if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) { |
+ int root_index = root_index_map_.Lookup(obj); |
+ if (root_index != RootIndexMap::kInvalidRootIndex) { |
if (FLAG_serializer_trace_level > 0) { |
PrintF(" Encoding root: %d\n", root_index); |
} |
- PutRoot(root_index, heap_object, how_to_code, where_to_point, skip); |
+ PutRoot(root_index, obj, how_to_code, where_to_point, skip); |
return; |
} |
- if (address_mapper_.IsMapped(heap_object)) { |
+ BackReference back_reference = back_reference_map_.Lookup(obj); |
+ if (back_reference.is_valid()) { |
if (FLAG_serializer_trace_level > 0) { |
PrintF(" Encoding back reference to: "); |
- heap_object->ShortPrint(); |
+ obj->ShortPrint(); |
PrintF("\n"); |
} |
- SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point, |
- skip); |
+ SerializeBackReference(back_reference, how_to_code, where_to_point, skip); |
return; |
} |
@@ -2021,8 +2017,8 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, |
sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); |
} |
- if (heap_object->IsCode()) { |
- Code* code_object = Code::cast(heap_object); |
+ if (obj->IsCode()) { |
+ Code* code_object = Code::cast(obj); |
switch (code_object->kind()) { |
case Code::OPTIMIZED_FUNCTION: // No optimized code compiled yet. |
case Code::HANDLER: // No handlers patched in yet. |
@@ -2049,32 +2045,32 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, |
SerializeBuiltin(Builtins::kCompileLazy, how_to_code, where_to_point); |
} else { |
code_object->MakeYoung(); |
- SerializeHeapObject(code_object, how_to_code, where_to_point); |
+ SerializeGeneric(code_object, how_to_code, where_to_point); |
} |
return; |
} |
UNREACHABLE(); |
} |
- if (heap_object == source_) { |
+ if (obj == source_) { |
SerializeSourceObject(how_to_code, where_to_point); |
return; |
} |
// Past this point we should not see any (context-specific) maps anymore. |
- CHECK(!heap_object->IsMap()); |
+ CHECK(!obj->IsMap()); |
// There should be no references to the global object embedded. |
- CHECK(!heap_object->IsJSGlobalProxy() && !heap_object->IsGlobalObject()); |
+ CHECK(!obj->IsJSGlobalProxy() && !obj->IsGlobalObject()); |
// There should be no hash table embedded. They would require rehashing. |
- CHECK(!heap_object->IsHashTable()); |
+ CHECK(!obj->IsHashTable()); |
- SerializeHeapObject(heap_object, how_to_code, where_to_point); |
+ SerializeGeneric(obj, how_to_code, where_to_point); |
} |
-void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, |
- HowToCode how_to_code, |
- WhereToPoint where_to_point) { |
+void CodeSerializer::SerializeGeneric(HeapObject* heap_object, |
+ HowToCode how_to_code, |
+ WhereToPoint where_to_point) { |
if (FLAG_serializer_trace_level > 0) { |
PrintF(" Encoding heap object: "); |
heap_object->ShortPrint(); |
@@ -2161,7 +2157,7 @@ void CodeSerializer::SerializeIC(Code* ic, HowToCode how_to_code, |
PrintF(" %s has no special handling\n", Code::Kind2String(ic->kind())); |
} |
DCHECK(ic->kind() == Code::LOAD_IC || ic->kind() == Code::STORE_IC); |
- SerializeHeapObject(ic, how_to_code, where_to_point); |
+ SerializeGeneric(ic, how_to_code, where_to_point); |
} |
@@ -2243,7 +2239,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( |
SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs) |
- : owns_script_data_(true) { |
+ : script_data_(NULL), owns_script_data_(true) { |
DisallowHeapAllocation no_gc; |
List<uint32_t>* stub_keys = cs->stub_keys(); |