| Index: src/heap/heap.cc
 | 
| diff --git a/src/heap/heap.cc b/src/heap/heap.cc
 | 
| index 20f1e1719b04d2ae305a2ffba21fbf97041fd84a..217c27b1349d40b1d2ea9d59357b86065804c376 100644
 | 
| --- a/src/heap/heap.cc
 | 
| +++ b/src/heap/heap.cc
 | 
| @@ -266,13 +266,6 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
 | 
|      return MARK_COMPACTOR;
 | 
|    }
 | 
|  
 | 
| -  // Is enough data promoted to justify a global GC?
 | 
| -  if (OldGenerationAllocationLimitReached()) {
 | 
| -    isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
 | 
| -    *reason = "promotion limit reached";
 | 
| -    return MARK_COMPACTOR;
 | 
| -  }
 | 
| -
 | 
|    // Is there enough space left in OLD to guarantee that a scavenge can
 | 
|    // succeed?
 | 
|    //
 | 
| @@ -967,7 +960,7 @@ bool Heap::CollectGarbage(GarbageCollector collector,
 | 
|    if (collector == MARK_COMPACTOR && !ShouldFinalizeIncrementalMarking() &&
 | 
|        !ShouldAbortIncrementalMarking() && !incremental_marking()->IsStopped() &&
 | 
|        !incremental_marking()->should_hurry() && FLAG_incremental_marking &&
 | 
| -      OldGenerationAllocationLimitReached()) {
 | 
| +      OldGenerationSpaceAvailable() <= 0) {
 | 
|      if (!incremental_marking()->IsComplete() &&
 | 
|          !mark_compact_collector()->marking_deque_.IsEmpty() &&
 | 
|          !FLAG_gc_global) {
 | 
| @@ -1079,10 +1072,15 @@ void Heap::StartIncrementalMarking(int gc_flags,
 | 
|  
 | 
|  void Heap::StartIncrementalMarkingIfAllocationLimitIsReached(
 | 
|      int gc_flags, const GCCallbackFlags gc_callback_flags) {
 | 
| -  if (incremental_marking()->IsStopped() &&
 | 
| -      incremental_marking()->ShouldActivateEvenWithoutIdleNotification()) {
 | 
| -    StartIncrementalMarking(gc_flags, GarbageCollectionReason::kAllocationLimit,
 | 
| -                            gc_callback_flags);
 | 
| +  if (incremental_marking()->IsStopped()) {
 | 
| +    IncrementalMarkingLimit reached_limit = IncrementalMarkingLimitReached();
 | 
| +    if (reached_limit == IncrementalMarkingLimit::kSoftLimit) {
 | 
| +      incremental_marking()->incremental_marking_job()->ScheduleTask(this);
 | 
| +    } else if (reached_limit == IncrementalMarkingLimit::kHardLimit) {
 | 
| +      StartIncrementalMarking(gc_flags,
 | 
| +                              GarbageCollectionReason::kAllocationLimit,
 | 
| +                              gc_callback_flags);
 | 
| +    }
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -5329,7 +5327,6 @@ void Heap::SetOldGenerationAllocationLimit(intptr_t old_gen_size,
 | 
|    }
 | 
|  }
 | 
|  
 | 
| -
 | 
|  void Heap::DampenOldGenerationAllocationLimit(intptr_t old_gen_size,
 | 
|                                                double gc_speed,
 | 
|                                                double mutator_speed) {
 | 
| @@ -5348,6 +5345,53 @@ void Heap::DampenOldGenerationAllocationLimit(intptr_t old_gen_size,
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +// This predicate is called when an old generation space cannot allocated from
 | 
| +// the free list and is about to add a new page. Returning false will cause a
 | 
| +// major GC. It happens when the old generation allocation limit is reached and
 | 
| +// - either we need to optimize for memory usage,
 | 
| +// - or the incremental marking is not in progress and we cannot start it.
 | 
| +bool Heap::ShouldExpandOldGenerationOnAllocationFailure() {
 | 
| +  if (always_allocate() || OldGenerationSpaceAvailable() > 0) return true;
 | 
| +  // We reached the old generation allocation limit.
 | 
| +
 | 
| +  if (ShouldOptimizeForMemoryUsage()) return false;
 | 
| +
 | 
| +  if (incremental_marking()->IsStopped() &&
 | 
| +      IncrementalMarkingLimitReached() == IncrementalMarkingLimit::kNoLimit) {
 | 
| +    // We cannot start incremental marking.
 | 
| +    return false;
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +// This function returns either kNoLimit, kSoftLimit, or kHardLimit.
 | 
| +// The kNoLimit means that either incremental marking is disabled or it is too
 | 
| +// early to start incremental marking.
 | 
| +// The kSoftLimit means that incremental marking should be started soon.
 | 
| +// The kHardLimit means that incremental marking should be started immediately.
 | 
| +Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() {
 | 
| +  if (!incremental_marking()->CanBeActivated() ||
 | 
| +      PromotedSpaceSizeOfObjects() < IncrementalMarking::kActivationThreshold) {
 | 
| +    // Incremental marking is disabled or it is too early to start.
 | 
| +    return IncrementalMarkingLimit::kNoLimit;
 | 
| +  }
 | 
| +  if ((FLAG_stress_compaction && (gc_count_ & 1) != 0) ||
 | 
| +      HighMemoryPressure()) {
 | 
| +    // If there is high memory pressure or stress testing is enabled, then
 | 
| +    // start marking immediately.
 | 
| +    return IncrementalMarkingLimit::kHardLimit;
 | 
| +  }
 | 
| +  intptr_t old_generation_space_available = OldGenerationSpaceAvailable();
 | 
| +  if (old_generation_space_available > new_space_->Capacity()) {
 | 
| +    return IncrementalMarkingLimit::kNoLimit;
 | 
| +  }
 | 
| +  // We are close to the allocation limit.
 | 
| +  // Choose between the hard and the soft limits.
 | 
| +  if (old_generation_space_available <= 0 || ShouldOptimizeForMemoryUsage()) {
 | 
| +    return IncrementalMarkingLimit::kHardLimit;
 | 
| +  }
 | 
| +  return IncrementalMarkingLimit::kSoftLimit;
 | 
| +}
 | 
|  
 | 
|  void Heap::EnableInlineAllocation() {
 | 
|    if (!inline_allocation_disabled_) return;
 | 
| 
 |