Optimize ClearNonLiveReferences: collect dependent code only from maps that are embedded in optimize code.
BUG=chromium:554488 LOG=NO Review URL: https://codereview.chromium.org/1471703002 Cr-Commit-Position: refs/heads/master@{#32218}
This commit is contained in:
parent
0fb2edd15d
commit
e777784fb4
@ -528,6 +528,8 @@ void GCTracer::PrintNVP() const {
|
||||
"weakcollection_abort=%.1f "
|
||||
"weakcells=%.1f "
|
||||
"nonlive_refs=%.1f "
|
||||
"extract_dependent_code=%.1f "
|
||||
"deopt_dependent_code=%.1f "
|
||||
"steps_count=%d "
|
||||
"steps_took=%.1f "
|
||||
"longest_step=%.1f "
|
||||
@ -595,6 +597,8 @@ void GCTracer::PrintNVP() const {
|
||||
current_.scopes[Scope::MC_WEAKCOLLECTION_ABORT],
|
||||
current_.scopes[Scope::MC_WEAKCELL],
|
||||
current_.scopes[Scope::MC_NONLIVEREFERENCES],
|
||||
current_.scopes[Scope::MC_EXTRACT_DEPENDENT_CODE],
|
||||
current_.scopes[Scope::MC_DEOPT_DEPENDENT_CODE],
|
||||
current_.incremental_marking_steps,
|
||||
current_.incremental_marking_duration,
|
||||
current_.longest_incremental_marking_step,
|
||||
|
@ -131,7 +131,9 @@ class GCTracer {
|
||||
MC_WEAKCOLLECTION_CLEAR,
|
||||
MC_WEAKCOLLECTION_ABORT,
|
||||
MC_WEAKCELL,
|
||||
MC_EXTRACT_DEPENDENT_CODE,
|
||||
MC_NONLIVEREFERENCES,
|
||||
MC_DEOPT_DEPENDENT_CODE,
|
||||
MC_FLUSH_CODE,
|
||||
SCAVENGER_CODE_FLUSH_CANDIDATES,
|
||||
SCAVENGER_OBJECT_GROUPS,
|
||||
|
@ -91,6 +91,7 @@ Heap::Heap()
|
||||
survived_last_scavenge_(0),
|
||||
always_allocate_scope_count_(0),
|
||||
contexts_disposed_(0),
|
||||
number_of_disposed_maps_(0),
|
||||
global_ic_age_(0),
|
||||
scan_on_scavenge_pages_(0),
|
||||
new_space_(this),
|
||||
@ -1037,7 +1038,7 @@ int Heap::NotifyContextDisposed(bool dependant_context) {
|
||||
isolate()->optimizing_compile_dispatcher()->Flush();
|
||||
}
|
||||
AgeInlineCaches();
|
||||
set_retained_maps(ArrayList::cast(empty_fixed_array()));
|
||||
number_of_disposed_maps_ = retained_maps()->Length();
|
||||
tracer()->AddContextDisposalTime(MonotonicallyIncreasingTimeInMs());
|
||||
return ++contexts_disposed_;
|
||||
}
|
||||
@ -5366,7 +5367,6 @@ DependentCode* Heap::LookupWeakObjectToCodeDependency(Handle<HeapObject> obj) {
|
||||
|
||||
|
||||
void Heap::AddRetainedMap(Handle<Map> map) {
|
||||
if (FLAG_retain_maps_for_n_gc == 0) return;
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(map);
|
||||
Handle<ArrayList> array(retained_maps(), isolate());
|
||||
array = ArrayList::Add(
|
||||
|
@ -2149,6 +2149,11 @@ class Heap {
|
||||
// For keeping track of context disposals.
|
||||
int contexts_disposed_;
|
||||
|
||||
// The length of the retained_maps array at the time of context disposal.
|
||||
// This separates maps in the retained_maps array that were created before
|
||||
// and after context disposal.
|
||||
int number_of_disposed_maps_;
|
||||
|
||||
int global_ic_age_;
|
||||
|
||||
int scan_on_scavenge_pages_;
|
||||
|
@ -349,16 +349,7 @@ void MarkCompactCollector::CollectGarbage() {
|
||||
|
||||
DCHECK(heap_->incremental_marking()->IsStopped());
|
||||
|
||||
// ClearNonLiveReferences can deoptimize code in dependent code arrays.
|
||||
// Process weak cells before so that weak cells in dependent code
|
||||
// arrays are cleared or contain only live code objects.
|
||||
ProcessAndClearWeakCells();
|
||||
|
||||
ClearNonLiveReferences();
|
||||
|
||||
ClearWeakCollections();
|
||||
|
||||
heap_->set_encountered_weak_cells(Smi::FromInt(0));
|
||||
ProcessWeakReferences();
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
if (FLAG_verify_heap) {
|
||||
@ -1821,18 +1812,40 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) {
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::RetainMaps() {
|
||||
if (heap()->ShouldReduceMemory() || heap()->ShouldAbortIncrementalMarking() ||
|
||||
FLAG_retain_maps_for_n_gc == 0) {
|
||||
// Do not retain dead maps if flag disables it or there is
|
||||
// - memory pressure (reduce_memory_footprint_),
|
||||
// - GC is requested by tests or dev-tools (abort_incremental_marking_).
|
||||
return;
|
||||
bool ShouldRetainMap(Map* map, int age) {
|
||||
if (age == 0) {
|
||||
// The map has aged. Do not retain this map.
|
||||
return false;
|
||||
}
|
||||
Object* constructor = map->GetConstructor();
|
||||
if (!constructor->IsHeapObject() ||
|
||||
Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(constructor)))) {
|
||||
// The constructor is dead, no new objects with this map can
|
||||
// be created. Do not retain this map.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::RetainMaps() {
|
||||
// Do not retain dead maps if flag disables it or there is
|
||||
// - memory pressure (reduce_memory_footprint_),
|
||||
// - GC is requested by tests or dev-tools (abort_incremental_marking_).
|
||||
bool map_retaining_is_disabled = heap()->ShouldReduceMemory() ||
|
||||
heap()->ShouldAbortIncrementalMarking() ||
|
||||
FLAG_retain_maps_for_n_gc == 0;
|
||||
|
||||
ArrayList* retained_maps = heap()->retained_maps();
|
||||
int length = retained_maps->Length();
|
||||
int new_length = 0;
|
||||
// The number_of_disposed_maps separates maps in the retained_maps
|
||||
// array that were created before and after context disposal.
|
||||
// We do not age and retain disposed maps to avoid memory leaks.
|
||||
int number_of_disposed_maps = heap()->number_of_disposed_maps_;
|
||||
int new_number_of_disposed_maps = 0;
|
||||
// This loop compacts the array by removing cleared weak cells,
|
||||
// ages and retains dead maps.
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
DCHECK(retained_maps->Get(i)->IsWeakCell());
|
||||
WeakCell* cell = WeakCell::cast(retained_maps->Get(i));
|
||||
@ -1841,20 +1854,13 @@ void MarkCompactCollector::RetainMaps() {
|
||||
int new_age;
|
||||
Map* map = Map::cast(cell->value());
|
||||
MarkBit map_mark = Marking::MarkBitFrom(map);
|
||||
if (Marking::IsWhite(map_mark)) {
|
||||
if (age == 0) {
|
||||
// The map has aged. Do not retain this map.
|
||||
continue;
|
||||
}
|
||||
Object* constructor = map->GetConstructor();
|
||||
if (!constructor->IsHeapObject() || Marking::IsWhite(Marking::MarkBitFrom(
|
||||
HeapObject::cast(constructor)))) {
|
||||
// The constructor is dead, no new objects with this map can
|
||||
// be created. Do not retain this map.
|
||||
continue;
|
||||
if (i >= number_of_disposed_maps && !map_retaining_is_disabled &&
|
||||
Marking::IsWhite(map_mark)) {
|
||||
if (ShouldRetainMap(map, age)) {
|
||||
MarkObject(map, map_mark);
|
||||
}
|
||||
Object* prototype = map->prototype();
|
||||
if (prototype->IsHeapObject() &&
|
||||
if (age > 0 && prototype->IsHeapObject() &&
|
||||
Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) {
|
||||
// The prototype is not marked, age the map.
|
||||
new_age = age - 1;
|
||||
@ -1863,10 +1869,10 @@ void MarkCompactCollector::RetainMaps() {
|
||||
// transition tree alive, not JSObjects. Do not age the map.
|
||||
new_age = age;
|
||||
}
|
||||
MarkObject(map, map_mark);
|
||||
} else {
|
||||
new_age = FLAG_retain_maps_for_n_gc;
|
||||
}
|
||||
// Compact the array and update the age.
|
||||
if (i != new_length) {
|
||||
retained_maps->Set(new_length, cell);
|
||||
Object** slot = retained_maps->Slot(new_length);
|
||||
@ -1875,8 +1881,12 @@ void MarkCompactCollector::RetainMaps() {
|
||||
} else if (new_age != age) {
|
||||
retained_maps->Set(new_length + 1, Smi::FromInt(new_age));
|
||||
}
|
||||
if (i < number_of_disposed_maps) {
|
||||
new_number_of_disposed_maps++;
|
||||
}
|
||||
new_length += 2;
|
||||
}
|
||||
heap()->number_of_disposed_maps_ = new_number_of_disposed_maps;
|
||||
Object* undefined = heap()->undefined_value();
|
||||
for (int i = new_length; i < length; i++) {
|
||||
retained_maps->Clear(i, undefined);
|
||||
@ -1886,6 +1896,33 @@ void MarkCompactCollector::RetainMaps() {
|
||||
}
|
||||
|
||||
|
||||
DependentCode* MarkCompactCollector::DependentCodeListFromNonLiveMaps() {
|
||||
GCTracer::Scope gc_scope(heap()->tracer(),
|
||||
GCTracer::Scope::MC_EXTRACT_DEPENDENT_CODE);
|
||||
ArrayList* retained_maps = heap()->retained_maps();
|
||||
int length = retained_maps->Length();
|
||||
DependentCode* head = DependentCode::cast(heap()->empty_fixed_array());
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
DCHECK(retained_maps->Get(i)->IsWeakCell());
|
||||
WeakCell* cell = WeakCell::cast(retained_maps->Get(i));
|
||||
DCHECK(!cell->cleared());
|
||||
Map* map = Map::cast(cell->value());
|
||||
MarkBit map_mark = Marking::MarkBitFrom(map);
|
||||
if (Marking::IsWhite(map_mark)) {
|
||||
DependentCode* candidate = map->dependent_code();
|
||||
// We rely on the fact that the weak code group comes first.
|
||||
STATIC_ASSERT(DependentCode::kWeakCodeGroup == 0);
|
||||
if (candidate->length() > 0 &&
|
||||
candidate->group() == DependentCode::kWeakCodeGroup) {
|
||||
candidate->set_next_link(head);
|
||||
head = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::EnsureMarkingDequeIsReserved() {
|
||||
DCHECK(!marking_deque_.in_use());
|
||||
if (marking_deque_memory_ == NULL) {
|
||||
@ -2192,6 +2229,26 @@ void MarkCompactCollector::ProcessAndClearOptimizedCodeMaps() {
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::ProcessWeakReferences() {
|
||||
// This should be done before processing weak cells because it checks
|
||||
// mark bits of maps in weak cells.
|
||||
DependentCode* dependent_code_list = DependentCodeListFromNonLiveMaps();
|
||||
|
||||
// Process weak cells before MarkCodeForDeoptimization and
|
||||
// ClearNonLiveReferences so that weak cells in dependent code arrays are
|
||||
// cleared or contain only live code objects.
|
||||
ProcessAndClearWeakCells();
|
||||
|
||||
MarkDependentCodeListForDeoptimization(dependent_code_list);
|
||||
|
||||
ClearNonLiveReferences();
|
||||
|
||||
ClearWeakCollections();
|
||||
|
||||
heap_->set_encountered_weak_cells(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::ClearNonLiveReferences() {
|
||||
GCTracer::Scope gc_scope(heap()->tracer(),
|
||||
GCTracer::Scope::MC_NONLIVEREFERENCES);
|
||||
@ -2209,10 +2266,6 @@ void MarkCompactCollector::ClearNonLiveReferences() {
|
||||
ClearNonLivePrototypeTransitions(map);
|
||||
} else {
|
||||
ClearNonLiveMapTransitions(map);
|
||||
have_code_to_deoptimize_ |=
|
||||
map->dependent_code()->MarkCodeForDeoptimization(
|
||||
isolate(), DependentCode::kWeakCodeGroup);
|
||||
map->set_dependent_code(DependentCode::cast(heap()->empty_fixed_array()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2237,6 +2290,20 @@ void MarkCompactCollector::ClearNonLiveReferences() {
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::MarkDependentCodeListForDeoptimization(
|
||||
DependentCode* list_head) {
|
||||
GCTracer::Scope gc_scope(heap()->tracer(),
|
||||
GCTracer::Scope::MC_DEOPT_DEPENDENT_CODE);
|
||||
Isolate* isolate = this->isolate();
|
||||
DependentCode* current = list_head;
|
||||
while (current->length() > 0) {
|
||||
have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization(
|
||||
isolate, DependentCode::kWeakCodeGroup);
|
||||
current = current->next_link();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
|
||||
FixedArray* prototype_transitions =
|
||||
TransitionArray::GetPrototypeTransitions(map);
|
||||
|
@ -627,6 +627,9 @@ class MarkCompactCollector {
|
||||
// increase chances of reusing of map transition tree in future.
|
||||
void RetainMaps();
|
||||
|
||||
// Collects a list of dependent code from maps embedded in optimize code.
|
||||
DependentCode* DependentCodeListFromNonLiveMaps();
|
||||
|
||||
// Mark objects reachable (transitively) from objects in the marking
|
||||
// stack. This function empties the marking stack, but may leave
|
||||
// overflowed objects in the heap, in which case the marking stack's
|
||||
@ -657,6 +660,7 @@ class MarkCompactCollector {
|
||||
void ClearNonLiveMapTransitions(Map* map);
|
||||
void ClearMapTransitions(Map* map, Map* dead_transition);
|
||||
bool ClearMapBackPointer(Map* map);
|
||||
void MarkDependentCodeListForDeoptimization(DependentCode* list_head);
|
||||
void TrimDescriptorArray(Map* map, DescriptorArray* descriptors,
|
||||
int number_of_own_descriptors);
|
||||
void TrimEnumCache(Map* map, DescriptorArray* descriptors);
|
||||
@ -683,6 +687,9 @@ class MarkCompactCollector {
|
||||
// trimming or clearing out the entire optimized code map.
|
||||
void ProcessAndClearOptimizedCodeMaps();
|
||||
|
||||
// Process non-live references in maps and optimized code.
|
||||
void ProcessWeakReferences();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Phase 2: Sweeping to clear mark bits and free non-live objects for
|
||||
// a non-compacting collection.
|
||||
|
Loading…
Reference in New Issue
Block a user