Changeset 163855 in webkit
- Timestamp:
- Feb 10, 2014 8:48:01 PM (10 years ago)
- Location:
- trunk/Source
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r163851 r163855 1 2014-02-10 Mark Lam <mark.lam@apple.com> 2 3 Removing limitation on JSLock's lockDropDepth. 4 <https://webkit.org/b/128570> 5 6 Reviewed by Geoffrey Garen. 7 8 Now that we've switched to using the C stack, we no longer need to limit 9 the JSLock::lockDropDepth to 2. 10 11 For C loop builds which still use the separate JSStack, the JSLock will 12 enforce ordering for re-grabbing the lock after dropping it. Re-grabbing 13 must occur in the reverse order of the dropping of the locks. 14 15 Ordering is achieved by JSLock::dropAllLocks() stashing away the 16 JSLock:: m_lockDropDepth in its DropAllLocks instance's m_dropDepth 17 before unlocking the lock. Subsequently, JSLock::grabAllLocks() will 18 ensure that JSLocks::m_lockDropDepth equals its DropAllLocks instance's 19 m_dropDepth before allowing the lock to be re-grabbed. Otherwise, it 20 will yield execution and retry again later. 21 22 Note: because JSLocks::m_lockDropDepth is protected by the JSLock's 23 mutex, grabAllLocks() will optimistically lock the JSLock before doing 24 the check on m_lockDropDepth. If the check fails, it will unlock the 25 JSLock, yield, and then relock it again later before retrying the check. 26 This ensures that m_lockDropDepth remains under the protection of the 27 JSLock's mutex. 28 29 * runtime/JSLock.cpp: 30 (JSC::JSLock::dropAllLocks): 31 (JSC::JSLock::grabAllLocks): 32 (JSC::JSLock::DropAllLocks::DropAllLocks): 33 (JSC::JSLock::DropAllLocks::~DropAllLocks): 34 * runtime/JSLock.h: 35 (JSC::JSLock::DropAllLocks::setDropDepth): 36 (JSC::JSLock::DropAllLocks::dropDepth): 37 1 38 2014-02-10 Filip Pizlo <fpizlo@apple.com> 2 39 -
trunk/Source/JavaScriptCore/runtime/JSLock.cpp
r163844 r163855 27 27 #include "JSObject.h" 28 28 #include "JSCInlines.h" 29 #if ENABLE(LLINT_C_LOOP) 30 #include <thread> 31 #endif 29 32 30 33 namespace JSC { … … 167 170 } 168 171 169 // This is fairly nasty. We allow multiple threads to run on the same170 // context, and we do not require any locking semantics in doing so -171 // clients of the API may simply use the context from multiple threads172 // concurently, and assume this will work. In order to make this work,173 // We lock the context when a thread enters, and unlock it when it leaves.174 // However we do not only unlock when the thread returns from its175 // entry point (evaluate script or call function), we also unlock the176 // context if the thread leaves JSC by making a call out to an external177 // function through a callback.178 //179 // All threads using the context share the same JS stack (the JSStack).180 // Whenever a thread calls into JSC it starts using the JSStack from the181 // previous 'high water mark' - the maximum point the stack has ever grown to182 // (returned by JSStack::end()). So if a first thread calls out to a183 // callback, and a second thread enters JSC, then also exits by calling out184 // to a callback, we can be left with stackframes from both threads in the185 // JSStack. As such, a problem may occur should the first thread's186 // callback complete first, and attempt to return to JSC. Were we to allow187 // this to happen, and were its stack to grow further, then it may potentially188 // write over the second thread's call frames.189 //190 // To avoid JS stack corruption we enforce a policy of only ever allowing two191 // threads to use a JS context concurrently, and only allowing the second of192 // these threads to execute until it has completed and fully returned from its193 // outermost call into JSC. We enforce this policy using 'lockDropDepth'. The194 // first time a thread exits it will call DropAllLocks - which will do as expected195 // and drop locks allowing another thread to enter. Should another thread, or the196 // same thread again, enter JSC (through evaluate script or call function), and exit197 // again through a callback, then the locks will not be dropped when DropAllLocks198 // is called (since lockDropDepth is non-zero). Since this thread is still holding199 // the locks, only it will be able to re-enter JSC (either be returning from the200 // callback, or by re-entering through another call to evaulate script or call201 // function).202 //203 // This policy is slightly more restricive than it needs to be for correctness -204 // we could validly allow futher entries into JSC from other threads, we only205 // need ensure that callbacks return in the reverse chronological order of the206 // order in which they were made - though implementing the less restrictive policy207 // would likely increase complexity and overhead.208 //209 210 172 // This function returns the number of locks that were dropped. 211 unsigned JSLock::dropAllLocks( )173 unsigned JSLock::dropAllLocks(DropAllLocks* dropper) 212 174 { 213 175 // Check if this thread is currently holding the lock. … … 216 178 return 0; 217 179 218 // Don't drop the locks if they've already been dropped once. 219 // (If the prior drop came from another thread, and it resumed first, 220 // it could trash our register file). 221 if (m_lockDropDepth) 222 return 0; 180 ++m_lockDropDepth; 181 182 UNUSED_PARAM(dropper); 183 #if ENABLE(LLINT_C_LOOP) 184 dropper->setDropDepth(m_lockDropDepth); 185 #endif 223 186 224 187 WTFThreadData& threadData = wtfThreadData(); … … 227 190 threadData.setSavedReservedZoneSize(m_vm->reservedZoneSize()); 228 191 229 // m_lockDropDepth is only incremented if any locks were dropped.230 ++m_lockDropDepth;231 232 192 unsigned droppedLockCount = m_lockCount; 233 193 unlock(droppedLockCount); … … 236 196 } 237 197 238 unsigned JSLock::dropAllLocksUnconditionally() 239 { 240 // Check if this thread is currently holding the lock. 241 // FIXME: Maybe we want to require this, guard with an ASSERT? 242 if (!currentThreadIsHoldingLock()) 243 return 0; 244 245 WTFThreadData& threadData = wtfThreadData(); 246 threadData.setSavedStackPointerAtVMEntry(m_vm->stackPointerAtVMEntry); 247 threadData.setSavedLastStackTop(m_vm->lastStackTop()); 248 threadData.setSavedReservedZoneSize(m_vm->reservedZoneSize()); 249 250 // m_lockDropDepth is only incremented if any locks were dropped. 251 ++m_lockDropDepth; 252 253 unsigned droppedLockCount = m_lockCount; 254 unlock(droppedLockCount); 255 256 return droppedLockCount; 257 } 258 259 void JSLock::grabAllLocks(unsigned droppedLockCount) 198 void JSLock::grabAllLocks(DropAllLocks* dropper, unsigned droppedLockCount) 260 199 { 261 200 // If no locks were dropped, nothing to do! … … 265 204 ASSERT(!currentThreadIsHoldingLock()); 266 205 lock(droppedLockCount); 206 207 UNUSED_PARAM(dropper); 208 #if ENABLE(LLINT_C_LOOP) 209 while (dropper->dropDepth() != m_lockDropDepth) { 210 unlock(droppedLockCount); 211 std::this_thread::yield(); 212 lock(droppedLockCount); 213 } 214 #endif 267 215 268 216 --m_lockDropDepth; … … 274 222 } 275 223 276 JSLock::DropAllLocks::DropAllLocks(ExecState* exec , AlwaysDropLocksTag alwaysDropLocks)224 JSLock::DropAllLocks::DropAllLocks(ExecState* exec) 277 225 : m_droppedLockCount(0) 278 226 , m_vm(exec ? &exec->vm() : nullptr) … … 280 228 if (!m_vm) 281 229 return; 282 283 if (alwaysDropLocks) 284 m_droppedLockCount = m_vm->apiLock().dropAllLocksUnconditionally(); 285 else 286 m_droppedLockCount = m_vm->apiLock().dropAllLocks(); 287 } 288 289 JSLock::DropAllLocks::DropAllLocks(VM* vm, AlwaysDropLocksTag alwaysDropLocks) 230 m_droppedLockCount = m_vm->apiLock().dropAllLocks(this); 231 } 232 233 JSLock::DropAllLocks::DropAllLocks(VM* vm) 290 234 : m_droppedLockCount(0) 291 235 , m_vm(vm) … … 293 237 if (!m_vm) 294 238 return; 295 296 if (alwaysDropLocks) 297 m_droppedLockCount = m_vm->apiLock().dropAllLocksUnconditionally(); 298 else 299 m_droppedLockCount = m_vm->apiLock().dropAllLocks(); 239 m_droppedLockCount = m_vm->apiLock().dropAllLocks(this); 300 240 } 301 241 … … 304 244 if (!m_vm) 305 245 return; 306 m_vm->apiLock().grabAllLocks( m_droppedLockCount);246 m_vm->apiLock().grabAllLocks(this, m_droppedLockCount); 307 247 } 308 248 -
trunk/Source/JavaScriptCore/runtime/JSLock.h
r163820 r163855 100 100 WTF_MAKE_NONCOPYABLE(DropAllLocks); 101 101 public: 102 // By default, we release all locks conditionally. Some clients, such as Mobile Safari, 103 // may require that we release all locks unconditionally. 104 enum AlwaysDropLocksTag { DontAlwaysDropLocks = 0, AlwaysDropLocks }; 105 JS_EXPORT_PRIVATE DropAllLocks(ExecState*, AlwaysDropLocksTag = DontAlwaysDropLocks); 106 JS_EXPORT_PRIVATE DropAllLocks(VM*, AlwaysDropLocksTag = DontAlwaysDropLocks); 102 JS_EXPORT_PRIVATE DropAllLocks(ExecState*); 103 JS_EXPORT_PRIVATE DropAllLocks(VM*); 107 104 JS_EXPORT_PRIVATE ~DropAllLocks(); 108 105 106 #if ENABLE(LLINT_C_LOOP) 107 void setDropDepth(unsigned depth) { m_dropDepth = depth; } 108 unsigned dropDepth() const { return m_dropDepth; } 109 #endif 110 109 111 private: 110 112 intptr_t m_droppedLockCount; 111 113 RefPtr<VM> m_vm; 114 #if ENABLE(LLINT_C_LOOP) 115 unsigned m_dropDepth; 116 #endif 112 117 }; 113 118 … … 117 122 void setOwnerThread(ThreadIdentifier owner) { m_ownerThread = owner; } 118 123 119 unsigned dropAllLocks(); 120 unsigned dropAllLocksUnconditionally(); 121 void grabAllLocks(unsigned lockCount); 124 unsigned dropAllLocks(DropAllLocks*); 125 void grabAllLocks(DropAllLocks*, unsigned lockCount); 122 126 123 127 Mutex m_lock; -
trunk/Source/WebCore/ChangeLog
r163854 r163855 1 2014-02-10 Mark Lam <mark.lam@apple.com> 2 3 Removing limitation on JSLock’s lockDropDepth. 4 <https://webkit.org/b/128570> 5 6 Reviewed by Geoffrey Garen. 7 8 No new tests. 9 10 * bindings/js/PageScriptDebugServer.cpp: 11 (WebCore::PageScriptDebugServer::runEventLoopWhilePaused): 12 * platform/ios/wak/WebCoreThread.mm: 13 (SendDelegateMessage): 14 (WebThreadRunOnMainThread): 15 - No longer need to specify AlwaysDropLocks, because DropAllLocks is 16 now always unconditional. 17 1 18 2014-02-10 Benjamin Poulain <benjamin@webkit.org> 2 19 -
trunk/Source/WebCore/bindings/js/PageScriptDebugServer.cpp
r163777 r163855 191 191 { 192 192 if (WebThreadIsEnabled()) 193 JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM() , JSC::JSLock::DropAllLocks::AlwaysDropLocks);193 JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM()); 194 194 WebRunLoopEnableNested(); 195 195 #endif -
trunk/Source/WebCore/platform/ios/wak/WebCoreThread.mm
r161603 r163855 211 211 { 212 212 // Code block created to scope JSC::JSLock::DropAllLocks outside of WebThreadLock() 213 JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM() , JSC::JSLock::DropAllLocks::AlwaysDropLocks);213 JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM()); 214 214 _WebThreadUnlock(); 215 215 … … 249 249 } 250 250 251 JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM() , JSC::JSLock::DropAllLocks::AlwaysDropLocks);251 JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM()); 252 252 _WebThreadUnlock(); 253 253
Note: See TracChangeset
for help on using the changeset viewer.