Index: src/heap/heap.cc |
diff --git a/src/heap/heap.cc b/src/heap/heap.cc |
index e2f6ed40ed940d8d9ad88f34b19ed9d023a0082a..e6ce079ce17ef37e321ee57cbaa475efa0ca88a8 100644 |
--- a/src/heap/heap.cc |
+++ b/src/heap/heap.cc |
@@ -790,14 +790,16 @@ void Heap::HandleGCRequest() { |
} else if (incremental_marking()->request_type() == |
IncrementalMarking::COMPLETE_MARKING) { |
incremental_marking()->reset_request_type(); |
- CollectAllGarbage(current_gc_flags_, "GC interrupt", |
+ CollectAllGarbage(current_gc_flags_, |
+ GarbageCollectionReason::kFinalizeMarkingViaStackGuard, |
current_gc_callback_flags_); |
} else if (incremental_marking()->request_type() == |
IncrementalMarking::FINALIZATION && |
incremental_marking()->IsMarking() && |
!incremental_marking()->finalize_marking_completed()) { |
incremental_marking()->reset_request_type(); |
- FinalizeIncrementalMarking("GC interrupt: finalize incremental marking"); |
+ FinalizeIncrementalMarking( |
+ GarbageCollectionReason::kFinalizeMarkingViaStackGuard); |
} |
} |
@@ -806,8 +808,7 @@ void Heap::ScheduleIdleScavengeIfNeeded(int bytes_allocated) { |
scavenge_job_->ScheduleIdleTaskIfNeeded(this, bytes_allocated); |
} |
- |
-void Heap::FinalizeIncrementalMarking(const char* gc_reason) { |
+void Heap::FinalizeIncrementalMarking(GarbageCollectionReason gc_reason) { |
if (FLAG_trace_incremental_marking) { |
isolate()->PrintWithTimestamp("[IncrementalMarking] (%s).\n", gc_reason); |
} |
@@ -857,7 +858,7 @@ HistogramTimer* Heap::GCTypeTimer(GarbageCollector collector) { |
} |
} |
-void Heap::CollectAllGarbage(int flags, const char* gc_reason, |
+void Heap::CollectAllGarbage(int flags, GarbageCollectionReason gc_reason, |
const v8::GCCallbackFlags gc_callback_flags) { |
// Since we are ignoring the return value, the exact choice of space does |
// not matter, so long as we do not specify NEW_SPACE, which would not |
@@ -867,8 +868,7 @@ void Heap::CollectAllGarbage(int flags, const char* gc_reason, |
set_current_gc_flags(kNoGCFlags); |
} |
- |
-void Heap::CollectAllAvailableGarbage(const char* gc_reason) { |
+void Heap::CollectAllAvailableGarbage(GarbageCollectionReason gc_reason) { |
// Since we are ignoring the return value, the exact choice of space does |
// not matter, so long as we do not specify NEW_SPACE, which would not |
// cause a full GC. |
@@ -902,12 +902,12 @@ void Heap::CollectAllAvailableGarbage(const char* gc_reason) { |
UncommitFromSpace(); |
} |
- |
-void Heap::ReportExternalMemoryPressure(const char* gc_reason) { |
+void Heap::ReportExternalMemoryPressure() { |
if (external_memory_ > |
(external_memory_at_last_mark_compact_ + external_memory_hard_limit())) { |
CollectAllGarbage( |
- kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask, gc_reason, |
+ kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask, |
+ GarbageCollectionReason::kExternalMemoryPressure, |
static_cast<GCCallbackFlags>(kGCCallbackFlagCollectAllAvailableGarbage | |
kGCCallbackFlagCollectAllExternalMemory)); |
return; |
@@ -915,13 +915,13 @@ void Heap::ReportExternalMemoryPressure(const char* gc_reason) { |
if (incremental_marking()->IsStopped()) { |
if (incremental_marking()->CanBeActivated()) { |
StartIncrementalMarking( |
- i::Heap::kNoGCFlags, |
+ i::Heap::kNoGCFlags, GarbageCollectionReason::kExternalMemoryPressure, |
static_cast<GCCallbackFlags>( |
kGCCallbackFlagSynchronousPhantomCallbackProcessing | |
- kGCCallbackFlagCollectAllExternalMemory), |
- gc_reason); |
+ kGCCallbackFlagCollectAllExternalMemory)); |
} else { |
- CollectAllGarbage(i::Heap::kNoGCFlags, gc_reason, |
+ CollectAllGarbage(i::Heap::kNoGCFlags, |
+ GarbageCollectionReason::kExternalMemoryPressure, |
kGCCallbackFlagSynchronousPhantomCallbackProcessing); |
} |
} else { |
@@ -955,8 +955,8 @@ void Heap::EnsureFillerObjectAtTop() { |
} |
} |
- |
-bool Heap::CollectGarbage(GarbageCollector collector, const char* gc_reason, |
+bool Heap::CollectGarbage(GarbageCollector collector, |
+ GarbageCollectionReason gc_reason, |
const char* collector_reason, |
const v8::GCCallbackFlags gc_callback_flags) { |
// The VM is in the GC state until exiting this function. |
@@ -1055,8 +1055,8 @@ bool Heap::CollectGarbage(GarbageCollector collector, const char* gc_reason, |
// Start incremental marking for the next cycle. The heap snapshot |
// generator needs incremental marking to stay off after it aborted. |
if (!ShouldAbortIncrementalMarking()) { |
- StartIncrementalMarkingIfNeeded(kNoGCFlags, kNoGCCallbackFlags, |
- "GC epilogue"); |
+ StartIncrementalMarkingIfAllocationLimitIsReached(kNoGCFlags, |
+ kNoGCCallbackFlags); |
} |
return next_gc_likely_to_collect_more; |
@@ -1082,28 +1082,28 @@ int Heap::NotifyContextDisposed(bool dependant_context) { |
return ++contexts_disposed_; |
} |
- |
void Heap::StartIncrementalMarking(int gc_flags, |
- const GCCallbackFlags gc_callback_flags, |
- const char* reason) { |
+ GarbageCollectionReason gc_reason, |
+ GCCallbackFlags gc_callback_flags) { |
DCHECK(incremental_marking()->IsStopped()); |
set_current_gc_flags(gc_flags); |
current_gc_callback_flags_ = gc_callback_flags; |
- incremental_marking()->Start(reason); |
+ incremental_marking()->Start(gc_reason); |
} |
-void Heap::StartIncrementalMarkingIfNeeded( |
- int gc_flags, const GCCallbackFlags gc_callback_flags, const char* reason) { |
+void Heap::StartIncrementalMarkingIfAllocationLimitIsReached( |
+ int gc_flags, const GCCallbackFlags gc_callback_flags) { |
if (incremental_marking()->IsStopped() && |
incremental_marking()->ShouldActivateEvenWithoutIdleNotification()) { |
- StartIncrementalMarking(gc_flags, gc_callback_flags, reason); |
+ StartIncrementalMarking(gc_flags, GarbageCollectionReason::kAllocationLimit, |
+ gc_callback_flags); |
} |
} |
-void Heap::StartIdleIncrementalMarking() { |
+void Heap::StartIdleIncrementalMarking(GarbageCollectionReason gc_reason) { |
gc_idle_time_handler_->ResetNoProgressCounter(); |
- StartIncrementalMarking(kReduceMemoryFootprintMask, kNoGCCallbackFlags, |
- "idle"); |
+ StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason, |
+ kNoGCCallbackFlags); |
} |
@@ -1212,17 +1212,15 @@ bool Heap::ReserveSpace(Reservation* reservations, List<Address>* maps) { |
} |
if (perform_gc) { |
if (space == NEW_SPACE) { |
- CollectGarbage(NEW_SPACE, "failed to reserve space in the new space"); |
+ CollectGarbage(NEW_SPACE, GarbageCollectionReason::kDeserializer); |
} else { |
if (counter > 1) { |
CollectAllGarbage( |
kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, |
- "failed to reserve space in paged or large " |
- "object space, trying to reduce memory footprint"); |
+ GarbageCollectionReason::kDeserializer); |
} else { |
- CollectAllGarbage( |
- kAbortIncrementalMarkingMask, |
- "failed to reserve space in paged or large object space"); |
+ CollectAllGarbage(kAbortIncrementalMarkingMask, |
+ GarbageCollectionReason::kDeserializer); |
} |
} |
gc_performed = true; |
@@ -4076,7 +4074,8 @@ bool Heap::IsHeapIterable() { |
void Heap::MakeHeapIterable() { |
DCHECK(AllowHeapAllocation::IsAllowed()); |
if (!IsHeapIterable()) { |
- CollectAllGarbage(kMakeHeapIterableMask, "Heap::MakeHeapIterable"); |
+ CollectAllGarbage(kMakeHeapIterableMask, |
+ GarbageCollectionReason::kMakeHeapIterable); |
} |
if (mark_compact_collector()->sweeping_in_progress()) { |
mark_compact_collector()->EnsureSweepingCompleted(); |
@@ -4211,20 +4210,21 @@ bool Heap::MarkingDequesAreEmpty() { |
->NumberOfWrappersToTrace() == 0)); |
} |
-void Heap::FinalizeIncrementalMarkingIfComplete(const char* comment) { |
+void Heap::FinalizeIncrementalMarkingIfComplete( |
+ GarbageCollectionReason gc_reason) { |
if (incremental_marking()->IsMarking() && |
(incremental_marking()->IsReadyToOverApproximateWeakClosure() || |
(!incremental_marking()->finalize_marking_completed() && |
MarkingDequesAreEmpty()))) { |
- FinalizeIncrementalMarking(comment); |
+ FinalizeIncrementalMarking(gc_reason); |
} else if (incremental_marking()->IsComplete() || |
(mark_compact_collector()->marking_deque()->IsEmpty())) { |
- CollectAllGarbage(current_gc_flags_, comment); |
+ CollectAllGarbage(current_gc_flags_, gc_reason); |
} |
} |
- |
-bool Heap::TryFinalizeIdleIncrementalMarking(double idle_time_in_ms) { |
+bool Heap::TryFinalizeIdleIncrementalMarking( |
+ double idle_time_in_ms, GarbageCollectionReason gc_reason) { |
size_t size_of_objects = static_cast<size_t>(SizeOfObjects()); |
double final_incremental_mark_compact_speed_in_bytes_per_ms = |
tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond(); |
@@ -4233,16 +4233,14 @@ bool Heap::TryFinalizeIdleIncrementalMarking(double idle_time_in_ms) { |
MarkingDequesAreEmpty() && |
gc_idle_time_handler_->ShouldDoOverApproximateWeakClosure( |
idle_time_in_ms))) { |
- FinalizeIncrementalMarking( |
- "Idle notification: finalize incremental marking"); |
+ FinalizeIncrementalMarking(gc_reason); |
return true; |
} else if (incremental_marking()->IsComplete() || |
(MarkingDequesAreEmpty() && |
gc_idle_time_handler_->ShouldDoFinalIncrementalMarkCompact( |
idle_time_in_ms, size_of_objects, |
final_incremental_mark_compact_speed_in_bytes_per_ms))) { |
- CollectAllGarbage(current_gc_flags_, |
- "idle notification: finalize incremental marking"); |
+ CollectAllGarbage(current_gc_flags_, gc_reason); |
return true; |
} |
return false; |
@@ -4317,7 +4315,7 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, |
DCHECK(contexts_disposed_ > 0); |
HistogramTimerScope scope(isolate_->counters()->gc_context()); |
TRACE_EVENT0("v8", "V8.GCContext"); |
- CollectAllGarbage(kNoGCFlags, "idle notification: contexts disposed"); |
+ CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal); |
break; |
} |
case DO_NOTHING: |
@@ -4450,10 +4448,11 @@ void Heap::CheckMemoryPressure() { |
} |
} |
if (memory_pressure_level_.Value() == MemoryPressureLevel::kCritical) { |
- CollectGarbageOnMemoryPressure("memory pressure"); |
+ CollectGarbageOnMemoryPressure(); |
} else if (memory_pressure_level_.Value() == MemoryPressureLevel::kModerate) { |
if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { |
- StartIdleIncrementalMarking(); |
+ StartIncrementalMarking(kReduceMemoryFootprintMask, |
+ GarbageCollectionReason::kMemoryPressure); |
} |
} |
MemoryReducer::Event event; |
@@ -4462,7 +4461,7 @@ void Heap::CheckMemoryPressure() { |
memory_reducer_->NotifyPossibleGarbage(event); |
} |
-void Heap::CollectGarbageOnMemoryPressure(const char* source) { |
+void Heap::CollectGarbageOnMemoryPressure() { |
const int kGarbageThresholdInBytes = 8 * MB; |
const double kGarbageThresholdAsFractionOfTotalMemory = 0.1; |
// This constant is the maximum response time in RAIL performance model. |
@@ -4470,7 +4469,8 @@ void Heap::CollectGarbageOnMemoryPressure(const char* source) { |
double start = MonotonicallyIncreasingTimeInMs(); |
CollectAllGarbage(kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, |
- source, kGCCallbackFlagCollectAllAvailableGarbage); |
+ GarbageCollectionReason::kMemoryPressure, |
+ kGCCallbackFlagCollectAllAvailableGarbage); |
double end = MonotonicallyIncreasingTimeInMs(); |
// Estimate how much memory we can free. |
@@ -4485,11 +4485,13 @@ void Heap::CollectGarbageOnMemoryPressure(const char* source) { |
// Otherwise, start incremental marking. |
if (end - start < kMaxMemoryPressurePauseMs / 2) { |
CollectAllGarbage( |
- kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, source, |
+ kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, |
+ GarbageCollectionReason::kMemoryPressure, |
kGCCallbackFlagCollectAllAvailableGarbage); |
} else { |
if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { |
- StartIdleIncrementalMarking(); |
+ StartIncrementalMarking(kReduceMemoryFootprintMask, |
+ GarbageCollectionReason::kMemoryPressure); |
} |
} |
} |
@@ -4575,6 +4577,58 @@ void Heap::ReportHeapStatistics(const char* title) { |
#endif // DEBUG |
+const char* Heap::GarbageCollectionReasonToString( |
+ GarbageCollectionReason gc_reason) { |
+ switch (gc_reason) { |
+ case GarbageCollectionReason::kAllocationFailure: |
+ return "allocation failure"; |
+ case GarbageCollectionReason::kAllocationLimit: |
+ return "allocation limit"; |
+ case GarbageCollectionReason::kContextDisposal: |
+ return "context disposal"; |
+ case GarbageCollectionReason::kCountersExtension: |
+ return "counters extension"; |
+ case GarbageCollectionReason::kDebugger: |
+ return "debugger"; |
+ case GarbageCollectionReason::kDeserializer: |
+ return "deserialize"; |
+ case GarbageCollectionReason::kExternalMemoryPressure: |
+ return "external memory pressure"; |
+ case GarbageCollectionReason::kFinalizeMarkingViaStackGuard: |
+ return "finalize incremental marking via stack guard"; |
+ case GarbageCollectionReason::kFinalizeMarkingViaTask: |
+ return "finalize incremental marking via task"; |
+ case GarbageCollectionReason::kFullHashtable: |
+ return "full hash-table"; |
+ case GarbageCollectionReason::kHeapProfiler: |
+ return "heap profiler"; |
+ case GarbageCollectionReason::kIdleTask: |
+ return "idle task"; |
+ case GarbageCollectionReason::kLastResort: |
+ return "last resort"; |
+ case GarbageCollectionReason::kLowMemoryNotification: |
+ return "low memory notification"; |
+ case GarbageCollectionReason::kMakeHeapIterable: |
+ return "make heap iterable"; |
+ case GarbageCollectionReason::kMemoryPressure: |
+ return "memory pressure"; |
+ case GarbageCollectionReason::kMemoryReducer: |
+ return "memory reducer"; |
+ case GarbageCollectionReason::kRuntime: |
+ return "runtime"; |
+ case GarbageCollectionReason::kSamplingProfiler: |
+ return "sampling profiler"; |
+ case GarbageCollectionReason::kSnapshotCreator: |
+ return "snapshot creator"; |
+ case GarbageCollectionReason::kTesting: |
+ return "testing"; |
+ case GarbageCollectionReason::kUnknown: |
+ return "unknown"; |
+ } |
+ UNREACHABLE(); |
+ return ""; |
+} |
+ |
bool Heap::Contains(HeapObject* value) { |
if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) { |
return false; |