Changeset 167733 in webkit


Ignore:
Timestamp:
Apr 23, 2014 5:43:15 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

The GC should only resume compiler threads that it suspended in the same GC pass.
<https://webkit.org/b/132088>

Reviewed by Mark Hahnenberg.

Previously, this scenario can occur:

  1. Thread 1 starts a GC and tries to suspend DFG worklist threads. However, no worklists were created yet at the that time.
  2. Thread 2 starts to compile some functions and creates a DFG worklist, and acquires the worklist thread's lock.
  3. Thread 1's GC completes and tries to resume suspended DFG worklist thread. This time, it sees the worklist created by Thread 2 and ends up unlocking the worklist thread's lock that is supposedly held by Thread 2.

Thereafter, chaos ensues.

The fix is to cache the worklists that were actually suspended by each GC pass,
and only resume those when the GC is done.

This issue was discovered by enabling COLLECT_ON_EVERY_ALLOCATION and running
the fast/workers layout tests.

  • heap/Heap.cpp:

(JSC::Heap::visitCompilerWorklists):
(JSC::Heap::deleteAllCompiledCode):
(JSC::Heap::suspendCompilerThreads):
(JSC::Heap::resumeCompilerThreads):

  • heap/Heap.h:
Location:
trunk/Source/JavaScriptCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r167729 r167733  
     12014-04-23  Mark Lam  <mark.lam@apple.com>
     2
     3        The GC should only resume compiler threads that it suspended in the same GC pass.
     4        <https://webkit.org/b/132088>
     5
     6        Reviewed by Mark Hahnenberg.
     7
     8        Previously, this scenario can occur:
     9        1. Thread 1 starts a GC and tries to suspend DFG worklist threads.  However,
     10           no worklists were created yet at the that time.
     11        2. Thread 2 starts to compile some functions and creates a DFG worklist, and
     12           acquires the worklist thread's lock.
     13        3. Thread 1's GC completes and tries to resume suspended DFG worklist thread.
     14           This time, it sees the worklist created by Thread 2 and ends up unlocking
     15           the worklist thread's lock that is supposedly held by Thread 2.
     16        Thereafter, chaos ensues.
     17
     18        The fix is to cache the worklists that were actually suspended by each GC pass,
     19        and only resume those when the GC is done.
     20
     21        This issue was discovered by enabling COLLECT_ON_EVERY_ALLOCATION and running
     22        the fast/workers layout tests.
     23
     24        * heap/Heap.cpp:
     25        (JSC::Heap::visitCompilerWorklists):
     26        (JSC::Heap::deleteAllCompiledCode):
     27        (JSC::Heap::suspendCompilerThreads):
     28        (JSC::Heap::resumeCompilerThreads):
     29        * heap/Heap.h:
     30
    1312014-04-23  Mark Hahnenberg  <mhahnenberg@apple.com>
    232
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r167326 r167733  
    627627#if ENABLE(DFG_JIT)
    628628    GCPHASE(VisitDFGWorklists);
    629     for (unsigned i = DFG::numberOfWorklists(); i--;) {
    630         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
    631             worklist->visitChildren(m_slotVisitor, m_codeBlocks);
    632     }
     629    for (auto worklist : m_suspendedCompilerWorklists)
     630        worklist->visitChildren(m_slotVisitor, m_codeBlocks);
    633631
    634632    if (Options::logGC() == GCLogging::Verbose)
     
    882880    // recompilations isn't a good idea.
    883881#if ENABLE(DFG_JIT)
    884     for (unsigned i = DFG::numberOfWorklists(); i--;) {
    885         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
    886             if (worklist->isActiveForVM(*vm()))
    887                 return;
    888         }
     882    for (auto worklist : m_suspendedCompilerWorklists) {
     883        if (worklist->isActiveForVM(*vm()))
     884            return;
    889885    }
    890886#endif // ENABLE(DFG_JIT)
     
    10231019#if ENABLE(DFG_JIT)
    10241020    GCPHASE(SuspendCompilerThreads);
     1021    ASSERT(m_suspendedCompilerWorklists.isEmpty());
    10251022    for (unsigned i = DFG::numberOfWorklists(); i--;) {
    1026         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
     1023        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
     1024            m_suspendedCompilerWorklists.append(worklist);
    10271025            worklist->suspendAllThreads();
     1026        }
    10281027    }
    10291028#endif
     
    12281227#if ENABLE(DFG_JIT)
    12291228    GCPHASE(ResumeCompilerThreads);
    1230     for (unsigned i = DFG::numberOfWorklists(); i--;) {
    1231         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
    1232             worklist->resumeAllThreads();
    1233     }
     1229    for (auto worklist : m_suspendedCompilerWorklists)
     1230        worklist->resumeAllThreads();
     1231    m_suspendedCompilerWorklists.clear();
    12341232#endif
    12351233}
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r167326 r167733  
    7171class WeakGCHandlePool;
    7272class SlotVisitor;
     73
     74namespace DFG {
     75class Worklist;
     76}
    7377
    7478typedef std::pair<JSValue, WTF::String> ValueStringPair;
     
    374378   
    375379    unsigned m_deferralDepth;
     380    Vector<DFG::Worklist*> m_suspendedCompilerWorklists;
    376381};
    377382
Note: See TracChangeset for help on using the changeset viewer.