Changeset 164627 in webkit


Ignore:
Timestamp:
Feb 24, 2014 8:44:09 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

Need to initialize VM stack data even when the VM is on an exclusive thread.
<https://webkit.org/b/129265>

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

We check VM::exclusiveThread as an optimization to forego the need to do
JSLock locking. However, we recently started piggy backing on JSLock's
lock() and unlock() to initialize VM stack data (stackPointerAtVMEntry
and lastStackTop) to appropriate values for the current thread. This is
needed because we may be acquiring the lock to enter the VM on a different
thread.

As a result, we ended up not initializing the VM stack data when
VM::exclusiveThread causes us to bypass the locking activity. Even though
the VM::exclusiveThread will not have to deal with the VM being entered
on a different thread, it still needs to initialize the VM stack data.
The VM relies on that data being initialized properly once it has been
entered.

With this fix, we push the check for exclusiveThread down into the JSLock,
and handle the bypassing of unneeded locking activity there while still
executing the necessary the VM stack data initialization.

  • API/APIShims.h:

(JSC::APIEntryShim::APIEntryShim):
(JSC::APICallbackShim::shouldDropAllLocks):

  • heap/MachineStackMarker.cpp:

(JSC::MachineThreads::addCurrentThread):

  • runtime/JSLock.cpp:

(JSC::JSLockHolder::JSLockHolder):
(JSC::JSLockHolder::init):
(JSC::JSLockHolder::~JSLockHolder):
(JSC::JSLock::JSLock):
(JSC::JSLock::setExclusiveThread):
(JSC::JSLock::lock):
(JSLock::unlock):
(JSLock::currentThreadIsHoldingLock):
(JSLock::dropAllLocks):
(JSLock::grabAllLocks):

  • runtime/JSLock.h:

(JSC::JSLock::exclusiveThread):

  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:

(JSC::VM::exclusiveThread):
(JSC::VM::setExclusiveThread):
(JSC::VM::currentThreadIsHoldingAPILock):

Source/WebCore:

No new tests.

  • bindings/js/JSDOMBinding.cpp:

(WebCore::reportException):

  • Added an assertion to ensure that we are holding the JSLock.
  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::JSDOMWindowBase::commonVM):

  • Updated to use the new VM::setExclusiveThread().
