| Index: src/serialize.cc
|
| diff --git a/src/serialize.cc b/src/serialize.cc
|
| index 86348aefee917c2c921fb806bf2d8df2f599e024..a01c8b854828c80325c8d53563a8d52e4ab3ba64 100644
|
| --- a/src/serialize.cc
|
| +++ b/src/serialize.cc
|
| @@ -635,6 +635,11 @@ void Deserializer::FlushICacheForNewCodeObjects() {
|
|
|
|
|
| bool Deserializer::ReserveSpace() {
|
| +#ifdef DEBUG
|
| + for (int i = NEW_SPACE; i < kNumberOfSpaces; ++i) {
|
| + CHECK(reservations_[i].length() > 0);
|
| + }
|
| +#endif // DEBUG
|
| if (!isolate_->heap()->ReserveSpace(reservations_)) return false;
|
| for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
|
| high_water_[i] = reservations_[i][0].start;
|
| @@ -643,16 +648,22 @@ bool Deserializer::ReserveSpace() {
|
| }
|
|
|
|
|
| -void Deserializer::Deserialize(Isolate* isolate) {
|
| +void Deserializer::Initialize(Isolate* isolate) {
|
| + DCHECK_EQ(NULL, isolate_);
|
| + DCHECK_NE(NULL, isolate);
|
| isolate_ = isolate;
|
| - DCHECK(isolate_ != NULL);
|
| + DCHECK_EQ(NULL, external_reference_decoder_);
|
| + external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
|
| +}
|
| +
|
| +
|
| +void Deserializer::Deserialize(Isolate* isolate) {
|
| + Initialize(isolate);
|
| if (!ReserveSpace()) FatalProcessOutOfMemory("deserializing context");
|
| // No active threads.
|
| DCHECK_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse());
|
| // No active handles.
|
| DCHECK(isolate_->handle_scope_implementer()->blocks()->is_empty());
|
| - DCHECK_EQ(NULL, external_reference_decoder_);
|
| - external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
|
| isolate_->heap()->IterateSmiRoots(this);
|
| isolate_->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG);
|
| isolate_->heap()->RepairFreeListsAfterBoot();
|
| @@ -688,33 +699,46 @@ void Deserializer::Deserialize(Isolate* isolate) {
|
| }
|
|
|
|
|
| -void Deserializer::DeserializePartial(Isolate* isolate, Object** root,
|
| - OnOOM on_oom) {
|
| - isolate_ = isolate;
|
| - for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
|
| - DCHECK(reservations_[i].length() > 0);
|
| - }
|
| +MaybeHandle<Object> Deserializer::DeserializePartial(
|
| + Isolate* isolate, Handle<FixedArray>* outdated_contexts_out) {
|
| + Initialize(isolate);
|
| if (!ReserveSpace()) {
|
| - if (on_oom == FATAL_ON_OOM) FatalProcessOutOfMemory("deserialize context");
|
| - *root = NULL;
|
| - return;
|
| - }
|
| - if (external_reference_decoder_ == NULL) {
|
| - external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
|
| + FatalProcessOutOfMemory("deserialize context");
|
| + return MaybeHandle<Object>();
|
| }
|
|
|
| DisallowHeapAllocation no_gc;
|
| -
|
| // Keep track of the code space start and end pointers in case new
|
| // code objects were unserialized
|
| OldSpace* code_space = isolate_->heap()->code_space();
|
| Address start_address = code_space->top();
|
| - VisitPointer(root);
|
| + Object* root;
|
| + Object* outdated_contexts;
|
| + VisitPointer(&root);
|
| + VisitPointer(&outdated_contexts);
|
|
|
| // There's no code deserialized here. If this assert fires
|
| // then that's changed and logging should be added to notify
|
| // the profiler et al of the new code.
|
| CHECK_EQ(start_address, code_space->top());
|
| + CHECK(outdated_contexts->IsFixedArray());
|
| + *outdated_contexts_out =
|
| + Handle<FixedArray>(FixedArray::cast(outdated_contexts), isolate);
|
| + return Handle<Object>(root, isolate);
|
| +}
|
| +
|
| +
|
| +MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode(
|
| + Isolate* isolate) {
|
| + Initialize(isolate);
|
| + if (!ReserveSpace()) {
|
| + return Handle<SharedFunctionInfo>();
|
| + } else {
|
| + DisallowHeapAllocation no_gc;
|
| + Object* root;
|
| + VisitPointer(&root);
|
| + return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(root));
|
| + }
|
| }
|
|
|
|
|
| @@ -1371,12 +1395,41 @@ void StartupSerializer::VisitPointers(Object** start, Object** end) {
|
| }
|
|
|
|
|
| -void PartialSerializer::Serialize(Object** object) {
|
| - this->VisitPointer(object);
|
| +void PartialSerializer::Serialize(Object** o) {
|
| + if ((*o)->IsContext()) global_object_ = Context::cast(*o)->global_object();
|
| + VisitPointer(o);
|
| + SerializeOutdatedContextsAsFixedArray();
|
| Pad();
|
| }
|
|
|
|
|
| +void PartialSerializer::SerializeOutdatedContextsAsFixedArray() {
|
| + int length = outdated_contexts_.length();
|
| + if (length == 0) {
|
| + FixedArray* empty = isolate_->heap()->empty_fixed_array();
|
| + SerializeObject(empty, kPlain, kStartOfObject, 0);
|
| + } else {
|
| + // Serialize an imaginary fixed array containing outdated contexts.
|
| + int size = FixedArray::SizeFor(length);
|
| + Allocate(NEW_SPACE, size);
|
| + sink_->Put(kNewObject + NEW_SPACE, "emulated FixedArray");
|
| + sink_->PutInt(size >> kObjectAlignmentBits, "FixedArray size in words");
|
| + Map* map = isolate_->heap()->fixed_array_map();
|
| + SerializeObject(map, kPlain, kStartOfObject, 0);
|
| + Smi* length_smi = Smi::FromInt(length);
|
| + sink_->Put(kOnePointerRawData, "Smi");
|
| + for (int i = 0; i < kPointerSize; i++) {
|
| + sink_->Put(reinterpret_cast<byte*>(&length_smi)[i], "Byte");
|
| + }
|
| + for (int i = 0; i < length; i++) {
|
| + BackReference back_ref = outdated_contexts_[i];
|
| + sink_->Put(kBackref + back_ref.space(), "BackRef");
|
| + sink_->PutInt(back_ref.reference(), "BackRefValue");
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| bool Serializer::ShouldBeSkipped(Object** current) {
|
| Object** roots = isolate()->heap()->roots_array_start();
|
| return current == &roots[Heap::kStoreBufferTopRootIndex]
|
| @@ -1633,6 +1686,15 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
| // Object has not yet been serialized. Serialize it here.
|
| ObjectSerializer serializer(this, obj, sink_, how_to_code, where_to_point);
|
| serializer.Serialize();
|
| +
|
| + if (obj->IsContext() &&
|
| + Context::cast(obj)->global_object() == global_object_) {
|
| + // Context refers to the current global object. This reference will
|
| + // become outdated after deserialization.
|
| + BackReference back_reference = back_reference_map_.Lookup(obj);
|
| + DCHECK(back_reference.is_valid());
|
| + outdated_contexts_.Add(back_reference);
|
| + }
|
| }
|
|
|
|
|
| @@ -2276,52 +2338,47 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
| base::ElapsedTimer timer;
|
| if (FLAG_profile_deserialization) timer.Start();
|
|
|
| - Object* root;
|
| + HandleScope scope(isolate);
|
|
|
| - {
|
| - HandleScope scope(isolate);
|
| + SmartPointer<SerializedCodeData> scd(
|
| + SerializedCodeData::FromCachedData(cached_data, *source));
|
| + if (scd.is_empty()) {
|
| + if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
|
| + DCHECK(cached_data->rejected());
|
| + return MaybeHandle<SharedFunctionInfo>();
|
| + }
|
|
|
| - SmartPointer<SerializedCodeData> scd(
|
| - SerializedCodeData::FromCachedData(cached_data, *source));
|
| - if (scd.is_empty()) {
|
| - if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
|
| - DCHECK(cached_data->rejected());
|
| - return MaybeHandle<SharedFunctionInfo>();
|
| - }
|
| + // Eagerly expand string table to avoid allocations during deserialization.
|
| + StringTable::EnsureCapacityForDeserialization(isolate,
|
| + scd->NumInternalizedStrings());
|
|
|
| - // Eagerly expand string table to avoid allocations during deserialization.
|
| - StringTable::EnsureCapacityForDeserialization(
|
| - isolate, scd->NumInternalizedStrings());
|
| -
|
| - // Prepare and register list of attached objects.
|
| - Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys();
|
| - Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
|
| - code_stub_keys.length() + kCodeStubsBaseIndex);
|
| - attached_objects[kSourceObjectIndex] = source;
|
| - for (int i = 0; i < code_stub_keys.length(); i++) {
|
| - attached_objects[i + kCodeStubsBaseIndex] =
|
| - CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
|
| - }
|
| + // Prepare and register list of attached objects.
|
| + Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys();
|
| + Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
|
| + code_stub_keys.length() + kCodeStubsBaseIndex);
|
| + attached_objects[kSourceObjectIndex] = source;
|
| + for (int i = 0; i < code_stub_keys.length(); i++) {
|
| + attached_objects[i + kCodeStubsBaseIndex] =
|
| + CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
|
| + }
|
|
|
| - Deserializer deserializer(scd.get());
|
| - deserializer.SetAttachedObjects(&attached_objects);
|
| + Deserializer deserializer(scd.get());
|
| + deserializer.SetAttachedObjects(&attached_objects);
|
|
|
| - // Deserialize.
|
| - deserializer.DeserializePartial(isolate, &root, Deserializer::NULL_ON_OOM);
|
| - if (root == NULL) {
|
| - // Deserializing may fail if the reservations cannot be fulfilled.
|
| - if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
|
| - return MaybeHandle<SharedFunctionInfo>();
|
| - }
|
| - deserializer.FlushICacheForNewCodeObjects();
|
| + // Deserialize.
|
| + Handle<SharedFunctionInfo> result;
|
| + if (!deserializer.DeserializeCode(isolate).ToHandle(&result)) {
|
| + // Deserializing may fail if the reservations cannot be fulfilled.
|
| + if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
|
| + return MaybeHandle<SharedFunctionInfo>();
|
| }
|
| + deserializer.FlushICacheForNewCodeObjects();
|
|
|
| if (FLAG_profile_deserialization) {
|
| double ms = timer.Elapsed().InMillisecondsF();
|
| int length = cached_data->length();
|
| PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms);
|
| }
|
| - Handle<SharedFunctionInfo> result(SharedFunctionInfo::cast(root), isolate);
|
| result->set_deserialized(true);
|
|
|
| if (isolate->logger()->is_logging_code_events() ||
|
| @@ -2335,7 +2392,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
| *result, NULL, name);
|
| }
|
|
|
| - return result;
|
| + return scope.CloseAndEscape(result);
|
| }
|
|
|
|
|
|
|