Index: src/heap.cc |
diff --git a/src/heap.cc b/src/heap.cc |
index 746c9b6d6faaf2676e3ddc7419f072f084007403..0930666d7cc6d240c12c9fab3e29fd99aa485cef 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()); |
} |
@@ -1354,6 +1356,8 @@ void Heap::Scavenge() { |
UpdateNewSpaceReferencesInExternalStringTable( |
&UpdateNewSpaceReferenceInExternalStringTableEntry); |
+ error_object_list_.UpdateReferencesInNewSpace(this); |
+ |
promotion_queue_.Destroy(); |
LiveObjectList::UpdateReferencesForScavengeGC(); |
@@ -5870,6 +5874,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); |
} |
@@ -6243,6 +6248,8 @@ void Heap::TearDown() { |
external_string_table_.TearDown(); |
+ error_object_list_.TearDown(); |
+ |
new_space_.TearDown(); |
if (old_pointer_space_ != NULL) { |
@@ -7149,6 +7156,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()) { |
@@ -7158,6 +7167,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(); |
@@ -7172,6 +7182,103 @@ 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 the original marked getter. |
+ 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); |
+ String* key = isolate->heap()->hidden_stack_trace_symbol(); |
+ if (key != getter_fun->GetHiddenProperty(key)) continue; |
+ 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; |