Location:
trunk/Source
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/APIShims.h

    r164147 r164627  
    5959    APIEntryShim(ExecState* exec, bool registerThread = true)
    6060        : APIEntryShimWithoutLock(&exec->vm(), registerThread)
    61         , m_lockHolder(exec->vm().exclusiveThread ? 0 : exec)
     61        , m_lockHolder(&exec->vm())
    6262    {
    6363    }
     
    6565    APIEntryShim(VM* vm, bool registerThread = true)
    6666        : APIEntryShimWithoutLock(vm, registerThread)
    67         , m_lockHolder(vm->exclusiveThread ? 0 : vm)
     67        , m_lockHolder(vm)
    6868    {
    6969    }
     
    103103    static bool shouldDropAllLocks(VM& vm)
    104104    {
    105         if (vm.exclusiveThread)
    106             return false;
    107 
    108105        // If the VM is in the middle of being destroyed then we don't want to resurrect it
    109106        // by allowing DropAllLocks to ref it. By this point the APILock has already been
  • trunk/Source/JavaScriptCore/ChangeLog

    r164620 r164627  
     12014-02-24  Mark Lam  <mark.lam@apple.com>
     2
     3        Need to initialize VM stack data even when the VM is on an exclusive thread.
     4        <https://webkit.org/b/129265>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        We check VM::exclusiveThread as an optimization to forego the need to do
     9        JSLock locking. However, we recently started piggy backing on JSLock's
     10        lock() and unlock() to initialize VM stack data (stackPointerAtVMEntry
     11        and lastStackTop) to appropriate values for the current thread. This is
     12        needed because we may be acquiring the lock to enter the VM on a different
     13        thread.
     14
     15        As a result, we ended up not initializing the VM stack data when
     16        VM::exclusiveThread causes us to bypass the locking activity. Even though
     17        the VM::exclusiveThread will not have to deal with the VM being entered
     18        on a different thread, it still needs to initialize the VM stack data.
     19        The VM relies on that data being initialized properly once it has been
     20        entered.
     21
     22        With this fix, we push the check for exclusiveThread down into the JSLock,
     23        and handle the bypassing of unneeded locking activity there while still
     24        executing the necessary the VM stack data initialization.
     25
     26        * API/APIShims.h:
     27        (JSC::APIEntryShim::APIEntryShim):
     28        (JSC::APICallbackShim::shouldDropAllLocks):
     29        * heap/MachineStackMarker.cpp:
     30        (JSC::MachineThreads::addCurrentThread):
     31        * runtime/JSLock.cpp:
     32        (JSC::JSLockHolder::JSLockHolder):
     33        (JSC::JSLockHolder::init):
     34        (JSC::JSLockHolder::~JSLockHolder):
     35        (JSC::JSLock::JSLock):
     36        (JSC::JSLock::setExclusiveThread):
     37        (JSC::JSLock::lock):
     38        (JSLock::unlock):
     39        (JSLock::currentThreadIsHoldingLock):
     40        (JSLock::dropAllLocks):
     41        (JSLock::grabAllLocks):
     42        * runtime/JSLock.h:
     43        (JSC::JSLock::exclusiveThread):
     44        * runtime/VM.cpp:
     45        (JSC::VM::VM):
     46        * runtime/VM.h:
     47        (JSC::VM::exclusiveThread):
     48        (JSC::VM::setExclusiveThread):
     49        (JSC::VM::currentThreadIsHoldingAPILock):
     50
    1512014-02-24  Filip Pizlo  <fpizlo@apple.com>
    252
  • trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp

    r164500 r164627  
    183183void MachineThreads::addCurrentThread()
    184184{
    185     ASSERT(!m_heap->vm()->exclusiveThread || m_heap->vm()->exclusiveThread == currentThread());
     185    ASSERT(!m_heap->vm()->hasExclusiveThread() || m_heap->vm()->exclusiveThread() == std::this_thread::get_id());
    186186
    187187    if (!m_threadSpecific || threadSpecificGet(m_threadSpecific))
  • trunk/Source/JavaScriptCore/runtime/JSLock.cpp

    r164484 r164627  
    5151
    5252JSLockHolder::JSLockHolder(ExecState* exec)
    53     : m_vm(exec ? &exec->vm() : 0)
     53    : m_vm(&exec->vm())
    5454{
    5555    init();
     
    7070void JSLockHolder::init()
    7171{
    72     if (m_vm)
    73         m_vm->apiLock().lock();
     72    m_vm->apiLock().lock();
    7473}
    7574
    7675JSLockHolder::~JSLockHolder()
    7776{
    78     if (!m_vm)
    79         return;
    80 
    8177    RefPtr<JSLock> apiLock(&m_vm->apiLock());
    8278    m_vm.clear();
     
    8581
    8682JSLock::JSLock(VM* vm)
    87     : m_lockCount(0)
     83    : m_ownerThreadID(std::thread::id())
     84    , m_lockCount(0)
    8885    , m_lockDropDepth(0)
     86    , m_hasExclusiveThread(false)
    8987    , m_vm(vm)
    9088{
     
    9997    ASSERT_UNUSED(vm, m_vm == vm);
    10098    m_vm = 0;
     99}
     100
     101void JSLock::setExclusiveThread(std::thread::id threadId)
     102{
     103    RELEASE_ASSERT(!m_lockCount && m_ownerThreadID == std::thread::id());
     104    m_hasExclusiveThread = (threadId != std::thread::id());
     105    m_ownerThreadID = threadId;
    101106}
    102107
     
    114119    }
    115120
    116     m_lock.lock();
    117 
    118     m_ownerThreadID = std::this_thread::get_id();
     121    if (!m_hasExclusiveThread) {
     122        m_lock.lock();
     123        m_ownerThreadID = std::this_thread::get_id();
     124    }
    119125    ASSERT(!m_lockCount);
    120126    m_lockCount = lockCount;
     
    122128    if (!m_vm)
    123129        return;
    124 
    125     WTFThreadData& threadData = wtfThreadData();
    126130
    127131    RELEASE_ASSERT(!m_vm->stackPointerAtVMEntry());
     
    129133    m_vm->setStackPointerAtVMEntry(p);
    130134
     135    WTFThreadData& threadData = wtfThreadData();
    131136    m_vm->setLastStackTop(threadData.savedLastStackTop());
    132137}
     
    147152        if (m_vm)
    148153            m_vm->setStackPointerAtVMEntry(nullptr);
    149         m_ownerThreadID = std::thread::id();
    150         m_lock.unlock();
     154
     155        if (!m_hasExclusiveThread) {
     156            m_ownerThreadID = std::thread::id();
     157            m_lock.unlock();
     158        }
    151159    }
    152160}
     
    164172bool JSLock::currentThreadIsHoldingLock()
    165173{
     174    ASSERT(!m_hasExclusiveThread || (exclusiveThread() == std::this_thread::get_id()));
     175    if (m_hasExclusiveThread)
     176        return !!m_lockCount;
    166177    return m_ownerThreadID == std::this_thread::get_id();
    167178}
     
    170181unsigned JSLock::dropAllLocks(DropAllLocks* dropper)
    171182{
     183    if (m_hasExclusiveThread) {
     184        ASSERT(exclusiveThread() == std::this_thread::get_id());
     185        return 0;
     186    }
     187
    172188    // Check if this thread is currently holding the lock.
    173189    // FIXME: Maybe we want to require this, guard with an ASSERT?
     
    194210void JSLock::grabAllLocks(DropAllLocks* dropper, unsigned droppedLockCount)
    195211{
     212    ASSERT(!m_hasExclusiveThread || !droppedLockCount);
     213
    196214    // If no locks were dropped, nothing to do!
    197215    if (!droppedLockCount)
  • trunk/Source/JavaScriptCore/runtime/JSLock.h

    r164484 r164627  
    9595        VM* vm() { return m_vm; }
    9696
     97        bool hasExclusiveThread() const { return m_hasExclusiveThread; }
     98        std::thread::id exclusiveThread() const
     99        {
     100            ASSERT(m_hasExclusiveThread);
     101            return m_ownerThreadID;
     102        }
     103        JS_EXPORT_PRIVATE void setExclusiveThread(std::thread::id);
    97104        JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock();
    98105
     
    130137        intptr_t m_lockCount;
    131138        unsigned m_lockDropDepth;
     139        bool m_hasExclusiveThread;
    132140        VM* m_vm;
    133141    };
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r164347 r164627  
    209209    , m_rtTraceList(new RTTraceList())
    210210#endif
    211     , exclusiveThread(0)
    212211    , m_newStringsSinceLastHashCons(0)
    213212#if ENABLE(ASSEMBLER)
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r164347 r164627  
    464464#endif
    465465
    466         ThreadIdentifier exclusiveThread;
     466        bool hasExclusiveThread() const { return m_apiLock->hasExclusiveThread(); }
     467        std::thread::id exclusiveThread() const { return m_apiLock->exclusiveThread(); }
     468        void setExclusiveThread(std::thread::id threadId) { m_apiLock->setExclusiveThread(threadId); }
    467469
    468470        JS_EXPORT_PRIVATE void resetDateCache();
     
    492494        void resetNewStringsSinceLastHashCons() { m_newStringsSinceLastHashCons = 0; }
    493495
    494         bool currentThreadIsHoldingAPILock() const
    495         {
    496             return m_apiLock->currentThreadIsHoldingLock() || exclusiveThread == currentThread();
    497         }
     496        bool currentThreadIsHoldingAPILock() const { return m_apiLock->currentThreadIsHoldingLock(); }
    498497
    499498        JSLock& apiLock() { return *m_apiLock; }
  • trunk/Source/WebCore/ChangeLog

    r164624 r164627  
     12014-02-24  Mark Lam  <mark.lam@apple.com>
     2
     3        Need to initialize VM stack data even when the VM is on an exclusive thread.
     4        <https://webkit.org/b/129265>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        No new tests.
     9
     10        * bindings/js/JSDOMBinding.cpp:
     11        (WebCore::reportException):
     12        - Added an assertion to ensure that we are holding the JSLock.
     13        * bindings/js/JSDOMWindowBase.cpp:
     14        (WebCore::JSDOMWindowBase::commonVM):
     15        - Updated to use the new VM::setExclusiveThread().
     16
    1172014-02-24  Anders Carlsson  <andersca@apple.com>
    218
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp

    r164554 r164627  
    154154void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScript)
    155155{
     156    RELEASE_ASSERT(exec->vm().currentThreadIsHoldingAPILock());
    156157    if (isTerminatedExecutionException(exception))
    157158        return;
  • trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp

    r164347 r164627  
    225225        vm->heap.machineThreads().addCurrentThread();
    226226#else
    227         vm->exclusiveThread = currentThread();
     227        vm->setExclusiveThread(std::this_thread::get_id());
    228228#endif // !PLATFORM(IOS)
    229229        initNormalWorldClientData(vm);
Note: See TracChangeset for help on using the changeset viewer.