#ifdef ENABLE_DEBUGGER_SUPPORT
isolate_->debug()->AfterGarbageCollection();
#endif // ENABLE_DEBUGGER_SUPPORT
-
- error_object_list_.DeferredFormatStackTrace(isolate());
}
UpdateNewSpaceReferencesInExternalStringTable(
&UpdateNewSpaceReferenceInExternalStringTableEntry);
- error_object_list_.UpdateReferencesInNewSpace(this);
-
promotion_queue_.Destroy();
if (!FLAG_watch_ic_patching) {
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);
}
external_string_table_.TearDown();
- error_object_list_.TearDown();
-
new_space_.TearDown();
if (old_pointer_space_ != NULL) {
}
-// 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 (list_.is_empty()) return;
- 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_ || list_.is_empty() || isolate->has_pending_exception()) return;
- nested_ = true;
- HandleScope scope(isolate);
- Handle<String> stack_key = isolate->factory()->stack_string();
- int write_index = 0;
- int budget = kBudgetPerGC;
- for (int i = 0; i < list_.length(); i++) {
- Object* object = list_[i];
- JSFunction* getter_fun;
-
- { DisallowHeapAllocation no_gc;
- // 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_string();
- Object* value = getter_fun->GetHiddenProperty(key);
- if (key != value) continue;
- }
-
- budget--;
- HandleScope scope(isolate);
- bool has_exception = false;
-#ifdef DEBUG
- Handle<Map> map(HeapObject::cast(object)->map(), isolate);
-#endif
- Handle<Object> object_handle(object, isolate);
- Handle<Object> getter_handle(getter_fun, isolate);
- Execution::Call(getter_handle, object_handle, 0, NULL, &has_exception);
- ASSERT(*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;
};
-// The stack property of an error object is implemented as a getter that
-// formats the attached raw stack trace into a string. This raw stack trace
-// keeps code and function objects alive until the getter is called the first
-// time. To release those objects, we call the getter after each GC for
-// newly tenured error objects that are kept in a list.
-class ErrorObjectList {
- public:
- inline void Add(JSObject* object);
-
- inline void Iterate(ObjectVisitor* v);
-
- void TearDown();
-
- void RemoveUnmarked(Heap* heap);
-
- void DeferredFormatStackTrace(Isolate* isolate);
-
- void UpdateReferences();
-
- void UpdateReferencesInNewSpace(Heap* heap);
-
- private:
- static const int kBudgetPerGC = 16;
-
- ErrorObjectList() : nested_(false) { }
-
- friend class Heap;
-
- List<Object*> list_;
- bool nested_;
-
- DISALLOW_COPY_AND_ASSIGN(ErrorObjectList);
-};
-
-
enum ArrayStorageAllocationMode {
DONT_INITIALIZE_ARRAY_ELEMENTS,
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
return &external_string_table_;
}
- ErrorObjectList* error_object_list() {
- return &error_object_list_;
- }
-
// Returns the current sweep generation.
int sweep_generation() {
return sweep_generation_;
ExternalStringTable external_string_table_;
- ErrorObjectList error_object_list_;
-
VisitorDispatchTable<ScavengingCallback> scavenging_visitors_table_;
MemoryChunk* chunks_queued_for_free_;