Changeset 253358 in webkit for trunk/Source/JavaScriptCore/dfg


Ignore:
Timestamp:
Dec 10, 2019, 5:45:00 PM (5 years ago)
Author:
[email protected]
Message:

Worklist::deleteCancelledPlansForVM() should not assume that a cancelled plan is ready for deletion.
https://bugs.webkit.org/show_bug.cgi?id=205086
<rdar://problem/57795002>

Reviewed by Saam Barati.

Consider this race scenario:

  1. The DFG thread finds a plan and started compiling, and it's holding a ref to the plan while it's compiling.
  2. The GC thread discovers that we no longer need the plan and cancels it.
  3. After the plan is cancelled but while the DFG thread is still compiling, the mutator thread calls Worklist::deleteCancelledPlansForVM().

Worklist::deleteCancelledPlansForVM() was assuming that by the time it is
called, Worklist::m_cancelledPlansPendingDestruction will contain the last ref
to the cancelled plan. However, this is an incorrect assumption, and the
assertion there that asserts refCount == 1 will fail.

This patch fixes Worklist::deleteCancelledPlansForVM() to append the cancelled
plan back into m_cancelledPlansPendingDestruction if its refCount is not 1
(implying that the compiler thread still has a ref to it), and defer deletion of
the plan to a subsequent call to deleteCancelledPlansForVM().

This patch also adds a WTFMove to Worklist::removeDeadPlans() when we append the
cancelled plan to m_cancelledPlansPendingDestruction there. This saves us one
unnecessary ref and deref of the plan.

  • dfg/DFGWorklist.cpp:

(JSC::DFG::Worklist::deleteCancelledPlansForVM):
(JSC::DFG::Worklist::removeDeadPlans):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp

    r253243 r253358  
    308308{
    309309    RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
    310 #if !ASSERT_DISABLED
    311310    HashSet<RefPtr<Plan>> removedPlans;
    312 #endif
     311
     312    // The following scenario can occur:
     313    // 1. The DFG thread started compiling a plan.
     314    // 2. The GC thread cancels the plan, and adds it to m_cancelledPlansPendingDestruction.
     315    // 3. The DFG thread finishes compiling, and discovers that the thread is cancelled.
     316    //    To avoid destructing the plan in the DFG thread, it adds it to
     317    //    m_cancelledPlansPendingDestruction.
     318    // 4. The above occurs before the mutator runs deleteCancelledPlansForVM().
     319    //
     320    // Hence, the same cancelled plan can appear in m_cancelledPlansPendingDestruction
     321    // more than once. This is why we need to filter the cancelled plans through
     322    // the removedPlans HashSet before we do the refCount check below.
    313323
    314324    for (size_t i = 0; i < m_cancelledPlansPendingDestruction.size(); ++i) {
     
    318328        m_cancelledPlansPendingDestruction[i--] = m_cancelledPlansPendingDestruction.last();
    319329        m_cancelledPlansPendingDestruction.removeLast();
    320 #if !ASSERT_DISABLED
    321         removedPlans.add(plan);
    322 #endif
    323     }
    324 
    325 #if !ASSERT_DISABLED
     330        removedPlans.add(WTFMove(plan));
     331    }
     332
    326333    while (!removedPlans.isEmpty()) {
    327334        RefPtr<Plan> plan = removedPlans.takeAny();
    328         RELEASE_ASSERT(plan->stage() == Plan::Cancelled);
    329         RELEASE_ASSERT(plan->refCount() == 1);
    330     }
    331 #endif
     335        ASSERT(plan->stage() == Plan::Cancelled);
     336        if (plan->refCount() > 1)
     337            m_cancelledPlansPendingDestruction.append(WTFMove(plan));
     338    }
    332339}
    333340
     
    460467                plan->cancel();
    461468                if (!isInMutator)
    462                     m_cancelledPlansPendingDestruction.append(plan);
     469                    m_cancelledPlansPendingDestruction.append(WTFMove(plan));
    463470            }
    464471            Deque<RefPtr<Plan>> newQueue;
Note: See TracChangeset for help on using the changeset viewer.