Changeset 121381 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Jun 27, 2012, 4:08:26 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/APIShims.h
r121098 r121381 29 29 #include "CallFrame.h" 30 30 #include "GCActivityCallback.h" 31 #include "IncrementalSweeper.h" 31 32 #include "JSLock.h" 32 33 #include <wtf/WTFThreadData.h> … … 35 36 36 37 class APIEntryShimWithoutLock { 38 public: 39 enum RefGlobalDataTag { DontRefGlobalData = 0, RefGlobalData }; 40 37 41 protected: 38 APIEntryShimWithoutLock(JSGlobalData* globalData, bool registerThread) 39 : m_globalData(globalData) 42 APIEntryShimWithoutLock(JSGlobalData* globalData, bool registerThread, RefGlobalDataTag shouldRefGlobalData) 43 : m_shouldRefGlobalData(shouldRefGlobalData) 44 , m_globalData(globalData) 40 45 , m_entryIdentifierTable(wtfThreadData().setCurrentIdentifierTable(globalData->identifierTable)) 41 46 { 47 if (shouldRefGlobalData) 48 m_globalData->ref(); 42 49 UNUSED_PARAM(registerThread); 43 50 if (registerThread) 44 51 globalData->heap.machineThreads().addCurrentThread(); 45 52 m_globalData->heap.activityCallback()->synchronize(); 46 m_globalData-> timeoutChecker.start();53 m_globalData->heap.sweeper()->synchronize(); 47 54 } 48 55 49 56 ~APIEntryShimWithoutLock() 50 57 { 51 m_globalData->timeoutChecker.stop();52 58 wtfThreadData().setCurrentIdentifierTable(m_entryIdentifierTable); 59 if (m_shouldRefGlobalData) 60 m_globalData->deref(); 53 61 } 54 62 55 private: 63 protected: 64 RefGlobalDataTag m_shouldRefGlobalData; 56 65 JSGlobalData* m_globalData; 57 66 IdentifierTable* m_entryIdentifierTable; … … 62 71 // Normal API entry 63 72 APIEntryShim(ExecState* exec, bool registerThread = true) 64 : APIEntryShimWithoutLock(&exec->globalData(), registerThread) 65 , m_lock(exec) 73 : APIEntryShimWithoutLock(&exec->globalData(), registerThread, RefGlobalData) 66 74 { 75 init(); 76 } 77 78 // This constructor is necessary for HeapTimer to prevent it from accidentally resurrecting 79 // the ref count of a "dead" JSGlobalData. 80 APIEntryShim(JSGlobalData* globalData, RefGlobalDataTag refGlobalData, bool registerThread = true) 81 : APIEntryShimWithoutLock(globalData, registerThread, refGlobalData) 82 { 83 init(); 67 84 } 68 85 69 86 // JSPropertyNameAccumulator only has a globalData. 70 87 APIEntryShim(JSGlobalData* globalData, bool registerThread = true) 71 : APIEntryShimWithoutLock(globalData, registerThread) 72 , m_lock(globalData->isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 88 : APIEntryShimWithoutLock(globalData, registerThread, RefGlobalData) 73 89 { 90 init(); 91 } 92 93 ~APIEntryShim() 94 { 95 m_globalData->timeoutChecker.stop(); 96 m_globalData->apiLock().unlock(); 74 97 } 75 98 76 99 private: 77 JSLock m_lock; 100 void init() 101 { 102 m_globalData->apiLock().lock(); 103 m_globalData->timeoutChecker.start(); 104 } 78 105 }; 79 106 … … 89 116 ~APICallbackShim() 90 117 { 91 m_globalData->heap.activityCallback()->synchronize();92 118 wtfThreadData().setCurrentIdentifierTable(m_globalData->identifierTable); 93 119 } -
trunk/Source/JavaScriptCore/API/JSContextRef.cpp
r121098 r121381 79 79 // we use a shared one for backwards compatibility. 80 80 if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) { 81 JSLock lock(LockForReal);82 81 return JSGlobalContextCreateInGroup(toRef(&JSGlobalData::sharedInstance()), globalObjectClass); 83 82 } … … 91 90 initializeThreading(); 92 91 93 JSLock lock(LockForReal);94 92 RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup(ThreadStackTypeSmall); 95 93 96 94 APIEntryShim entryShim(globalData.get(), false); 97 98 95 globalData->makeUsableFromMultipleThreads(); 99 96 … … 125 122 void JSGlobalContextRelease(JSGlobalContextRef ctx) 126 123 { 127 ExecState* exec = toJS(ctx); 128 JSLock lock(exec); 129 130 JSGlobalData& globalData = exec->globalData(); 131 IdentifierTable* savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(globalData.identifierTable); 132 133 bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject()); 134 if (protectCountIsZero) { 135 globalData.heap.activityCallback()->synchronize(); 136 globalData.heap.reportAbandonedObjectGraph(); 137 } 138 globalData.deref(); 124 IdentifierTable* savedIdentifierTable; 125 ExecState* exec = toJS(ctx); 126 { 127 JSLockHolder lock(exec); 128 129 JSGlobalData& globalData = exec->globalData(); 130 savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(globalData.identifierTable); 131 132 bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject()); 133 if (protectCountIsZero) 134 globalData.heap.reportAbandonedObjectGraph(); 135 globalData.deref(); 136 } 139 137 140 138 wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable); … … 167 165 { 168 166 ExecState* exec = toJS(ctx); 169 JSLock lock(exec);167 JSLockHolder lock(exec); 170 168 171 169 unsigned count = 0; -
trunk/Source/JavaScriptCore/ChangeLog
r121374 r121381 1 2012-06-25 Mark Hahnenberg <[email protected]> 2 3 JSLock should be per-JSGlobalData 4 https://bugs.webkit.org/show_bug.cgi?id=89123 5 6 Reviewed by Geoffrey Garen. 7 8 * API/APIShims.h: 9 (APIEntryShimWithoutLock): 10 (JSC::APIEntryShimWithoutLock::APIEntryShimWithoutLock): Added an extra parameter to the constructor to 11 determine whether we should ref the JSGlobalData or not. We want to ref all the time except for in the 12 HeapTimer class because timerDidFire could run after somebody has started to tear down that particular 13 JSGlobalData, so we wouldn't want to resurrect the ref count of that JSGlobalData from 0 back to 1 after 14 its destruction has begun. 15 (JSC::APIEntryShimWithoutLock::~APIEntryShimWithoutLock): 16 (JSC::APIEntryShim::APIEntryShim): 17 (APIEntryShim): 18 (JSC::APIEntryShim::~APIEntryShim): 19 (JSC::APIEntryShim::init): Factored out common initialization code for the various APIEntryShim constructors. 20 Also moved the timeoutChecker stop and start here because we need to start after we've grabbed the API lock 21 and before we've released it, which can only done in APIEntryShim. 22 (JSC::APICallbackShim::~APICallbackShim): We no longer need to synchronize here. 23 * API/JSContextRef.cpp: 24 (JSGlobalContextCreate): 25 (JSGlobalContextCreateInGroup): 26 (JSGlobalContextRelease): 27 (JSContextCreateBacktrace): 28 * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: 29 * heap/CopiedSpace.cpp: 30 (JSC::CopiedSpace::tryAllocateSlowCase): 31 * heap/Heap.cpp: 32 (JSC::Heap::protect): 33 (JSC::Heap::unprotect): 34 (JSC::Heap::collect): 35 (JSC::Heap::setActivityCallback): 36 (JSC::Heap::activityCallback): 37 (JSC::Heap::sweeper): 38 * heap/Heap.h: Changed m_activityCallback and m_sweeper to be raw pointers rather than OwnPtrs because they 39 are now responsible for their own lifetime. Also changed the order of declaration of the GCActivityCallback 40 and the IncrementalSweeper to make sure they're the last things that get initialized during construction to 41 prevent any issues with uninitialized memory in the JSGlobalData/Heap they might care about. 42 (Heap): 43 * heap/HeapTimer.cpp: Refactored to allow for thread-safe operation and shutdown. 44 (JSC::HeapTimer::~HeapTimer): 45 (JSC::HeapTimer::invalidate): 46 (JSC): 47 (JSC::HeapTimer::didStartVMShutdown): Called at the beginning of ~JSGlobalData. If we're on the same thread 48 that the HeapTimer is running on, we kill the HeapTimer ourselves. If not, then we set some state in the 49 HeapTimer and schedule it to fire immediately so that it can notice and kill itself. 50 (JSC::HeapTimer::timerDidFire): We grab our mutex and check our JSGlobalData pointer. If it has been zero-ed 51 out, then we know the VM has started to shutdown and we should kill ourselves. Otherwise, grab the APIEntryShim, 52 but without ref-ing the JSGlobalData (we don't want to bring the JSGlobalData's ref-count from 0 to 1) in case 53 we were interrupted between releasing our mutex and trying to grab the APILock. 54 * heap/HeapTimer.h: 55 (HeapTimer): 56 * heap/IncrementalSweeper.cpp: 57 (JSC::IncrementalSweeper::doWork): We no longer need the API shim here since HeapTimer::timerDidFire handles 58 all of that for us. 59 (JSC::IncrementalSweeper::create): 60 * heap/IncrementalSweeper.h: 61 (IncrementalSweeper): 62 * heap/MarkedAllocator.cpp: 63 (JSC::MarkedAllocator::allocateSlowCase): 64 * heap/WeakBlock.cpp: 65 (JSC::WeakBlock::reap): 66 * jsc.cpp: 67 (functionGC): 68 (functionReleaseExecutableMemory): 69 (jscmain): 70 * runtime/Completion.cpp: 71 (JSC::checkSyntax): 72 (JSC::evaluate): 73 * runtime/GCActivityCallback.h: 74 (DefaultGCActivityCallback): 75 (JSC::DefaultGCActivityCallback::create): 76 * runtime/JSGlobalData.cpp: 77 (JSC::JSGlobalData::JSGlobalData): 78 (JSC::JSGlobalData::~JSGlobalData): Signals to the two HeapTimers (GCActivityCallback and IncrementalSweeper) 79 that the VM has started shutting down. It then waits until the HeapTimer is done with whatever activity 80 it needs to do before continuing with any further destruction. Also asserts that we do not currently hold the 81 APILock because this could potentially cause deadlock when we try to signal to the HeapTimers using their mutexes. 82 (JSC::JSGlobalData::sharedInstance): Protect the initialization for the shared instance with the GlobalJSLock. 83 (JSC::JSGlobalData::sharedInstanceInternal): 84 * runtime/JSGlobalData.h: Change to be ThreadSafeRefCounted so that we don't have to worry about refing and 85 de-refing JSGlobalDatas on separate threads since we don't do it that often anyways. 86 (JSGlobalData): 87 (JSC::JSGlobalData::apiLock): 88 * runtime/JSGlobalObject.cpp: 89 (JSC::JSGlobalObject::~JSGlobalObject): 90 (JSC::JSGlobalObject::init): 91 * runtime/JSLock.cpp: 92 (JSC): 93 (JSC::GlobalJSLock::GlobalJSLock): For accessing the shared instance. 94 (JSC::GlobalJSLock::~GlobalJSLock): 95 (JSC::JSLockHolder::JSLockHolder): MutexLocker for JSLock. Also refs the JSGlobalData to keep it alive so that 96 it can successfully unlock it later without it disappearing from underneath it. 97 (JSC::JSLockHolder::~JSLockHolder): 98 (JSC::JSLock::JSLock): 99 (JSC::JSLock::~JSLock): 100 (JSC::JSLock::lock): Uses the spin lock for guarding the lock count and owner thread fields. Uses the mutex for 101 actually waiting for long periods. 102 (JSC::JSLock::unlock): 103 (JSC::JSLock::currentThreadIsHoldingLock): 104 (JSC::JSLock::dropAllLocks): 105 (JSC::JSLock::dropAllLocksUnconditionally): 106 (JSC::JSLock::grabAllLocks): 107 (JSC::JSLock::DropAllLocks::DropAllLocks): 108 (JSC::JSLock::DropAllLocks::~DropAllLocks): 109 * runtime/JSLock.h: 110 (JSC): 111 (GlobalJSLock): 112 (JSLockHolder): 113 (JSLock): 114 (DropAllLocks): 115 * runtime/WeakGCMap.h: 116 (JSC::WeakGCMap::set): 117 * testRegExp.cpp: 118 (realMain): 119 1 120 2012-06-27 Filip Pizlo <[email protected]> 2 121 -
trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
r121215 r121381 7 7 ??0DateInstance@JSC@@IAE@PAVExecState@1@PAVStructure@1@@Z 8 8 ??0DefaultGCActivityCallback@JSC@@QAE@PAVHeap@1@@Z 9 ??0DropAllLocks@JSLock@JSC@@QAE@W4JSLockBehavior@2@@Z 9 ??0DropAllLocks@JSLock@JSC@@QAE@PAVExecState@2@@Z 10 ??0DropAllLocks@JSLock@JSC@@QAE@PAVJSGlobalData@2@@Z 10 11 ??0DynamicGlobalObjectScope@JSC@@QAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@@Z 11 12 ??0InternalFunction@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@@Z 12 13 ??0JSGlobalObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@PBUGlobalObjectMethodTable@1@@Z 13 ??0JSLock@JSC@@QAE@PAVExecState@1@@Z 14 ??0JSLockHolder@JSC@@QAE@AAVJSGlobalData@1@@Z 15 ??0JSLockHolder@JSC@@QAE@PAVExecState@1@@Z 16 ??0JSLockHolder@JSC@@QAE@PAVJSGlobalData@1@@Z 14 17 ??0MD5@WTF@@QAE@XZ 15 18 ??0Mutex@WTF@@QAE@XZ … … 34 37 ??1JSGlobalData@JSC@@QAE@XZ 35 38 ??1JSGlobalObject@JSC@@QAE@XZ 39 ??1JSLockHolder@JSC@@QAE@XZ 36 40 ??1Mutex@WTF@@QAE@XZ 37 41 ??1RefCountedLeakCounter@WTF@@QAE@XZ … … 125 129 ?cryptographicallyRandomValues@WTF@@YAXPAXI@Z 126 130 ?currentThread@WTF@@YAIXZ 127 ?currentThreadIsHoldingLock@JSLock@JSC@@SA_NXZ128 131 ?currentTime@WTF@@YANXZ 129 132 ?data@CString@WTF@@QBEPBDXZ … … 237 240 ?jsString@JSC@@YAPAVJSString@1@PAVJSGlobalData@1@ABVUString@1@@Z 238 241 ?length@CString@WTF@@QBEIXZ 239 ?lock@JSLock@JSC@@ SAXW4JSLockBehavior@2@@Z242 ?lock@JSLock@JSC@@QAEXXZ 240 243 ?lock@Mutex@WTF@@QAEXXZ 241 244 ?lockAtomicallyInitializedStaticMutex@WTF@@YAXXZ 242 ?lockCount@JSLock@JSC@@SAHXZ243 245 ?match@RegExp@JSC@@QAEHAAVJSGlobalData@2@ABVUString@2@IAAV?$Vector@H$0CA@@WTF@@@Z 244 246 ?materializePropertyMap@Structure@JSC@@AAEXAAVJSGlobalData@2@@Z … … 325 327 ?substringSharingImpl@UString@JSC@@QBE?AV12@II@Z 326 328 ?suggestedNewPropertyStorageSize@Structure@JSC@@QAEIXZ 329 ?sweeper@Heap@JSC@@QAEPAVIncrementalSweeper@2@XZ 327 330 ?synthesizePrototype@JSValue@JSC@@QBEPAVJSObject@2@PAVExecState@2@@Z 328 331 ?thisObject@DebuggerCallFrame@JSC@@QBEPAVJSObject@2@XZ … … 354 357 ?tryLock@Mutex@WTF@@QAE_NXZ 355 358 ?type@DebuggerCallFrame@JSC@@QBE?AW4Type@12@XZ 356 ?unlock@JSLock@JSC@@ SAXW4JSLockBehavior@2@@Z359 ?unlock@JSLock@JSC@@QAEXXZ 357 360 ?unlock@Mutex@WTF@@QAEXXZ 358 361 ?unlockAtomicallyInitializedStaticMutex@WTF@@YAXXZ -
trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp
r121098 r121381 67 67 return tryAllocateOversize(bytes, outPtr); 68 68 69 ASSERT(m_heap->globalData()->apiLock().currentThreadIsHoldingLock()); 69 70 m_heap->didAllocate(m_allocator.currentCapacity()); 70 71 -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r121098 r121381 161 161 } 162 162 163 static inline bool isValidSharedInstanceThreadState() 164 { 165 if (!JSLock::lockCount()) 166 return false; 167 168 if (!JSLock::currentThreadIsHoldingLock()) 169 return false; 170 171 return true; 163 static inline bool isValidSharedInstanceThreadState(JSGlobalData* globalData) 164 { 165 return globalData->apiLock().currentThreadIsHoldingLock(); 172 166 } 173 167 … … 177 171 return false; 178 172 179 if (globalData->isSharedInstance() && !isValidSharedInstanceThreadState( ))173 if (globalData->isSharedInstance() && !isValidSharedInstanceThreadState(globalData)) 180 174 return false; 181 175 … … 328 322 { 329 323 ASSERT(k); 330 ASSERT( JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());324 ASSERT(m_globalData->apiLock().currentThreadIsHoldingLock()); 331 325 332 326 if (!k.isCell()) … … 339 333 { 340 334 ASSERT(k); 341 ASSERT( JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());335 ASSERT(m_globalData->apiLock().currentThreadIsHoldingLock()); 342 336 343 337 if (!k.isCell()) … … 693 687 694 688 GCPHASE(Collect); 689 ASSERT(globalData()->apiLock().currentThreadIsHoldingLock()); 695 690 ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); 696 691 ASSERT(m_isSafeToCollect); … … 778 773 } 779 774 780 void Heap::setActivityCallback( PassOwnPtr<GCActivityCallback>activityCallback)775 void Heap::setActivityCallback(GCActivityCallback* activityCallback) 781 776 { 782 777 m_activityCallback = activityCallback; … … 785 780 GCActivityCallback* Heap::activityCallback() 786 781 { 787 return m_activityCallback .get();782 return m_activityCallback; 788 783 } 789 784 790 785 IncrementalSweeper* Heap::sweeper() 791 786 { 792 return m_sweeper .get();787 return m_sweeper; 793 788 } 794 789 -
trunk/Source/JavaScriptCore/heap/Heap.h
r121098 r121381 100 100 101 101 JS_EXPORT_PRIVATE GCActivityCallback* activityCallback(); 102 JS_EXPORT_PRIVATE void setActivityCallback( PassOwnPtr<GCActivityCallback>);102 JS_EXPORT_PRIVATE void setActivityCallback(GCActivityCallback*); 103 103 JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool); 104 104 105 IncrementalSweeper* sweeper();105 JS_EXPORT_PRIVATE IncrementalSweeper* sweeper(); 106 106 107 107 // true if an allocation or collection is in progress … … 238 238 double m_lastCodeDiscardTime; 239 239 240 OwnPtr<GCActivityCallback> m_activityCallback;241 OwnPtr<IncrementalSweeper> m_sweeper;242 243 240 DoublyLinkedList<ExecutableBase> m_compiledCode; 241 242 GCActivityCallback* m_activityCallback; 243 IncrementalSweeper* m_sweeper; 244 244 }; 245 245 -
trunk/Source/JavaScriptCore/heap/HeapTimer.cpp
r121098 r121381 27 27 #include "HeapTimer.h" 28 28 29 #include "APIShims.h" 30 #include "JSObject.h" 31 #include "JSString.h" 32 #include "ScopeChain.h" 29 33 #include <wtf/Threading.h> 30 34 … … 47 51 HeapTimer::~HeapTimer() 48 52 { 49 invalidate(); 53 CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); 54 CFRunLoopTimerInvalidate(m_timer.get()); 50 55 } 51 56 … … 61 66 void HeapTimer::invalidate() 62 67 { 63 CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); 64 CFRunLoopTimerInvalidate(m_timer.get()); 68 m_globalData = 0; 69 CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() - s_decade); 70 } 71 72 void HeapTimer::didStartVMShutdown() 73 { 74 if (CFRunLoopGetCurrent() == m_runLoop.get()) { 75 invalidate(); 76 delete this; 77 return; 78 } 79 ASSERT(!m_globalData->apiLock().currentThreadIsHoldingLock()); 80 MutexLocker locker(m_shutdownMutex); 81 invalidate(); 65 82 } 66 83 … … 68 85 { 69 86 HeapTimer* agent = static_cast<HeapTimer*>(info); 70 agent->doWork(); 87 agent->m_shutdownMutex.lock(); 88 if (!agent->m_globalData) { 89 agent->m_shutdownMutex.unlock(); 90 delete agent; 91 return; 92 } 93 { 94 // We don't ref here to prevent us from resurrecting the ref count of a "dead" JSGlobalData. 95 APIEntryShim shim(agent->m_globalData, APIEntryShimWithoutLock::DontRefGlobalData); 96 agent->doWork(); 97 } 98 agent->m_shutdownMutex.unlock(); 71 99 } 72 100 … … 82 110 } 83 111 112 void HeapTimer::didStartVMShutdown() 113 { 114 delete this; 115 } 116 84 117 void HeapTimer::synchronize() 85 118 { … … 90 123 } 91 124 92 93 125 #endif 94 126 -
trunk/Source/JavaScriptCore/heap/HeapTimer.h
r121098 r121381 28 28 29 29 #include <wtf/RetainPtr.h> 30 #include <wtf/Threading.h> 30 31 31 32 #if USE(CF) … … 47 48 48 49 virtual ~HeapTimer(); 49 50 51 void didStartVMShutdown(); 50 52 virtual void synchronize(); 51 53 virtual void doWork() = 0; … … 60 62 RetainPtr<CFRunLoopRef> m_runLoop; 61 63 CFRunLoopTimerContext m_context; 64 65 Mutex m_shutdownMutex; 62 66 #endif 63 67 -
trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp
r121316 r121381 46 46 void IncrementalSweeper::doWork() 47 47 { 48 APIEntryShim shim(m_globalData);49 48 doSweep(WTF::monotonicallyIncreasingTime()); 50 49 } … … 56 55 } 57 56 58 PassOwnPtr<IncrementalSweeper>IncrementalSweeper::create(Heap* heap)57 IncrementalSweeper* IncrementalSweeper::create(Heap* heap) 59 58 { 60 return adoptPtr(new IncrementalSweeper(heap, CFRunLoopGetCurrent()));59 return new IncrementalSweeper(heap, CFRunLoopGetCurrent()); 61 60 } 62 61 … … 111 110 } 112 111 113 PassOwnPtr<IncrementalSweeper>IncrementalSweeper::create(Heap* heap)112 IncrementalSweeper* IncrementalSweeper::create(Heap* heap) 114 113 { 115 return adoptPtr(new IncrementalSweeper(heap->globalData()));114 return new IncrementalSweeper(heap->globalData()); 116 115 } 117 116 -
trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h
r121098 r121381 40 40 class IncrementalSweeper : public HeapTimer { 41 41 public: 42 static PassOwnPtr<IncrementalSweeper>create(Heap*);42 static IncrementalSweeper* create(Heap*); 43 43 void startSweeping(const HashSet<MarkedBlock*>& blockSnapshot); 44 44 virtual void doWork(); -
trunk/Source/JavaScriptCore/heap/MarkedAllocator.cpp
r121098 r121381 4 4 #include "GCActivityCallback.h" 5 5 #include "Heap.h" 6 #include "JSGlobalData.h" 6 7 #include <wtf/CurrentTime.h> 7 8 … … 57 58 void* MarkedAllocator::allocateSlowCase() 58 59 { 60 ASSERT(m_heap->globalData()->apiLock().currentThreadIsHoldingLock()); 59 61 #if COLLECT_ON_EVERY_ALLOCATION 60 62 m_heap->collectAllGarbage(); -
trunk/Source/JavaScriptCore/heap/WeakBlock.cpp
r121098 r121381 128 128 continue; 129 129 130 if (Heap::isMarked(weakImpl->jsValue().asCell())) 130 if (Heap::isMarked(weakImpl->jsValue().asCell())) { 131 ASSERT(weakImpl->state() == WeakImpl::Live); 131 132 continue; 133 } 132 134 133 135 weakImpl->setState(WeakImpl::Dead); -
trunk/Source/JavaScriptCore/jsc.cpp
r121098 r121381 300 300 EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec) 301 301 { 302 JSLock lock(SilenceAssertionsOnly);302 JSLockHolder lock(exec); 303 303 exec->heap()->collectAllGarbage(); 304 304 return JSValue::encode(jsUndefined()); … … 308 308 EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec) 309 309 { 310 JSLock lock(SilenceAssertionsOnly);310 JSLockHolder lock(exec); 311 311 exec->globalData().releaseExecutableMemory(); 312 312 return JSValue::encode(jsUndefined()); … … 668 668 int jscmain(int argc, char** argv) 669 669 { 670 JSLock lock(SilenceAssertionsOnly); 671 670 672 671 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap); 672 JSLockHolder lock(globalData.get()); 673 673 674 674 CommandLine options; -
trunk/Source/JavaScriptCore/runtime/Completion.cpp
r121098 r121381 38 38 bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException) 39 39 { 40 JSLock lock(exec);40 JSLockHolder lock(exec); 41 41 ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); 42 42 … … 54 54 JSValue evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& source, JSValue thisValue, JSValue* returnedException) 55 55 { 56 JSLock lock(exec);56 JSLockHolder lock(exec); 57 57 ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); 58 58 if (exec->globalData().isCollectorBusy()) -
trunk/Source/JavaScriptCore/runtime/GCActivityCallback.h
r121098 r121381 70 70 class DefaultGCActivityCallback : public GCActivityCallback { 71 71 public: 72 static PassOwnPtr<DefaultGCActivityCallback>create(Heap*);72 static DefaultGCActivityCallback* create(Heap*); 73 73 74 74 DefaultGCActivityCallback(Heap*); … … 92 92 }; 93 93 94 inline PassOwnPtr<DefaultGCActivityCallback>DefaultGCActivityCallback::create(Heap* heap)94 inline DefaultGCActivityCallback* DefaultGCActivityCallback::create(Heap* heap) 95 95 { 96 return adoptPtr(new DefaultGCActivityCallback(heap));96 return new DefaultGCActivityCallback(heap); 97 97 } 98 98 -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp
r121098 r121381 35 35 #include "DebuggerActivation.h" 36 36 #include "FunctionConstructor.h" 37 #include "GCActivityCallback.h" 37 38 #include "GetterSetter.h" 38 39 #include "HostCallReturnValue.h" 40 #include "IncrementalSweeper.h" 39 41 #include "Interpreter.h" 40 42 #include "JSActivation.h" … … 179 181 interpreter = new Interpreter; 180 182 181 if (isSharedInstance())182 turnOffVerifier();183 184 183 // Need to be careful to keep everything consistent here 184 JSLockHolder lock(this); 185 185 IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable); 186 JSLock lock(SilenceAssertionsOnly);187 186 structureStructure.set(*this, Structure::createStructure(*this)); 188 187 debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull())); … … 223 222 JSGlobalData::~JSGlobalData() 224 223 { 224 ASSERT(!m_apiLock.currentThreadIsHoldingLock()); 225 heap.activityCallback()->didStartVMShutdown(); 226 heap.sweeper()->didStartVMShutdown(); 225 227 heap.lastChanceToFinalize(); 226 228 … … 312 314 JSGlobalData& JSGlobalData::sharedInstance() 313 315 { 316 GlobalJSLock globalLock; 314 317 JSGlobalData*& instance = sharedInstanceInternal(); 315 318 if (!instance) { … … 322 325 JSGlobalData*& JSGlobalData::sharedInstanceInternal() 323 326 { 324 ASSERT(JSLock::currentThreadIsHoldingLock());325 327 static JSGlobalData* sharedInstance; 326 328 return sharedInstance; -
trunk/Source/JavaScriptCore/runtime/JSGlobalData.h
r121098 r121381 36 36 #include "Intrinsic.h" 37 37 #include "JITStubs.h" 38 #include "JSLock.h" 38 39 #include "JSValue.h" 39 40 #include "LLIntData.h" … … 47 48 #include <wtf/Forward.h> 48 49 #include <wtf/HashMap.h> 49 #include <wtf/RefCounted.h>50 50 #include <wtf/SimpleStats.h> 51 #include <wtf/ThreadSafeRefCounted.h> 51 52 #include <wtf/ThreadSpecific.h> 52 53 #include <wtf/WTFThreadData.h> … … 153 154 #endif 154 155 155 class JSGlobalData : public RefCounted<JSGlobalData> {156 class JSGlobalData : public ThreadSafeRefCounted<JSGlobalData> { 156 157 public: 157 158 // WebCore has a one-to-one mapping of threads to JSGlobalDatas; … … 181 182 void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); } 182 183 184 private: 185 JSLock m_apiLock; 186 187 public: 183 188 Heap heap; // The heap is our first data member to ensure that it's destructed after all the objects that reference it. 184 189 … … 410 415 #undef registerTypedArrayFunction 411 416 417 JSLock& apiLock() { return m_apiLock; } 418 412 419 private: 413 420 friend class LLIntOffsetsExtractor; -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r121215 r121381 124 124 JSGlobalObject::~JSGlobalObject() 125 125 { 126 ASSERT(JSLock::currentThreadIsHoldingLock());127 128 126 if (m_debugger) 129 127 m_debugger->detach(this); … … 140 138 void JSGlobalObject::init(JSObject* thisValue) 141 139 { 142 ASSERT( JSLock::currentThreadIsHoldingLock());140 ASSERT(globalData().apiLock().currentThreadIsHoldingLock()); 143 141 144 142 m_globalScopeChain.set(globalData(), this, ScopeChainNode::create(0, this, &globalData(), this, thisValue)); -
trunk/Source/JavaScriptCore/runtime/JSLock.cpp
r121098 r121381 24 24 #include "Heap.h" 25 25 #include "CallFrame.h" 26 #include "JSGlobalObject.h" 26 27 #include "JSObject.h" 27 28 #include "ScopeChain.h" … … 38 39 #if (OS(DARWIN) || USE(PTHREADS)) 39 40 40 // Acquire this mutex before accessing lock-related data. 41 static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER; 42 43 // Thread-specific key that tells whether a thread holds the JSMutex, and how many times it was taken recursively. 44 pthread_key_t JSLockCount; 45 46 static void createJSLockCount() 47 { 48 pthread_key_create(&JSLockCount, 0); 49 } 50 51 pthread_once_t createJSLockCountOnce = PTHREAD_ONCE_INIT; 52 53 // Lock nesting count. 54 intptr_t JSLock::lockCount() 55 { 56 pthread_once(&createJSLockCountOnce, createJSLockCount); 57 58 return reinterpret_cast<intptr_t>(pthread_getspecific(JSLockCount)); 59 } 60 61 static void setLockCount(intptr_t count) 62 { 63 ASSERT(count >= 0); 64 pthread_setspecific(JSLockCount, reinterpret_cast<void*>(count)); 65 } 66 67 JSLock::JSLock(ExecState* exec) 68 : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 69 { 70 lock(m_lockBehavior); 71 } 72 73 JSLock::JSLock(JSGlobalData* globalData) 74 : m_lockBehavior(globalData->isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 75 { 76 lock(m_lockBehavior); 77 } 78 79 void JSLock::lock(JSLockBehavior lockBehavior) 80 { 81 #ifdef NDEBUG 82 // Locking "not for real" is a debug-only feature. 83 if (lockBehavior == SilenceAssertionsOnly) 84 return; 85 #endif 86 87 pthread_once(&createJSLockCountOnce, createJSLockCount); 88 89 intptr_t currentLockCount = lockCount(); 90 if (!currentLockCount && lockBehavior == LockForReal) { 91 int result = pthread_mutex_lock(&JSMutex); 92 ASSERT_UNUSED(result, !result); 41 static pthread_mutex_t sharedInstanceLock = PTHREAD_MUTEX_INITIALIZER; 42 43 GlobalJSLock::GlobalJSLock() 44 { 45 pthread_mutex_lock(&sharedInstanceLock); 46 } 47 48 GlobalJSLock::~GlobalJSLock() 49 { 50 pthread_mutex_unlock(&sharedInstanceLock); 51 } 52 53 JSLockHolder::JSLockHolder(ExecState* exec) 54 : m_globalData(&exec->globalData()) 55 { 56 m_globalData->apiLock().lock(); 57 } 58 59 JSLockHolder::JSLockHolder(JSGlobalData* globalData) 60 : m_globalData(globalData) 61 { 62 m_globalData->apiLock().lock(); 63 } 64 65 JSLockHolder::JSLockHolder(JSGlobalData& globalData) 66 : m_globalData(&globalData) 67 { 68 m_globalData->apiLock().lock(); 69 } 70 71 JSLockHolder::~JSLockHolder() 72 { 73 m_globalData->apiLock().unlock(); 74 } 75 76 JSLock::JSLock() 77 : m_lockCount(0) 78 { 79 m_spinLock.Init(); 80 } 81 82 JSLock::~JSLock() 83 { 84 } 85 86 void JSLock::lock() 87 { 88 ThreadIdentifier currentThread = WTF::currentThread(); 89 { 90 SpinLockHolder holder(&m_spinLock); 91 if (m_ownerThread == currentThread && m_lockCount) { 92 m_lockCount++; 93 return; 94 } 93 95 } 94 setLockCount(currentLockCount + 1); 95 } 96 97 void JSLock::unlock(JSLockBehavior lockBehavior) 98 { 99 ASSERT(lockCount()); 100 101 #ifdef NDEBUG 102 // Locking "not for real" is a debug-only feature. 103 if (lockBehavior == SilenceAssertionsOnly) 104 return; 105 #endif 106 107 intptr_t newLockCount = lockCount() - 1; 108 setLockCount(newLockCount); 109 if (!newLockCount && lockBehavior == LockForReal) { 110 int result = pthread_mutex_unlock(&JSMutex); 111 ASSERT_UNUSED(result, !result); 96 97 m_lock.lock(); 98 99 { 100 SpinLockHolder holder(&m_spinLock); 101 m_ownerThread = currentThread; 102 ASSERT(!m_lockCount); 103 m_lockCount = 1; 112 104 } 113 105 } 114 106 107 void JSLock::unlock() 108 { 109 ASSERT(currentThreadIsHoldingLock()); 110 111 SpinLockHolder holder(&m_spinLock); 112 m_lockCount--; 113 114 if (!m_lockCount) 115 m_lock.unlock(); 116 } 117 115 118 void JSLock::lock(ExecState* exec) 116 119 { 117 lock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly);120 exec->globalData().apiLock().lock(); 118 121 } 119 122 120 123 void JSLock::unlock(ExecState* exec) 121 124 { 122 unlock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly);125 exec->globalData().apiLock().unlock(); 123 126 } 124 127 125 128 bool JSLock::currentThreadIsHoldingLock() 126 129 { 127 pthread_once(&createJSLockCountOnce, createJSLockCount); 128 return !!pthread_getspecific(JSLockCount); 130 return m_lockCount && m_ownerThread == WTF::currentThread(); 129 131 } 130 132 … … 150 152 // write over the second thread's call frames. 151 153 // 152 // Inavoid JS stack corruption we enforce a policy of only ever allowing two154 // To avoid JS stack corruption we enforce a policy of only ever allowing two 153 155 // threads to use a JS context concurrently, and only allowing the second of 154 156 // these threads to execute until it has completed and fully returned from its … … 159 161 // again through a callback, then the locks will not be dropped when DropAllLocks 160 162 // is called (since lockDropDepth is non-zero). Since this thread is still holding 161 // the locks, only it will re able to re-enter JSC (either be returning from the163 // the locks, only it will be able to re-enter JSC (either be returning from the 162 164 // callback, or by re-entering through another call to evaulate script or call 163 165 // function). … … 169 171 // would likely increase complexity and overhead. 170 172 // 171 static unsigned lockDropDepth = 0; 173 174 // This function returns the number of locks that were dropped. 175 unsigned JSLock::dropAllLocks() 176 { 177 if (m_lockDropDepth++) 178 return 0; 179 180 return dropAllLocksUnconditionally(); 181 } 182 183 unsigned JSLock::dropAllLocksUnconditionally() 184 { 185 unsigned lockCount = m_lockCount; 186 for (unsigned i = 0; i < lockCount; i++) 187 unlock(); 188 189 return lockCount; 190 } 191 192 void JSLock::grabAllLocks(unsigned lockCount) 193 { 194 for (unsigned i = 0; i < lockCount; i++) 195 lock(); 196 197 m_lockDropDepth--; 198 } 172 199 173 200 JSLock::DropAllLocks::DropAllLocks(ExecState* exec) 174 : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 175 { 176 pthread_once(&createJSLockCountOnce, createJSLockCount); 177 178 if (lockDropDepth++) { 179 m_lockCount = 0; 180 return; 181 } 182 183 m_lockCount = JSLock::lockCount(); 184 for (intptr_t i = 0; i < m_lockCount; i++) 185 JSLock::unlock(m_lockBehavior); 186 } 187 188 JSLock::DropAllLocks::DropAllLocks(JSLockBehavior JSLockBehavior) 189 : m_lockBehavior(JSLockBehavior) 190 { 191 pthread_once(&createJSLockCountOnce, createJSLockCount); 192 193 if (lockDropDepth++) { 194 m_lockCount = 0; 195 return; 196 } 197 198 // It is necessary to drop even "unreal" locks, because having a non-zero lock count 199 // will prevent a real lock from being taken. 200 201 m_lockCount = JSLock::lockCount(); 202 for (intptr_t i = 0; i < m_lockCount; i++) 203 JSLock::unlock(m_lockBehavior); 201 : m_lockCount(0) 202 , m_globalData(&exec->globalData()) 203 { 204 m_lockCount = m_globalData->apiLock().dropAllLocks(); 205 } 206 207 JSLock::DropAllLocks::DropAllLocks(JSGlobalData* globalData) 208 : m_lockCount(0) 209 , m_globalData(globalData) 210 { 211 m_lockCount = m_globalData->apiLock().dropAllLocks(); 204 212 } 205 213 206 214 JSLock::DropAllLocks::~DropAllLocks() 207 215 { 208 for (intptr_t i = 0; i < m_lockCount; i++) 209 JSLock::lock(m_lockBehavior); 210 211 --lockDropDepth; 216 m_globalData->apiLock().grabAllLocks(m_lockCount); 212 217 } 213 218 214 219 #else // (OS(DARWIN) || USE(PTHREADS)) 215 220 216 JSLock::JSLock(ExecState*) 217 : m_lockBehavior(SilenceAssertionsOnly) 218 { 219 } 220 221 // If threading support is off, set the lock count to a constant value of 1 so ssertions 222 // that the lock is held don't fail 223 intptr_t JSLock::lockCount() 224 { 225 return 1; 221 GlobalJSLock::GlobalJSLock() 222 { 223 } 224 225 GlobalJSLock::~GlobalJSLock() 226 { 227 } 228 229 JSLockHolder::JSLockHolder(JSGlobalData*) 230 { 231 } 232 233 JSLockHolder::JSLockHolder(JSGlobalData&) 234 { 235 } 236 237 JSLockHolder::JSLockHolder(ExecState*) 238 { 239 } 240 241 JSLockHolder::~JSLockHolder() 242 { 243 } 244 245 JSLock::JSLock() 246 { 247 } 248 249 JSLock::~JSLock() 250 { 226 251 } 227 252 … … 231 256 } 232 257 233 void JSLock::lock( JSLockBehavior)234 { 235 } 236 237 void JSLock::unlock( JSLockBehavior)258 void JSLock::lock() 259 { 260 } 261 262 void JSLock::unlock() 238 263 { 239 264 } … … 247 272 } 248 273 274 void JSLock::lock(JSGlobalData&) 275 { 276 } 277 278 void JSLock::unlock(JSGlobalData&) 279 { 280 } 281 282 unsigned JSLock::dropAllLocks() 283 { 284 return 0; 285 } 286 287 unsigned JSLock::dropAllLocksUnconditionally() 288 { 289 return 0; 290 } 291 292 void JSLock::grabAllLocks(unsigned) 293 { 294 } 295 249 296 JSLock::DropAllLocks::DropAllLocks(ExecState*) 250 297 { 251 298 } 252 299 253 JSLock::DropAllLocks::DropAllLocks(JS LockBehavior)300 JSLock::DropAllLocks::DropAllLocks(JSGlobalData*) 254 301 { 255 302 } -
trunk/Source/JavaScriptCore/runtime/JSLock.h
r121098 r121381 24 24 #include <wtf/Assertions.h> 25 25 #include <wtf/Noncopyable.h> 26 #include <wtf/RefPtr.h> 27 #include <wtf/TCSpinLock.h> 28 #include <wtf/Threading.h> 26 29 27 30 namespace JSC { … … 31 34 // JavaScript data structure or that interacts with shared state 32 35 // such as the protect count hash table. The simplest way to lock 33 // is to create a local JSLock object in the scope where the lock 34 // must be held. The lock is recursive so nesting is ok. The JSLock 36 // is to create a local JSLockHolder object in the scope where the lock 37 // must be held and pass it the context that requires protection. 38 // The lock is recursive so nesting is ok. The JSLock 35 39 // object also acts as a convenience short-hand for running important 36 40 // initialization routines. … … 45 49 // thread acquired it to begin with. 46 50 47 // For contexts other than the single shared one, implicit locking is not done,48 // but we still need to perform all the counting in order to keep debug49 // assertions working, so that clients that use the shared context don't break.50 51 51 class ExecState; 52 52 class JSGlobalData; 53 53 54 enum JSLockBehavior { SilenceAssertionsOnly, LockForReal }; 54 // This class is used to protect the initialization of the legacy single 55 // shared JSGlobalData. 56 class GlobalJSLock { 57 WTF_MAKE_NONCOPYABLE(GlobalJSLock); 58 public: 59 JS_EXPORT_PRIVATE GlobalJSLock(); 60 JS_EXPORT_PRIVATE ~GlobalJSLock(); 61 }; 62 63 class JSLockHolder { 64 public: 65 JS_EXPORT_PRIVATE JSLockHolder(JSGlobalData*); 66 JS_EXPORT_PRIVATE JSLockHolder(JSGlobalData&); 67 JS_EXPORT_PRIVATE JSLockHolder(ExecState*); 68 69 JS_EXPORT_PRIVATE ~JSLockHolder(); 70 private: 71 RefPtr<JSGlobalData> m_globalData; 72 }; 55 73 56 74 class JSLock { 57 75 WTF_MAKE_NONCOPYABLE(JSLock); 58 76 public: 59 JS _EXPORT_PRIVATE JSLock(ExecState*);60 JS Lock(JSGlobalData*);77 JSLock(); 78 JS_EXPORT_PRIVATE ~JSLock(); 61 79 62 JSLock(JSLockBehavior lockBehavior) 63 : m_lockBehavior(lockBehavior) 64 { 65 #ifdef NDEBUG 66 // Locking "not for real" is a debug-only feature. 67 if (lockBehavior == SilenceAssertionsOnly) 68 return; 69 #endif 70 lock(lockBehavior); 71 } 80 JS_EXPORT_PRIVATE void lock(); 81 JS_EXPORT_PRIVATE void unlock(); 72 82 73 ~JSLock()74 {75 #ifdef NDEBUG76 // Locking "not for real" is a debug-only feature.77 if (m_lockBehavior == SilenceAssertionsOnly)78 return;79 #endif80 unlock(m_lockBehavior);81 }82 83 JS_EXPORT_PRIVATE static void lock(JSLockBehavior);84 JS_EXPORT_PRIVATE static void unlock(JSLockBehavior);85 83 static void lock(ExecState*); 86 84 static void unlock(ExecState*); 85 static void lock(JSGlobalData&); 86 static void unlock(JSGlobalData&); 87 87 88 JS_EXPORT_PRIVATE static intptr_t lockCount(); 89 JS_EXPORT_PRIVATE static bool currentThreadIsHoldingLock(); 88 JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock(); 90 89 91 JSLockBehavior m_lockBehavior; 90 unsigned dropAllLocks(); 91 unsigned dropAllLocksUnconditionally(); 92 void grabAllLocks(unsigned lockCount); 93 94 SpinLock m_spinLock; 95 Mutex m_lock; 96 ThreadIdentifier m_ownerThread; 97 intptr_t m_lockCount; 98 unsigned m_lockDropDepth; 92 99 93 100 class DropAllLocks { … … 95 102 public: 96 103 JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec); 97 JS_EXPORT_PRIVATE DropAllLocks(JS LockBehavior);104 JS_EXPORT_PRIVATE DropAllLocks(JSGlobalData*); 98 105 JS_EXPORT_PRIVATE ~DropAllLocks(); 99 106 100 107 private: 101 108 intptr_t m_lockCount; 102 JSLockBehavior m_lockBehavior;109 RefPtr<JSGlobalData> m_globalData; 103 110 }; 104 111 }; -
trunk/Source/JavaScriptCore/runtime/WeakGCMap.h
r121098 r121381 76 76 } 77 77 78 void set(JSGlobalData& , const KeyType& key, ExternalType value)78 void set(JSGlobalData& globalData, const KeyType& key, ExternalType value) 79 79 { 80 ASSERT_UNUSED(globalData, globalData.apiLock().currentThreadIsHoldingLock()); 80 81 typename MapType::AddResult result = m_map.add(key, 0); 81 82 if (!result.isNewEntry) -
trunk/Source/JavaScriptCore/testRegExp.cpp
r121098 r121381 496 496 int realMain(int argc, char** argv) 497 497 { 498 JSLock lock(SilenceAssertionsOnly);499 500 498 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap); 499 JSLockHolder lock(globalData.get()); 501 500 502 501 CommandLine options;
Note:
See TracChangeset
for help on using the changeset viewer.