| Index: src/heap.cc
|
| diff --git a/src/heap.cc b/src/heap.cc
|
| index 013a18c3205903a13989b56016252a0142d2d3de..3ffcd1b0a4aba60434bddd6c3078a2f6d581d5fc 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());
|
| }
|
|
|
|
|
| @@ -1377,6 +1379,8 @@ void Heap::Scavenge() {
|
| UpdateNewSpaceReferencesInExternalStringTable(
|
| &UpdateNewSpaceReferenceInExternalStringTableEntry);
|
|
|
| + error_object_list_.UpdateReferencesInNewSpace(this);
|
| +
|
| promotion_queue_.Destroy();
|
|
|
| LiveObjectList::UpdateReferencesForScavengeGC();
|
| @@ -5959,6 +5963,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);
|
| }
|
| @@ -6332,6 +6337,8 @@ void Heap::TearDown() {
|
|
|
| external_string_table_.TearDown();
|
|
|
| + error_object_list_.TearDown();
|
| +
|
| new_space_.TearDown();
|
|
|
| if (old_pointer_space_ != NULL) {
|
| @@ -7238,6 +7245,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()) {
|
| @@ -7247,6 +7256,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();
|
| @@ -7261,6 +7271,116 @@ 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_ || isolate->has_pending_exception()) 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];
|
| + JSFunction* getter_fun;
|
| +
|
| + { AssertNoAllocation assert;
|
| + // Skip possible holes in the list.
|
| + if (object->IsTheHole()) continue;
|
| + if (isolate->heap()->InNewSpace(object) || budget == 0) {
|
| + list_[write_index++] = object;
|
| + continue;
|
| + }
|
| +
|
| + // Check whether the stack property is backed by the original 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;
|
| + getter_fun = JSFunction::cast(getter_obj);
|
| + String* key = isolate->heap()->hidden_stack_trace_symbol();
|
| + if (key != getter_fun->GetHiddenProperty(key)) continue;
|
| + }
|
| +
|
| + budget--;
|
| + HandleScope scope(isolate);
|
| + bool has_exception = false;
|
| + Handle<Map> map(HeapObject::cast(object)->map(), isolate);
|
| + Handle<Object> object_handle(object, isolate);
|
| + Handle<Object> getter_handle(getter_fun, isolate);
|
| + Execution::Call(getter_handle, object_handle, 0, NULL, &has_exception);
|
| + CHECK(*map == HeapObject::cast(*object_handle)->map());
|
| + if (has_exception) {
|
| + // Hit an exception (most likely a stack overflow).
|
| + // Wrap up this pass and retry after another GC.
|
| + isolate->clear_pending_exception();
|
| + // We use the handle since calling the getter might have caused a GC.
|
| + list_[write_index++] = *object_handle;
|
| + budget = 0;
|
| + }
|
| + }
|
| + 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;
|
|
|