Chromium Code Reviews| Index: src/heap.cc |
| diff --git a/src/heap.cc b/src/heap.cc |
| index e1090176c9709d9815a3e1c1fdca4f758eeeab84..752d0dd0965e7de5693d1f2f8ad4ea8e54a1a516 100644 |
| --- a/src/heap.cc |
| +++ b/src/heap.cc |
| @@ -550,6 +550,8 @@ void Heap::GarbageCollectionEpilogue() { |
| #ifdef ENABLE_DEBUGGER_SUPPORT |
| isolate_->debug()->AfterGarbageCollection(); |
| #endif // ENABLE_DEBUGGER_SUPPORT |
| + |
| + error_object_list_.DeferredFormatStackTrace(isolate()); |
| } |
| @@ -1348,6 +1350,8 @@ void Heap::Scavenge() { |
| UpdateNewSpaceReferencesInExternalStringTable( |
| &UpdateNewSpaceReferenceInExternalStringTableEntry); |
| + error_object_list_.UpdateReferencesInNewSpace(this); |
| + |
| promotion_queue_.Destroy(); |
| LiveObjectList::UpdateReferencesForScavengeGC(); |
| @@ -5913,6 +5917,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { |
| mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { |
| // Scavenge collections have special processing for this. |
| external_string_table_.Iterate(v); |
| + error_object_list_.Iterate(v); |
| } |
| v->Synchronize(VisitorSynchronization::kExternalStringsTable); |
| } |
| @@ -6453,6 +6458,8 @@ void Heap::TearDown() { |
| external_string_table_.TearDown(); |
| + error_object_list_.TearDown(); |
| + |
| new_space_.TearDown(); |
| if (old_pointer_space_ != NULL) { |
| @@ -7358,6 +7365,8 @@ void ExternalStringTable::CleanUp() { |
| } |
| } |
| new_space_strings_.Rewind(last); |
| + new_space_strings_.Trim(); |
| + |
| last = 0; |
| for (int i = 0; i < old_space_strings_.length(); ++i) { |
| if (old_space_strings_[i] == heap_->the_hole_value()) { |
| @@ -7367,6 +7376,7 @@ void ExternalStringTable::CleanUp() { |
| old_space_strings_[last++] = old_space_strings_[i]; |
| } |
| old_space_strings_.Rewind(last); |
| + old_space_strings_.Trim(); |
| #ifdef VERIFY_HEAP |
| if (FLAG_verify_heap) { |
| Verify(); |
| @@ -7381,6 +7391,102 @@ void ExternalStringTable::TearDown() { |
| } |
| +// Update all references. |
| +void ErrorObjectList::UpdateReferences() { |
| + for (int i = 0; i < list_.length(); i++) { |
| + HeapObject* object = HeapObject::cast(list_[i]); |
| + MapWord first_word = object->map_word(); |
| + if (first_word.IsForwardingAddress()) { |
| + list_[i] = first_word.ToForwardingAddress(); |
| + } |
| + } |
| +} |
| + |
| + |
| +// Unforwarded objects in new space are dead and removed from the list. |
| +void ErrorObjectList::UpdateReferencesInNewSpace(Heap* heap) { |
| + if (!nested_) { |
| + int write_index = 0; |
| + for (int i = 0; i < list_.length(); i++) { |
| + MapWord first_word = HeapObject::cast(list_[i])->map_word(); |
| + if (first_word.IsForwardingAddress()) { |
| + list_[write_index++] = first_word.ToForwardingAddress(); |
| + } |
| + } |
| + list_.Rewind(write_index); |
| + } else { |
| + // If a GC is triggered during DeferredFormatStackTrace, we do not move |
| + // objects in the list, just remove dead ones, as to not confuse the |
| + // loop in DeferredFormatStackTrace. |
| + for (int i = 0; i < list_.length(); i++) { |
| + MapWord first_word = HeapObject::cast(list_[i])->map_word(); |
| + list_[i] = first_word.IsForwardingAddress() |
| + ? first_word.ToForwardingAddress() |
| + : heap->the_hole_value(); |
| + } |
| + } |
| +} |
| + |
| + |
| +void ErrorObjectList::DeferredFormatStackTrace(Isolate* isolate) { |
| + // If formatting the stack trace causes a GC, this method will be |
| + // recursively called. In that case, skip the recursive call, since |
| + // the loop modifies the list while iterating over it. |
| + if (nested_) return; |
| + nested_ = true; |
| + HandleScope scope(isolate); |
| + Handle<String> stack_key = isolate->factory()->stack_symbol(); |
| + int write_index = 0; |
| + int budget = kBudgetPerGC; |
| + for (int i = 0; i < list_.length(); i++) { |
| + Object* object = list_[i]; |
| + // Skip possible holes in the list. |
| + if (object->IsTheHole()) continue; |
| + if (isolate->heap()->InNewSpace(object) || budget == 0) { |
| + list_[write_index++] = object; |
| + continue; |
| + } |
| + |
| + // Fire the stack property getter, if it is a getter defined in native code. |
| + LookupResult lookup(isolate); |
| + JSObject::cast(object)->LocalLookupRealNamedProperty(*stack_key, &lookup); |
| + if (!lookup.IsFound() || lookup.type() != CALLBACKS) continue; |
| + Object* callback = lookup.GetCallbackObject(); |
| + if (!callback->IsAccessorPair()) continue; |
| + Object* getter_obj = AccessorPair::cast(callback)->getter(); |
| + if (!getter_obj->IsJSFunction()) continue; |
| + JSFunction* getter_fun = JSFunction::cast(getter_obj); |
| + if (!getter_fun->shared()->native()) continue; |
|
Vyacheslav Egorov (Google)
2012/11/20 17:30:42
I don't think this can guard you well enough. Here
|
| + bool has_exception = false; |
| + Execution::Call(Handle<Object>(getter_fun, isolate), |
| + Handle<Object>(object, isolate), |
| + 0, |
| + NULL, |
| + &has_exception); |
| + ASSERT(!has_exception); |
| + budget--; |
| + } |
| + list_.Rewind(write_index); |
| + list_.Trim(); |
| + nested_ = false; |
| +} |
| + |
| + |
| +void ErrorObjectList::RemoveUnmarked(Heap* heap) { |
| + for (int i = 0; i < list_.length(); i++) { |
| + HeapObject* object = HeapObject::cast(list_[i]); |
| + if (!Marking::MarkBitFrom(object).Get()) { |
| + list_[i] = heap->the_hole_value(); |
| + } |
| + } |
| +} |
| + |
| + |
| +void ErrorObjectList::TearDown() { |
| + list_.Free(); |
| +} |
| + |
| + |
| void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { |
| chunk->set_next_chunk(chunks_queued_for_free_); |
| chunks_queued_for_free_ = chunk; |