Ignore:
Timestamp:
Oct 14, 2013, 12:34:44 PM (12 years ago)
Author:
[email protected]
Message:

llint_slow_path_put_by_id can deadlock on a ConcurrentJITLock
https://bugs.webkit.org/show_bug.cgi?id=122667

Reviewed by Filip Pizlo.

The issue this patch is attempting to fix is that there are places in our codebase
where we acquire the ConcurrentJITLock for a particular CodeBlock, then we do some
operations that can initiate a garbage collection. Garbage collection then calls
some methods of CodeBlock that also take the ConcurrentJITLock (because they don't
always necessarily run during garbage collection). This causes a deadlock.

To fix this issue, this patch adds a new RAII-style object (DisallowGC) that stores
into a thread-local field that indicates that it is unsafe to perform any operation
that could trigger garbage collection on the current thread. In debug builds,
ConcurrentJITLocker contains one of these DisallowGC objects so that we can eagerly
detect deadlocks.

This patch also adds a new type of ConcurrentJITLocker, GCSafeConcurrentJITLocker,
which uses the DeferGC mechanism to prevent collections from occurring while the
lock is held.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • heap/DeferGC.cpp: Added.
  • heap/DeferGC.h:

(JSC::DisallowGC::DisallowGC):
(JSC::DisallowGC::~DisallowGC):
(JSC::DisallowGC::isGCDisallowedOnCurrentThread):
(JSC::DisallowGC::initialize):

  • jit/JITStubs.cpp:

(JSC::tryCachePutByID):
(JSC::tryCacheGetByID):
(JSC::DEFINE_STUB_FUNCTION):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/ConcurrentJITLock.h:

(JSC::ConcurrentJITLockerBase::ConcurrentJITLockerBase):
(JSC::ConcurrentJITLockerBase::~ConcurrentJITLockerBase):
(JSC::ConcurrentJITLockerBase::unlockEarly):
(JSC::GCSafeConcurrentJITLocker::GCSafeConcurrentJITLocker):
(JSC::ConcurrentJITLocker::ConcurrentJITLocker):

  • runtime/InitializeThreading.cpp:

(JSC::initializeThreadingOnce):

  • runtime/JSCellInlines.h:

(JSC::allocateCell):

  • runtime/Structure.cpp:

(JSC::Structure::materializePropertyMap):
(JSC::Structure::putSpecificValue):
(JSC::Structure::createPropertyMap):

  • runtime/Structure.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/ConcurrentJITLock.h

    r153169 r157413  
    2727#define ConcurrentJITLock_h
    2828
     29#include "DeferGC.h"
    2930#include <wtf/ByteSpinLock.h>
    3031#include <wtf/NoLock.h>
     
    3435#if ENABLE(CONCURRENT_JIT)
    3536typedef ByteSpinLock ConcurrentJITLock;
    36 typedef ByteSpinLocker ConcurrentJITLocker;
     37typedef ByteSpinLocker ConcurrentJITLockerImpl;
    3738#else
    3839typedef NoLock ConcurrentJITLock;
    39 typedef NoLockLocker ConcurrentJITLocker;
     40typedef NoLockLocker ConcurrentJITLockerImpl;
    4041#endif
     42
     43class ConcurrentJITLockerBase {
     44    WTF_MAKE_NONCOPYABLE(ConcurrentJITLockerBase);
     45public:
     46    explicit ConcurrentJITLockerBase(ConcurrentJITLock& lockable)
     47        : m_locker(&lockable)
     48    {
     49    }
     50    explicit ConcurrentJITLockerBase(ConcurrentJITLock* lockable)
     51        : m_locker(lockable)
     52    {
     53    }
     54
     55    ~ConcurrentJITLockerBase()
     56    {
     57    }
     58   
     59    void unlockEarly()
     60    {
     61        m_locker.unlockEarly();
     62    }
     63
     64private:
     65    ConcurrentJITLockerImpl m_locker;
     66};
     67
     68class GCSafeConcurrentJITLocker : public ConcurrentJITLockerBase {
     69public:
     70    GCSafeConcurrentJITLocker(ConcurrentJITLock& lockable, Heap& heap)
     71        : ConcurrentJITLockerBase(lockable)
     72        , m_deferGC(heap)
     73    {
     74    }
     75
     76    GCSafeConcurrentJITLocker(ConcurrentJITLock* lockable, Heap& heap)
     77        : ConcurrentJITLockerBase(lockable)
     78        , m_deferGC(heap)
     79    {
     80    }
     81
     82private:
     83#if ENABLE(CONCURRENT_JIT)
     84    DeferGC m_deferGC;
     85#else
     86    struct NoDefer {
     87        NoDefer(Heap& heap) : m_heap(heap) { }
     88        Heap& m_heap;
     89    };
     90    NoDefer m_deferGC;
     91#endif
     92};
     93
     94class ConcurrentJITLocker : public ConcurrentJITLockerBase {
     95public:
     96    ConcurrentJITLocker(ConcurrentJITLock& lockable)
     97        : ConcurrentJITLockerBase(lockable)
     98    {
     99    }
     100
     101    ConcurrentJITLocker(ConcurrentJITLock* lockable)
     102        : ConcurrentJITLockerBase(lockable)
     103    {
     104    }
     105
     106#if ENABLE(CONCURRENT_JIT) && !defined(NDEBUG)
     107private:
     108    DisallowGC m_disallowGC;
     109#endif
     110};
    41111
    42112} // namespace JSC
    43113
    44114#endif // ConcurrentJITLock_h
    45 
Note: See TracChangeset for help on using the changeset viewer.