Changeset 235261 in webkit
- Timestamp:
- Aug 23, 2018 4:57:03 PM (6 years ago)
- Location:
- trunk/Source
- Files:
-
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r235254 r235261 1 2018-08-23 Saam barati <sbarati@apple.com> 2 3 JSRunLoopTimer may run part of a member function after it's destroyed 4 https://bugs.webkit.org/show_bug.cgi?id=188426 5 6 Reviewed by Mark Lam. 7 8 When I was reading the JSRunLoopTimer code, I noticed that it is possible 9 to end up running timer code after the class had been destroyed. 10 11 The issue I spotted was in this function: 12 ``` 13 void JSRunLoopTimer::timerDidFire() 14 { 15 JSLock* apiLock = m_apiLock.get(); 16 if (!apiLock) { 17 // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed. 18 return; 19 } 20 // HERE 21 std::lock_guard<JSLock> lock(*apiLock); 22 RefPtr<VM> vm = apiLock->vm(); 23 if (!vm) { 24 // The VM has been destroyed, so we should just give up. 25 return; 26 } 27 28 doWork(); 29 } 30 ``` 31 32 Look at the comment 'HERE'. Let's say that the timer callback thread gets context 33 switched before grabbing the API lock. Then, some other thread destroys the VM. 34 And let's say that the VM owns (perhaps transitively) this timer. Then, the 35 timer would run code and access member variables after it was destroyed. 36 37 This patch fixes this issue by introducing a new timer manager class. 38 This class manages timers on a per VM basis. When a timer is scheduled, 39 this class refs the timer. It also calls the timer callback while actively 40 maintaining a +1 ref to it. So, it's no longer possible to call the timer 41 callback after the timer has been destroyed. However, calling a timer callback 42 can still race with the VM being destroyed. We continue to detect this case and 43 bail out of the callback early. 44 45 This patch also removes a lot of duplicate code between GCActivityCallback 46 and JSRunLoopTimer. 47 48 * heap/EdenGCActivityCallback.cpp: 49 (JSC::EdenGCActivityCallback::doCollection): 50 (JSC::EdenGCActivityCallback::lastGCLength): 51 (JSC::EdenGCActivityCallback::deathRate): 52 * heap/EdenGCActivityCallback.h: 53 * heap/FullGCActivityCallback.cpp: 54 (JSC::FullGCActivityCallback::doCollection): 55 (JSC::FullGCActivityCallback::lastGCLength): 56 (JSC::FullGCActivityCallback::deathRate): 57 * heap/FullGCActivityCallback.h: 58 * heap/GCActivityCallback.cpp: 59 (JSC::GCActivityCallback::doWork): 60 (JSC::GCActivityCallback::scheduleTimer): 61 (JSC::GCActivityCallback::didAllocate): 62 (JSC::GCActivityCallback::willCollect): 63 (JSC::GCActivityCallback::cancel): 64 (JSC::GCActivityCallback::cancelTimer): Deleted. 65 (JSC::GCActivityCallback::nextFireTime): Deleted. 66 * heap/GCActivityCallback.h: 67 * heap/Heap.cpp: 68 (JSC::Heap::reportAbandonedObjectGraph): 69 (JSC::Heap::notifyIncrementalSweeper): 70 (JSC::Heap::updateAllocationLimits): 71 (JSC::Heap::didAllocate): 72 * heap/IncrementalSweeper.cpp: 73 (JSC::IncrementalSweeper::scheduleTimer): 74 (JSC::IncrementalSweeper::doWork): 75 (JSC::IncrementalSweeper::doSweep): 76 (JSC::IncrementalSweeper::sweepNextBlock): 77 (JSC::IncrementalSweeper::startSweeping): 78 (JSC::IncrementalSweeper::stopSweeping): 79 * heap/IncrementalSweeper.h: 80 * heap/StopIfNecessaryTimer.cpp: 81 (JSC::StopIfNecessaryTimer::doWork): 82 (JSC::StopIfNecessaryTimer::scheduleSoon): 83 * heap/StopIfNecessaryTimer.h: 84 * runtime/JSRunLoopTimer.cpp: 85 (JSC::epochTime): 86 (JSC::JSRunLoopTimer::Manager::timerDidFireCallback): 87 (JSC::JSRunLoopTimer::Manager::PerVMData::setRunLoop): 88 (JSC::JSRunLoopTimer::Manager::PerVMData::PerVMData): 89 (JSC::JSRunLoopTimer::Manager::PerVMData::~PerVMData): 90 (JSC::JSRunLoopTimer::Manager::timerDidFire): 91 (JSC::JSRunLoopTimer::Manager::shared): 92 (JSC::JSRunLoopTimer::Manager::registerVM): 93 (JSC::JSRunLoopTimer::Manager::unregisterVM): 94 (JSC::JSRunLoopTimer::Manager::scheduleTimer): 95 (JSC::JSRunLoopTimer::Manager::cancelTimer): 96 (JSC::JSRunLoopTimer::Manager::timeUntilFire): 97 (JSC::JSRunLoopTimer::Manager::didChangeRunLoop): 98 (JSC::JSRunLoopTimer::timerDidFire): 99 (JSC::JSRunLoopTimer::JSRunLoopTimer): 100 (JSC::JSRunLoopTimer::timeUntilFire): 101 (JSC::JSRunLoopTimer::setTimeUntilFire): 102 (JSC::JSRunLoopTimer::cancelTimer): 103 (JSC::JSRunLoopTimer::setRunLoop): Deleted. 104 (JSC::JSRunLoopTimer::timerDidFireCallback): Deleted. 105 (JSC::JSRunLoopTimer::scheduleTimer): Deleted. 106 * runtime/JSRunLoopTimer.h: 107 (JSC::JSRunLoopTimer::Manager::PerVMData::PerVMData): 108 * runtime/PromiseDeferredTimer.cpp: 109 (JSC::PromiseDeferredTimer::doWork): 110 (JSC::PromiseDeferredTimer::runRunLoop): 111 (JSC::PromiseDeferredTimer::addPendingPromise): 112 (JSC::PromiseDeferredTimer::hasPendingPromise): 113 (JSC::PromiseDeferredTimer::hasDependancyInPendingPromise): 114 (JSC::PromiseDeferredTimer::cancelPendingPromise): 115 (JSC::PromiseDeferredTimer::scheduleWorkSoon): 116 * runtime/PromiseDeferredTimer.h: 117 * runtime/VM.cpp: 118 (JSC::VM::VM): 119 (JSC::VM::~VM): 120 (JSC::VM::setRunLoop): 121 (JSC::VM::registerRunLoopTimer): Deleted. 122 (JSC::VM::unregisterRunLoopTimer): Deleted. 123 * runtime/VM.h: 124 (JSC::VM::runLoop const): 125 * wasm/js/WebAssemblyPrototype.cpp: 126 (JSC::webAssemblyModuleValidateAsyncInternal): 127 (JSC::instantiate): 128 (JSC::compileAndInstantiate): 129 (JSC::webAssemblyModuleInstantinateAsyncInternal): 130 (JSC::webAssemblyCompileStreamingInternal): 131 (JSC::webAssemblyInstantiateStreamingInternal): 132 1 133 2018-08-23 Mark Lam <mark.lam@apple.com> 2 134 -
trunk/Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp
r235152 r235261 37 37 } 38 38 39 void EdenGCActivityCallback::doCollection( )39 void EdenGCActivityCallback::doCollection(VM& vm) 40 40 { 41 m_vm->heap.collectAsync(CollectionScope::Eden);41 vm.heap.collectAsync(CollectionScope::Eden); 42 42 } 43 43 44 Seconds EdenGCActivityCallback::lastGCLength( )44 Seconds EdenGCActivityCallback::lastGCLength(Heap& heap) 45 45 { 46 return m_vm->heap.lastEdenGCLength();46 return heap.lastEdenGCLength(); 47 47 } 48 48 49 double EdenGCActivityCallback::deathRate( )49 double EdenGCActivityCallback::deathRate(Heap& heap) 50 50 { 51 Heap* heap = &m_vm->heap; 52 size_t sizeBefore = heap->sizeBeforeLastEdenCollection(); 53 size_t sizeAfter = heap->sizeAfterLastEdenCollection(); 51 size_t sizeBefore = heap.sizeBeforeLastEdenCollection(); 52 size_t sizeAfter = heap.sizeAfterLastEdenCollection(); 54 53 if (!sizeBefore) 55 54 return 1.0; -
trunk/Source/JavaScriptCore/heap/EdenGCActivityCallback.h
r235152 r235261 34 34 EdenGCActivityCallback(Heap*); 35 35 36 void doCollection( ) override;36 void doCollection(VM&) override; 37 37 38 38 protected: 39 Seconds lastGCLength( ) override;39 Seconds lastGCLength(Heap&) override; 40 40 double gcTimeSlice(size_t bytes) override; 41 double deathRate( ) override;41 double deathRate(Heap&) override; 42 42 }; 43 43 -
trunk/Source/JavaScriptCore/heap/FullGCActivityCallback.cpp
r235152 r235261 40 40 } 41 41 42 void FullGCActivityCallback::doCollection( )42 void FullGCActivityCallback::doCollection(VM& vm) 43 43 { 44 Heap& heap = m_vm->heap;44 Heap& heap = vm.heap; 45 45 m_didGCRecently = false; 46 46 … … 57 57 } 58 58 59 Seconds FullGCActivityCallback::lastGCLength( )59 Seconds FullGCActivityCallback::lastGCLength(Heap& heap) 60 60 { 61 return m_vm->heap.lastFullGCLength();61 return heap.lastFullGCLength(); 62 62 } 63 63 64 double FullGCActivityCallback::deathRate( )64 double FullGCActivityCallback::deathRate(Heap& heap) 65 65 { 66 Heap* heap = &m_vm->heap; 67 size_t sizeBefore = heap->sizeBeforeLastFullCollection(); 68 size_t sizeAfter = heap->sizeAfterLastFullCollection(); 66 size_t sizeBefore = heap.sizeBeforeLastFullCollection(); 67 size_t sizeAfter = heap.sizeAfterLastFullCollection(); 69 68 if (!sizeBefore) 70 69 return 1.0; -
trunk/Source/JavaScriptCore/heap/FullGCActivityCallback.h
r235152 r235261 34 34 FullGCActivityCallback(Heap*); 35 35 36 void doCollection( ) override;36 void doCollection(VM&) override; 37 37 38 38 bool didGCRecently() const { return m_didGCRecently; } … … 40 40 41 41 protected: 42 Seconds lastGCLength( ) override;42 Seconds lastGCLength(Heap&) override; 43 43 double gcTimeSlice(size_t bytes) override; 44 double deathRate( ) override;44 double deathRate(Heap&) override; 45 45 46 46 bool m_didGCRecently { false }; -
trunk/Source/JavaScriptCore/heap/GCActivityCallback.cpp
r235152 r235261 1 1 /* 2 * Copyright (C) 2010-201 7Apple Inc. All rights reserved.2 * Copyright (C) 2010-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 46 46 } 47 47 48 void GCActivityCallback::doWork( )48 void GCActivityCallback::doWork(VM& vm) 49 49 { 50 Heap* heap = &m_vm->heap;51 50 if (!isEnabled()) 52 51 return; 53 52 54 JSLockHolder locker(m_vm); 55 if (heap->isDeferred()) { 53 ASSERT(vm.currentThreadIsHoldingAPILock()); 54 Heap& heap = vm.heap; 55 if (heap.isDeferred()) { 56 56 scheduleTimer(0_s); 57 57 return; 58 58 } 59 59 60 doCollection( );60 doCollection(vm); 61 61 } 62 62 63 #if USE(CF)64 63 void GCActivityCallback::scheduleTimer(Seconds newDelay) 65 64 { … … 68 67 Seconds delta = m_delay - newDelay; 69 68 m_delay = newDelay; 70 CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta.seconds()); 69 if (auto timeUntilFire = this->timeUntilFire()) 70 setTimeUntilFire(*timeUntilFire - delta); 71 else 72 setTimeUntilFire(newDelay); 71 73 } 72 74 73 void GCActivityCallback::cancelTimer() 74 { 75 m_delay = s_decade; 76 CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds()); 77 } 78 79 MonotonicTime GCActivityCallback::nextFireTime() 80 { 81 return MonotonicTime::now() + Seconds(CFRunLoopTimerGetNextFireDate(m_timer.get()) - CFAbsoluteTimeGetCurrent()); 82 } 83 #else 84 void GCActivityCallback::scheduleTimer(Seconds newDelay) 85 { 86 if (newDelay * timerSlop > m_delay) 87 return; 88 Seconds delta = m_delay - newDelay; 89 m_delay = newDelay; 90 91 Seconds secondsUntilFire = m_timer.secondsUntilFire(); 92 m_timer.startOneShot(std::max<Seconds>(secondsUntilFire - delta, 0_s)); 93 } 94 95 void GCActivityCallback::cancelTimer() 96 { 97 m_delay = s_decade; 98 m_timer.startOneShot(s_decade); 99 } 100 101 MonotonicTime GCActivityCallback::nextFireTime() 102 { 103 return MonotonicTime::now() + m_timer.secondsUntilFire(); 104 } 105 #endif 106 107 void GCActivityCallback::didAllocate(size_t bytes) 75 void GCActivityCallback::didAllocate(Heap& heap, size_t bytes) 108 76 { 109 77 // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. … … 111 79 if (!bytes) 112 80 bytes = 1; 113 double bytesExpectedToReclaim = static_cast<double>(bytes) * deathRate( );114 Seconds newDelay = lastGCLength( ) / gcTimeSlice(bytesExpectedToReclaim);81 double bytesExpectedToReclaim = static_cast<double>(bytes) * deathRate(heap); 82 Seconds newDelay = lastGCLength(heap) / gcTimeSlice(bytesExpectedToReclaim); 115 83 scheduleTimer(newDelay); 116 84 } … … 118 86 void GCActivityCallback::willCollect() 119 87 { 120 cancel Timer();88 cancel(); 121 89 } 122 90 123 91 void GCActivityCallback::cancel() 124 92 { 93 m_delay = s_decade; 125 94 cancelTimer(); 126 95 } -
trunk/Source/JavaScriptCore/heap/GCActivityCallback.h
r235152 r235261 49 49 GCActivityCallback(Heap*); 50 50 51 void doWork( ) override;51 void doWork(VM&) override; 52 52 53 virtual void doCollection( ) = 0;53 virtual void doCollection(VM&) = 0; 54 54 55 v irtual void didAllocate(size_t);56 v irtual void willCollect();57 v irtual void cancel();55 void didAllocate(Heap&, size_t); 56 void willCollect(); 57 void cancel(); 58 58 bool isEnabled() const { return m_enabled; } 59 59 void setEnabled(bool enabled) { m_enabled = enabled; } … … 61 61 static bool s_shouldCreateGCTimer; 62 62 63 MonotonicTime nextFireTime();64 65 63 protected: 66 virtual Seconds lastGCLength( ) = 0;64 virtual Seconds lastGCLength(Heap&) = 0; 67 65 virtual double gcTimeSlice(size_t bytes) = 0; 68 virtual double deathRate( ) = 0;66 virtual double deathRate(Heap&) = 0; 69 67 70 68 GCActivityCallback(VM* vm) … … 78 76 79 77 protected: 80 void cancelTimer();81 78 void scheduleTimer(Seconds); 82 79 -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r235152 r235261 540 540 // we hasten the next collection by pretending that we've allocated more memory. 541 541 if (m_fullActivityCallback) { 542 m_fullActivityCallback->didAllocate( 542 m_fullActivityCallback->didAllocate(*this, 543 543 m_sizeAfterLastCollect - m_sizeAfterLastFullCollect + m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect); 544 544 } … … 2195 2195 } 2196 2196 2197 m_sweeper->startSweeping( );2197 m_sweeper->startSweeping(*this); 2198 2198 } 2199 2199 … … 2274 2274 if (m_fullActivityCallback) { 2275 2275 ASSERT(currentHeapSize >= m_sizeAfterLastFullCollect); 2276 m_fullActivityCallback->didAllocate( currentHeapSize - m_sizeAfterLastFullCollect);2276 m_fullActivityCallback->didAllocate(*this, currentHeapSize - m_sizeAfterLastFullCollect); 2277 2277 } 2278 2278 } … … 2355 2355 { 2356 2356 if (m_edenActivityCallback) 2357 m_edenActivityCallback->didAllocate( m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);2357 m_edenActivityCallback->didAllocate(*this, m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect); 2358 2358 m_bytesAllocatedThisCycle += bytes; 2359 2359 performIncrement(bytes); -
trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp
r235152 r235261 1 1 /* 2 * Copyright (C) 2012 , 2016Apple Inc. All rights reserved.2 * Copyright (C) 2012-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 35 35 namespace JSC { 36 36 37 static const Seconds sweepTimeSlice = 10_ms; // seconds37 static const Seconds sweepTimeSlice = 10_ms; 38 38 static const double sweepTimeTotal = .10; 39 39 static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal; … … 41 41 void IncrementalSweeper::scheduleTimer() 42 42 { 43 Base::scheduleTimer(sweepTimeSlice * sweepTimeMultiplier);43 setTimeUntilFire(sweepTimeSlice * sweepTimeMultiplier); 44 44 } 45 45 … … 50 50 } 51 51 52 void IncrementalSweeper::doWork( )52 void IncrementalSweeper::doWork(VM& vm) 53 53 { 54 doSweep( MonotonicTime::now());54 doSweep(vm, MonotonicTime::now()); 55 55 } 56 56 57 void IncrementalSweeper::doSweep( MonotonicTime sweepBeginTime)57 void IncrementalSweeper::doSweep(VM& vm, MonotonicTime sweepBeginTime) 58 58 { 59 while (sweepNextBlock( )) {59 while (sweepNextBlock(vm)) { 60 60 Seconds elapsedTime = MonotonicTime::now() - sweepBeginTime; 61 61 if (elapsedTime < sweepTimeSlice) … … 73 73 } 74 74 75 bool IncrementalSweeper::sweepNextBlock( )75 bool IncrementalSweeper::sweepNextBlock(VM& vm) 76 76 { 77 m_vm->heap.stopIfNecessary();77 vm.heap.stopIfNecessary(); 78 78 79 79 MarkedBlock::Handle* block = nullptr; … … 86 86 87 87 if (block) { 88 DeferGCForAWhile deferGC( m_vm->heap);88 DeferGCForAWhile deferGC(vm.heap); 89 89 block->sweep(nullptr); 90 m_vm->heap.objectSpace().freeOrShrinkBlock(block);90 vm.heap.objectSpace().freeOrShrinkBlock(block); 91 91 return true; 92 92 } 93 93 94 return m_vm->heap.sweepNextLogicallyEmptyWeakBlock();94 return vm.heap.sweepNextLogicallyEmptyWeakBlock(); 95 95 } 96 96 97 void IncrementalSweeper::startSweeping( )97 void IncrementalSweeper::startSweeping(Heap& heap) 98 98 { 99 99 scheduleTimer(); 100 m_currentDirectory = m_vm->heap.objectSpace().firstDirectory();100 m_currentDirectory = heap.objectSpace().firstDirectory(); 101 101 } 102 102 … … 104 104 { 105 105 m_currentDirectory = nullptr; 106 if (m_vm) 107 cancelTimer(); 106 cancelTimer(); 108 107 } 109 108 -
trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h
r235152 r235261 38 38 JS_EXPORT_PRIVATE explicit IncrementalSweeper(Heap*); 39 39 40 JS_EXPORT_PRIVATE void startSweeping( );40 JS_EXPORT_PRIVATE void startSweeping(Heap&); 41 41 void freeFastMallocMemoryAfterSweeping() { m_shouldFreeFastMallocMemoryAfterSweeping = true; } 42 42 43 JS_EXPORT_PRIVATE void doWork() override; 44 bool sweepNextBlock(); 45 JS_EXPORT_PRIVATE void stopSweeping(); 43 void doWork(VM&) override; 44 void stopSweeping(); 46 45 47 46 private: 48 void doSweep(MonotonicTime startTime); 47 bool sweepNextBlock(VM&); 48 void doSweep(VM&, MonotonicTime startTime); 49 49 void scheduleTimer(); 50 50 -
trunk/Source/JavaScriptCore/heap/StopIfNecessaryTimer.cpp
r235152 r235261 1 1 /* 2 * Copyright (C) 2016 Apple Inc. All rights reserved.2 * Copyright (C) 2016-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 36 36 } 37 37 38 void StopIfNecessaryTimer::doWork( )38 void StopIfNecessaryTimer::doWork(VM& vm) 39 39 { 40 40 cancelTimer(); 41 41 WTF::storeStoreFence(); 42 m_vm->heap.stopIfNecessary();42 vm.heap.stopIfNecessary(); 43 43 } 44 44 … … 49 49 return; 50 50 } 51 s cheduleTimer(0_s);51 setTimeUntilFire(0_s); 52 52 } 53 53 -
trunk/Source/JavaScriptCore/heap/StopIfNecessaryTimer.h
r235152 r235261 37 37 explicit StopIfNecessaryTimer(VM*); 38 38 39 void doWork( ) override;39 void doWork(VM&) override; 40 40 41 41 void scheduleSoon(); -
trunk/Source/JavaScriptCore/runtime/JSRunLoopTimer.cpp
r235152 r235261 1 1 /* 2 * Copyright (C) 2012-201 7Apple Inc. All rights reserved.2 * Copyright (C) 2012-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 #include "JSRunLoopTimer.h" 28 28 29 #include "GCActivityCallback.h"30 29 #include "IncrementalSweeper.h" 31 30 #include "JSCInlines.h" … … 34 33 35 34 #include <wtf/MainThread.h> 35 #include <wtf/NoTailCalls.h> 36 36 #include <wtf/Threading.h> 37 37 … … 47 47 const Seconds JSRunLoopTimer::s_decade { 60 * 60 * 24 * 365 * 10 }; 48 48 49 static inline JSRunLoopTimer::Manager::EpochTime epochTime(Seconds delay) 50 { 51 #if USE(CF) 52 return Seconds { CFAbsoluteTimeGetCurrent() + delay.value() }; 53 #else 54 return MonotonicTime::now().secondsSinceEpoch() + delay; 55 #endif 56 } 57 58 #if USE(CF) 59 void JSRunLoopTimer::Manager::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr) 60 { 61 static_cast<JSRunLoopTimer::Manager*>(contextPtr)->timerDidFire(); 62 } 63 64 void JSRunLoopTimer::Manager::PerVMData::setRunLoop(Manager* manager, CFRunLoopRef newRunLoop) 65 { 66 if (runLoop) { 67 CFRunLoopRemoveTimer(runLoop.get(), timer.get(), kCFRunLoopCommonModes); 68 CFRunLoopTimerInvalidate(timer.get()); 69 runLoop.clear(); 70 timer.clear(); 71 } 72 73 if (newRunLoop) { 74 runLoop = newRunLoop; 75 memset(&context, 0, sizeof(CFRunLoopTimerContext)); 76 RELEASE_ASSERT(manager); 77 context.info = manager; 78 timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), CFAbsoluteTimeGetCurrent() + s_decade.seconds(), 0, 0, JSRunLoopTimer::Manager::timerDidFireCallback, &context)); 79 CFRunLoopAddTimer(runLoop.get(), timer.get(), kCFRunLoopCommonModes); 80 81 EpochTime scheduleTime = epochTime(s_decade); 82 for (auto& pair : timers) 83 scheduleTime = std::min(pair.second, scheduleTime); 84 CFRunLoopTimerSetNextFireDate(timer.get(), scheduleTime.value()); 85 } 86 } 87 #else 88 JSRunLoopTimer::Manager::PerVMData::PerVMData(Manager& manager) 89 : runLoop(&RunLoop::current()) 90 , timer(std::make_unique<RunLoop::Timer<Manager>>(*runLoop, &manager, &JSRunLoopTimer::Manager::timerDidFireCallback)) 91 { 92 #if USE(GLIB_EVENT_LOOP) 93 timer->setPriority(RunLoopSourcePriority::JavascriptTimer); 94 timer->setName("[JavaScriptCore] JSRunLoopTimer"); 95 #endif 96 } 97 98 void JSRunLoopTimer::Manager::timerDidFireCallback() 99 { 100 timerDidFire(); 101 } 102 #endif 103 104 JSRunLoopTimer::Manager::PerVMData::~PerVMData() 105 { 106 #if USE(CF) 107 setRunLoop(nullptr, nullptr); 108 #endif 109 } 110 111 void JSRunLoopTimer::Manager::timerDidFire() 112 { 113 Vector<Ref<JSRunLoopTimer>> timersToFire; 114 115 { 116 auto locker = holdLock(m_lock); 117 #if USE(CF) 118 CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent(); 119 #else 120 RunLoop* currentRunLoop = &RunLoop::current(); 121 #endif 122 EpochTime nowEpochTime = epochTime(0_s); 123 for (auto& entry : m_mapping) { 124 PerVMData& data = entry.value; 125 #if USE(CF) 126 if (data.runLoop.get() != currentRunLoop) 127 continue; 128 #else 129 if (data.runLoop != currentRunLoop) 130 continue; 131 #endif 132 133 EpochTime scheduleTime = epochTime(s_decade); 134 for (size_t i = 0; i < data.timers.size(); ++i) { 135 { 136 auto& pair = data.timers[i]; 137 if (pair.second > nowEpochTime) { 138 scheduleTime = std::min(pair.second, scheduleTime); 139 continue; 140 } 141 auto& last = data.timers.last(); 142 if (&last != &pair) 143 std::swap(pair, last); 144 --i; 145 } 146 147 auto pair = data.timers.takeLast(); 148 timersToFire.append(WTFMove(pair.first)); 149 } 150 151 #if USE(CF) 152 CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); 153 #else 154 data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch())); 155 #endif 156 } 157 } 158 159 for (auto& timer : timersToFire) 160 timer->timerDidFire(); 161 } 162 163 JSRunLoopTimer::Manager& JSRunLoopTimer::Manager::shared() 164 { 165 static Manager* manager; 166 static std::once_flag once; 167 std::call_once(once, [&] { 168 manager = new Manager; 169 }); 170 return *manager; 171 } 172 173 void JSRunLoopTimer::Manager::registerVM(VM& vm) 174 { 175 PerVMData data { *this }; 176 #if USE(CF) 177 data.setRunLoop(this, vm.runLoop()); 178 #endif 179 180 auto locker = holdLock(m_lock); 181 auto addResult = m_mapping.add({ vm.apiLock() }, WTFMove(data)); 182 RELEASE_ASSERT(addResult.isNewEntry); 183 } 184 185 void JSRunLoopTimer::Manager::unregisterVM(VM& vm) 186 { 187 auto locker = holdLock(m_lock); 188 189 auto iter = m_mapping.find({ vm.apiLock() }); 190 RELEASE_ASSERT(iter != m_mapping.end()); 191 m_mapping.remove(iter); 192 } 193 194 void JSRunLoopTimer::Manager::scheduleTimer(JSRunLoopTimer& timer, Seconds delay) 195 { 196 EpochTime fireEpochTime = epochTime(delay); 197 198 auto locker = holdLock(m_lock); 199 auto iter = m_mapping.find(timer.m_apiLock); 200 RELEASE_ASSERT(iter != m_mapping.end()); // We don't allow calling this after the VM dies. 201 202 PerVMData& data = iter->value; 203 EpochTime scheduleTime = fireEpochTime; 204 bool found = false; 205 for (auto& entry : data.timers) { 206 if (entry.first.ptr() == &timer) { 207 entry.second = fireEpochTime; 208 found = true; 209 } 210 scheduleTime = std::min(scheduleTime, entry.second); 211 } 212 213 if (!found) 214 data.timers.append({ timer, fireEpochTime }); 215 216 #if USE(CF) 217 CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); 218 #else 219 data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch())); 220 #endif 221 } 222 223 void JSRunLoopTimer::Manager::cancelTimer(JSRunLoopTimer& timer) 224 { 225 auto locker = holdLock(m_lock); 226 auto iter = m_mapping.find(timer.m_apiLock); 227 if (iter == m_mapping.end()) { 228 // It's trivial to allow this to be called after the VM dies, so we allow for it. 229 return; 230 } 231 232 PerVMData& data = iter->value; 233 EpochTime scheduleTime = epochTime(s_decade); 234 for (unsigned i = 0; i < data.timers.size(); ++i) { 235 { 236 auto& entry = data.timers[i]; 237 if (entry.first.ptr() == &timer) { 238 RELEASE_ASSERT(timer.refCount() >= 2); // If we remove it from the entry below, we should not be the last thing pointing to it! 239 auto& last = data.timers.last(); 240 if (&last != &entry) 241 std::swap(entry, last); 242 data.timers.removeLast(); 243 i--; 244 continue; 245 } 246 } 247 248 scheduleTime = std::min(scheduleTime, data.timers[i].second); 249 } 250 251 #if USE(CF) 252 CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); 253 #else 254 data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch())); 255 #endif 256 } 257 258 std::optional<Seconds> JSRunLoopTimer::Manager::timeUntilFire(JSRunLoopTimer& timer) 259 { 260 auto locker = holdLock(m_lock); 261 auto iter = m_mapping.find(timer.m_apiLock); 262 RELEASE_ASSERT(iter != m_mapping.end()); // We only allow this to be called with a live VM. 263 264 PerVMData& data = iter->value; 265 for (auto& entry : data.timers) { 266 if (entry.first.ptr() == &timer) { 267 EpochTime nowEpochTime = epochTime(0_s); 268 return entry.second - nowEpochTime; 269 } 270 } 271 272 return std::nullopt; 273 } 274 275 #if USE(CF) 276 void JSRunLoopTimer::Manager::didChangeRunLoop(VM& vm, CFRunLoopRef newRunLoop) 277 { 278 auto locker = holdLock(m_lock); 279 auto iter = m_mapping.find({ vm.apiLock() }); 280 RELEASE_ASSERT(iter != m_mapping.end()); 281 282 PerVMData& data = iter->value; 283 data.setRunLoop(this, newRunLoop); 284 } 285 #endif 286 49 287 void JSRunLoopTimer::timerDidFire() 50 288 { 51 JSLock* apiLock = m_apiLock.get(); 52 if (!apiLock) { 53 // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed. 54 return; 55 } 56 57 std::lock_guard<JSLock> lock(*apiLock); 58 RefPtr<VM> vm = apiLock->vm(); 289 NO_TAIL_CALLS(); 290 291 { 292 auto locker = holdLock(m_lock); 293 if (!m_isScheduled) { 294 // We raced between this callback being called and cancel() being called. 295 // That's fine, we just don't do anything here. 296 return; 297 } 298 } 299 300 std::lock_guard<JSLock> lock(m_apiLock.get()); 301 RefPtr<VM> vm = m_apiLock->vm(); 59 302 if (!vm) { 60 303 // The VM has been destroyed, so we should just give up. … … 62 305 } 63 306 64 doWork(); 65 } 66 67 #if USE(CF) 307 doWork(*vm); 308 } 68 309 69 310 JSRunLoopTimer::JSRunLoopTimer(VM* vm) 70 : m_vm(vm) 71 , m_apiLock(&vm->apiLock()) 72 { 73 m_vm->registerRunLoopTimer(this); 74 } 75 76 void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop) 77 { 78 if (m_runLoop) { 79 CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); 80 CFRunLoopTimerInvalidate(m_timer.get()); 81 m_runLoop.clear(); 82 m_timer.clear(); 83 } 84 85 m_runLoop = runLoop; 86 if (runLoop) { 87 memset(&m_context, 0, sizeof(CFRunLoopTimerContext)); 88 m_context.info = this; 89 m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), s_decade.seconds(), 0, 0, JSRunLoopTimer::timerDidFireCallback, &m_context)); 90 CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); 91 } 311 : m_apiLock(vm->apiLock()) 312 { 92 313 } 93 314 94 315 JSRunLoopTimer::~JSRunLoopTimer() 95 316 { 96 JSLock* apiLock = m_apiLock.get(); 97 std::lock_guard<JSLock> lock(*apiLock); 98 m_vm->unregisterRunLoopTimer(this); 99 m_apiLock = nullptr; 100 } 101 102 void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr) 103 { 104 static_cast<JSRunLoopTimer*>(contextPtr)->timerDidFire(); 105 } 106 107 void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds) 108 { 109 CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + intervalInSeconds.seconds());110 m_isScheduled = true; 317 } 318 319 std::optional<Seconds> JSRunLoopTimer::timeUntilFire() 320 { 321 return Manager::shared().timeUntilFire(*this); 322 } 323 324 void JSRunLoopTimer::setTimeUntilFire(Seconds intervalInSeconds) 325 { 326 { 327 auto locker = holdLock(m_lock); 328 m_isScheduled = true; 329 Manager::shared().scheduleTimer(*this, intervalInSeconds); 330 } 331 111 332 auto locker = holdLock(m_timerCallbacksLock); 112 333 for (auto& task : m_timerSetCallbacks) … … 116 337 void JSRunLoopTimer::cancelTimer() 117 338 { 118 CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds());339 auto locker = holdLock(m_lock); 119 340 m_isScheduled = false; 120 } 121 122 #else 123 124 JSRunLoopTimer::JSRunLoopTimer(VM* vm) 125 : m_vm(vm) 126 , m_apiLock(&vm->apiLock()) 127 , m_timer(RunLoop::current(), this, &JSRunLoopTimer::timerDidFireCallback) 128 { 129 #if USE(GLIB_EVENT_LOOP) 130 m_timer.setPriority(RunLoopSourcePriority::JavascriptTimer); 131 m_timer.setName("[JavaScriptCore] JSRunLoopTimer"); 132 #endif 133 m_timer.startOneShot(s_decade); 134 } 135 136 JSRunLoopTimer::~JSRunLoopTimer() 137 { 138 } 139 140 void JSRunLoopTimer::timerDidFireCallback() 141 { 142 m_timer.startOneShot(s_decade); 143 timerDidFire(); 144 } 145 146 void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds) 147 { 148 m_timer.startOneShot(intervalInSeconds); 149 m_isScheduled = true; 150 151 auto locker = holdLock(m_timerCallbacksLock); 152 for (auto& task : m_timerSetCallbacks) 153 task->run(); 154 } 155 156 void JSRunLoopTimer::cancelTimer() 157 { 158 m_timer.startOneShot(s_decade); 159 m_isScheduled = false; 160 } 161 162 #endif 341 Manager::shared().cancelTimer(*this); 342 } 163 343 164 344 void JSRunLoopTimer::addTimerSetNotification(TimerNotificationCallback callback) -
trunk/Source/JavaScriptCore/runtime/JSRunLoopTimer.h
r235152 r235261 48 48 using TimerNotificationCallback = RefPtr<WTF::SharedTask<TimerNotificationType>>; 49 49 50 JSRunLoopTimer(VM*);50 class Manager { 51 51 #if USE(CF) 52 static void timerDidFireCallback(CFRunLoopTimerRef, void*);52 static void timerDidFireCallback(CFRunLoopTimerRef, void*); 53 53 #else 54 void timerDidFireCallback();54 void timerDidFireCallback(); 55 55 #endif 56 56 57 void timerDidFire(); 58 59 public: 60 using EpochTime = Seconds; 61 62 static Manager& shared(); 63 void registerVM(VM&); 64 void unregisterVM(VM&); 65 void scheduleTimer(JSRunLoopTimer&, Seconds nextFireTime); 66 void cancelTimer(JSRunLoopTimer&); 67 68 std::optional<Seconds> timeUntilFire(JSRunLoopTimer&); 69 70 #if USE(CF) 71 void didChangeRunLoop(VM&, CFRunLoopRef newRunLoop); 72 #endif 73 74 private: 75 Lock m_lock; 76 77 struct PerVMData { 78 PerVMData() = default; 79 #if USE(CF) 80 PerVMData(Manager&) { } 81 #else 82 PerVMData(Manager&); 83 #endif 84 PerVMData(PerVMData&&) = default; 85 PerVMData& operator=(PerVMData&&) = default; 86 87 ~PerVMData(); 88 89 #if USE(CF) 90 void setRunLoop(Manager*, CFRunLoopRef); 91 RetainPtr<CFRunLoopTimerRef> timer; 92 RetainPtr<CFRunLoopRef> runLoop; 93 CFRunLoopTimerContext context; 94 #else 95 RunLoop* runLoop; 96 std::unique_ptr<RunLoop::Timer<Manager>> timer; 97 #endif 98 Vector<std::pair<Ref<JSRunLoopTimer>, EpochTime>> timers; 99 }; 100 101 HashMap<Ref<JSLock>, PerVMData> m_mapping; 102 }; 103 104 JSRunLoopTimer(VM*); 57 105 JS_EXPORT_PRIVATE virtual ~JSRunLoopTimer(); 58 virtual void doWork( ) = 0;106 virtual void doWork(VM&) = 0; 59 107 60 void s cheduleTimer(Seconds intervalInSeconds);108 void setTimeUntilFire(Seconds intervalInSeconds); 61 109 void cancelTimer(); 62 110 bool isScheduled() const { return m_isScheduled; } 63 111 64 112 // Note: The only thing the timer notification callback cannot do is 65 // call s cheduleTimer(). This will cause a deadlock. It would not113 // call setTimeUntilFire(). This will cause a deadlock. It would not 66 114 // be hard to make this work, however, there are no clients that need 67 115 // this behavior. We should implement it only if we find that we need it. … … 69 117 JS_EXPORT_PRIVATE void removeTimerSetNotification(TimerNotificationCallback); 70 118 71 #if USE(CF) 72 JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef); 73 #endif // USE(CF) 119 JS_EXPORT_PRIVATE std::optional<Seconds> timeUntilFire(); 74 120 75 121 protected: 76 VM* m_vm; 122 static const Seconds s_decade; 123 Ref<JSLock> m_apiLock; 77 124 78 static const Seconds s_decade; 125 private: 126 friend class Manager; 79 127 80 RefPtr<JSLock> m_apiLock; 128 void timerDidFire(); 129 130 HashSet<TimerNotificationCallback> m_timerSetCallbacks; 131 Lock m_timerCallbacksLock; 132 133 Lock m_lock; 81 134 bool m_isScheduled { false }; 82 #if USE(CF)83 RetainPtr<CFRunLoopTimerRef> m_timer;84 RetainPtr<CFRunLoopRef> m_runLoop;85 86 CFRunLoopTimerContext m_context;87 88 Lock m_shutdownMutex;89 #else90 RunLoop::Timer<JSRunLoopTimer> m_timer;91 #endif92 93 Lock m_timerCallbacksLock;94 HashSet<TimerNotificationCallback> m_timerSetCallbacks;95 96 private:97 void timerDidFire();98 135 }; 99 136 -
trunk/Source/JavaScriptCore/runtime/PromiseDeferredTimer.cpp
r235152 r235261 1 1 /* 2 * Copyright (C) 2017 Apple Inc. All rights reserved.2 * Copyright (C) 2017-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 44 44 } 45 45 46 void PromiseDeferredTimer::doWork( )46 void PromiseDeferredTimer::doWork(VM& vm) 47 47 { 48 ASSERT( m_vm->currentThreadIsHoldingAPILock());48 ASSERT(vm.currentThreadIsHoldingAPILock()); 49 49 m_taskLock.lock(); 50 50 cancelTimer(); … … 67 67 68 68 task(); 69 m_vm->drainMicrotasks();69 vm.drainMicrotasks(); 70 70 71 71 m_taskLock.lock(); … … 76 76 if (m_pendingPromises.isEmpty() && m_shouldStopRunLoopWhenAllPromisesFinish) { 77 77 #if USE(CF) 78 CFRunLoopStop( m_runLoop.get());78 CFRunLoopStop(vm.runLoop()); 79 79 #else 80 80 RunLoop::current().stop(); … … 87 87 void PromiseDeferredTimer::runRunLoop() 88 88 { 89 ASSERT(!m_ vm->currentThreadIsHoldingAPILock());89 ASSERT(!m_apiLock->vm()->currentThreadIsHoldingAPILock()); 90 90 #if USE(CF) 91 ASSERT(CFRunLoopGetCurrent() == m_ runLoop.get());91 ASSERT(CFRunLoopGetCurrent() == m_apiLock->vm()->runLoop()); 92 92 #endif 93 93 m_shouldStopRunLoopWhenAllPromisesFinish = true; 94 if (m_pendingPromises.size()) 94 if (m_pendingPromises.size()) { 95 95 #if USE(CF) 96 96 CFRunLoopRun(); … … 98 98 RunLoop::run(); 99 99 #endif 100 } 100 101 } 101 102 102 void PromiseDeferredTimer::addPendingPromise( JSPromiseDeferred* ticket, Vector<Strong<JSCell>>&& dependencies)103 void PromiseDeferredTimer::addPendingPromise(VM& vm, JSPromiseDeferred* ticket, Vector<Strong<JSCell>>&& dependencies) 103 104 { 104 ASSERT( m_vm->currentThreadIsHoldingAPILock());105 ASSERT(vm.currentThreadIsHoldingAPILock()); 105 106 for (unsigned i = 0; i < dependencies.size(); ++i) 106 107 ASSERT(dependencies[i].get() != ticket); … … 109 110 if (result.isNewEntry) { 110 111 dataLogLnIf(PromiseDeferredTimerInternal::verbose, "Adding new pending promise: ", RawPointer(ticket)); 111 dependencies.append(Strong<JSCell>( *m_vm, ticket));112 dependencies.append(Strong<JSCell>(vm, ticket)); 112 113 result.iterator->value = WTFMove(dependencies); 113 114 } else { … … 123 124 bool PromiseDeferredTimer::hasPendingPromise(JSPromiseDeferred* ticket) 124 125 { 125 ASSERT( m_vm->currentThreadIsHoldingAPILock());126 ASSERT(ticket->vm()->currentThreadIsHoldingAPILock()); 126 127 return m_pendingPromises.contains(ticket); 127 128 } … … 129 130 bool PromiseDeferredTimer::hasDependancyInPendingPromise(JSPromiseDeferred* ticket, JSCell* dependency) 130 131 { 131 ASSERT( m_vm->currentThreadIsHoldingAPILock());132 ASSERT(ticket->vm()->currentThreadIsHoldingAPILock()); 132 133 ASSERT(m_pendingPromises.contains(ticket)); 133 134 … … 138 139 bool PromiseDeferredTimer::cancelPendingPromise(JSPromiseDeferred* ticket) 139 140 { 140 ASSERT( m_vm->currentThreadIsHoldingAPILock());141 ASSERT(ticket->vm()->currentThreadIsHoldingAPILock()); 141 142 bool result = m_pendingPromises.remove(ticket); 142 143 … … 152 153 m_tasks.append(std::make_tuple(ticket, WTFMove(task))); 153 154 if (!isScheduled() && !m_currentlyRunningTask) 154 s cheduleTimer(0_s);155 setTimeUntilFire(0_s); 155 156 } 156 157 -
trunk/Source/JavaScriptCore/runtime/PromiseDeferredTimer.h
r235152 r235261 45 45 PromiseDeferredTimer(VM&); 46 46 47 void doWork( ) override;47 void doWork(VM&) override; 48 48 49 void addPendingPromise( JSPromiseDeferred*, Vector<Strong<JSCell>>&& dependencies);49 void addPendingPromise(VM&, JSPromiseDeferred*, Vector<Strong<JSCell>>&& dependencies); 50 50 JS_EXPORT_PRIVATE bool hasPendingPromise(JSPromiseDeferred* ticket); 51 51 JS_EXPORT_PRIVATE bool hasDependancyInPendingPromise(JSPromiseDeferred* ticket, JSCell* dependency); -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r235254 r235261 382 382 setLastStackTop(stack.origin()); 383 383 384 JSRunLoopTimer::Manager::shared().registerVM(*this); 385 384 386 // Need to be careful to keep everything consistent here 385 387 JSLockHolder lock(this); … … 582 584 m_apiLock->willDestroyVM(this); 583 585 heap.lastChanceToFinalize(); 586 587 JSRunLoopTimer::Manager::shared().unregisterVM(*this); 584 588 585 589 delete interpreter; … … 1210 1214 1211 1215 #if USE(CF) 1212 void VM::registerRunLoopTimer(JSRunLoopTimer* timer)1213 {1214 ASSERT(runLoop());1215 ASSERT(!m_runLoopTimers.contains(timer));1216 m_runLoopTimers.add(timer);1217 timer->setRunLoop(runLoop());1218 }1219 1220 void VM::unregisterRunLoopTimer(JSRunLoopTimer* timer)1221 {1222 ASSERT(m_runLoopTimers.contains(timer));1223 m_runLoopTimers.remove(timer);1224 timer->setRunLoop(nullptr);1225 }1226 1227 1216 void VM::setRunLoop(CFRunLoopRef runLoop) 1228 1217 { 1229 1218 ASSERT(runLoop); 1230 1219 m_runLoop = runLoop; 1231 for (auto timer : m_runLoopTimers) 1232 timer->setRunLoop(runLoop); 1220 JSRunLoopTimer::Manager::shared().didChangeRunLoop(*this, runLoop); 1233 1221 } 1234 1222 #endif // USE(CF) -
trunk/Source/JavaScriptCore/runtime/VM.h
r235254 r235261 308 308 #if USE(CF) 309 309 // These need to be initialized before heap below. 310 HashSet<JSRunLoopTimer*> m_runLoopTimers;311 310 RetainPtr<CFRunLoopRef> m_runLoop; 312 311 #endif … … 888 887 #if USE(CF) 889 888 CFRunLoopRef runLoop() const { return m_runLoop.get(); } 890 void registerRunLoopTimer(JSRunLoopTimer*);891 void unregisterRunLoopTimer(JSRunLoopTimer*);892 889 JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef); 893 890 #endif // USE(CF) -
trunk/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp
r235152 r235261 92 92 dependencies.append(Strong<JSCell>(vm, globalObject)); 93 93 94 vm.promiseDeferredTimer->addPendingPromise( promise, WTFMove(dependencies));94 vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); 95 95 96 96 Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable { … … 174 174 dependencies.append(Strong<JSCell>(vm, instance)); 175 175 dependencies.append(Strong<JSCell>(vm, importObject)); 176 vm.promiseDeferredTimer->addPendingPromise( promise, WTFMove(dependencies));176 vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); 177 177 // Note: This completion task may or may not get called immediately. 178 178 module->module().compileAsync(&vm.wasmContext, instance->memoryMode(), createSharedTask<Wasm::CodeBlock::CallbackType>([promise, instance, module, importObject, resolveKind, creationMode, &vm] (Ref<Wasm::CodeBlock>&& refCodeBlock) mutable { … … 195 195 dependencies.append(Strong<JSCell>(vm, importObject)); 196 196 dependencies.append(Strong<JSCell>(vm, moduleKeyCell)); 197 vm.promiseDeferredTimer->addPendingPromise( promise, WTFMove(dependencies));197 vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); 198 198 199 199 Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, buffer); … … 232 232 dependencies.append(Strong<JSCell>(vm, importObject)); 233 233 dependencies.append(Strong<JSCell>(vm, globalObject)); 234 vm.promiseDeferredTimer->addPendingPromise( promise, WTFMove(dependencies));234 vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); 235 235 236 236 Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, importObject, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable { … … 311 311 Vector<Strong<JSCell>> dependencies; 312 312 dependencies.append(Strong<JSCell>(vm, globalObject)); 313 vm.promiseDeferredTimer->addPendingPromise( promise, WTFMove(dependencies));313 vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); 314 314 315 315 if (globalObject->globalObjectMethodTable()->compileStreaming) … … 348 348 dependencies.append(Strong<JSCell>(vm, globalObject)); 349 349 dependencies.append(Strong<JSCell>(vm, importObject)); 350 vm.promiseDeferredTimer->addPendingPromise( promise, WTFMove(dependencies));350 vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); 351 351 352 352 // FIXME: <http://webkit.org/b/184888> if there's an importObject and it contains a Memory, then we can compile the module with the right memory type (fast or not) by looking at the memory's type. -
trunk/Source/WebCore/ChangeLog
r235258 r235261 1 2018-08-23 Saam barati <sbarati@apple.com> 2 3 JSRunLoopTimer may run part of a member function after it's destroyed 4 https://bugs.webkit.org/show_bug.cgi?id=188426 5 6 Reviewed by Mark Lam. 7 8 * page/cocoa/ResourceUsageThreadCocoa.mm: 9 (WebCore::ResourceUsageThread::platformThreadBody): 10 * page/linux/ResourceUsageThreadLinux.cpp: 11 (WebCore::ResourceUsageThread::platformThreadBody): 12 1 13 2018-08-23 David Fenton <david_fenton@apple.com> 2 14 -
trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm
r235152 r235261 249 249 data.totalExternalSize = currentGCOwnedExternal; 250 250 251 data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime(); 252 data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime(); 251 auto now = MonotonicTime::now(); 252 data.timeOfNextEdenCollection = now + vm->heap.edenActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); 253 data.timeOfNextFullCollection = now + vm->heap.fullActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); 253 254 } 254 255 -
trunk/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp
r235152 r235261 1 1 /* 2 2 * Copyright (C) 2017 Igalia S.L. 3 * Copyright (C) 2018 Apple Inc. All rights reserved. 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 169 170 data.totalExternalSize = currentGCOwnedExternal; 170 171 171 data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime(); 172 data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime(); 172 auto now = MonotonicTime::now(); 173 data.timeOfNextEdenCollection = now + vm->heap.edenActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); 174 data.timeOfNextFullCollection = now + vm->heap.fullActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); 173 175 } 174 176
Note: See TracChangeset
for help on using the changeset viewer.