WebKit Bugzilla
Attachment 347021 Details for
Bug 188426
: JSRunLoopTimer may run part of a member function after it's destroyed
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
a-backup.diff (text/plain), 43.96 KB, created by
Saam Barati
on 2018-08-13 11:46:59 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2018-08-13 11:46:59 PDT
Size:
43.96 KB
patch
obsolete
>Index: Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp >=================================================================== >--- Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp (revision 234782) >+++ Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp (working copy) >@@ -36,21 +36,20 @@ EdenGCActivityCallback::EdenGCActivityCa > { > } > >-void EdenGCActivityCallback::doCollection() >+void EdenGCActivityCallback::doCollection(VM& vm) > { >- m_vm->heap.collectAsync(CollectionScope::Eden); >+ vm.heap.collectAsync(CollectionScope::Eden); > } > >-Seconds EdenGCActivityCallback::lastGCLength() >+Seconds EdenGCActivityCallback::lastGCLength(Heap& heap) > { >- return m_vm->heap.lastEdenGCLength(); >+ return heap.lastEdenGCLength(); > } > >-double EdenGCActivityCallback::deathRate() >+double EdenGCActivityCallback::deathRate(Heap& heap) > { >- Heap* heap = &m_vm->heap; >- size_t sizeBefore = heap->sizeBeforeLastEdenCollection(); >- size_t sizeAfter = heap->sizeAfterLastEdenCollection(); >+ size_t sizeBefore = heap.sizeBeforeLastEdenCollection(); >+ size_t sizeAfter = heap.sizeAfterLastEdenCollection(); > if (!sizeBefore) > return 1.0; > if (sizeAfter > sizeBefore) { >Index: Source/JavaScriptCore/heap/EdenGCActivityCallback.h >=================================================================== >--- Source/JavaScriptCore/heap/EdenGCActivityCallback.h (revision 234782) >+++ Source/JavaScriptCore/heap/EdenGCActivityCallback.h (working copy) >@@ -33,12 +33,12 @@ class JS_EXPORT_PRIVATE EdenGCActivityCa > public: > EdenGCActivityCallback(Heap*); > >- void doCollection() override; >+ void doCollection(VM&) override; > > protected: >- Seconds lastGCLength() override; >+ Seconds lastGCLength(Heap&) override; > double gcTimeSlice(size_t bytes) override; >- double deathRate() override; >+ double deathRate(Heap&) override; > }; > > inline RefPtr<GCActivityCallback> GCActivityCallback::createEdenTimer(Heap* heap) >Index: Source/JavaScriptCore/heap/FullGCActivityCallback.cpp >=================================================================== >--- Source/JavaScriptCore/heap/FullGCActivityCallback.cpp (revision 234782) >+++ Source/JavaScriptCore/heap/FullGCActivityCallback.cpp (working copy) >@@ -39,9 +39,9 @@ FullGCActivityCallback::FullGCActivityCa > { > } > >-void FullGCActivityCallback::doCollection() >+void FullGCActivityCallback::doCollection(VM& vm) > { >- Heap& heap = m_vm->heap; >+ Heap& heap = vm.heap; > m_didGCRecently = false; > > #if !PLATFORM(IOS) >@@ -56,16 +56,15 @@ void FullGCActivityCallback::doCollectio > heap.collectAsync(CollectionScope::Full); > } > >-Seconds FullGCActivityCallback::lastGCLength() >+Seconds FullGCActivityCallback::lastGCLength(Heap& heap) > { >- return m_vm->heap.lastFullGCLength(); >+ return heap.lastFullGCLength(); > } > >-double FullGCActivityCallback::deathRate() >+double FullGCActivityCallback::deathRate(Heap& heap) > { >- Heap* heap = &m_vm->heap; >- size_t sizeBefore = heap->sizeBeforeLastFullCollection(); >- size_t sizeAfter = heap->sizeAfterLastFullCollection(); >+ size_t sizeBefore = heap.sizeBeforeLastFullCollection(); >+ size_t sizeAfter = heap.sizeAfterLastFullCollection(); > if (!sizeBefore) > return 1.0; > if (sizeAfter > sizeBefore) { >Index: Source/JavaScriptCore/heap/FullGCActivityCallback.h >=================================================================== >--- Source/JavaScriptCore/heap/FullGCActivityCallback.h (revision 234782) >+++ Source/JavaScriptCore/heap/FullGCActivityCallback.h (working copy) >@@ -33,15 +33,15 @@ class JS_EXPORT_PRIVATE FullGCActivityCa > public: > FullGCActivityCallback(Heap*); > >- void doCollection() override; >+ void doCollection(VM&) override; > > bool didGCRecently() const { return m_didGCRecently; } > void setDidGCRecently() { m_didGCRecently = true; } > > protected: >- Seconds lastGCLength() override; >+ Seconds lastGCLength(Heap&) override; > double gcTimeSlice(size_t bytes) override; >- double deathRate() override; >+ double deathRate(Heap&) override; > > bool m_didGCRecently { false }; > }; >Index: Source/JavaScriptCore/heap/GCActivityCallback.cpp >=================================================================== >--- Source/JavaScriptCore/heap/GCActivityCallback.cpp (revision 234782) >+++ Source/JavaScriptCore/heap/GCActivityCallback.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2010-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2010-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -45,83 +45,52 @@ GCActivityCallback::GCActivityCallback(H > { > } > >-void GCActivityCallback::doWork() >+void GCActivityCallback::doWork(VM& vm) > { >- Heap* heap = &m_vm->heap; > if (!isEnabled()) > return; > >- JSLockHolder locker(m_vm); >- if (heap->isDeferred()) { >+ ASSERT(vm.currentThreadIsHoldingAPILock()); >+ Heap& heap = vm.heap; >+ if (heap.isDeferred()) { > scheduleTimer(0_s); > return; > } > >- doCollection(); >+ doCollection(vm); > } > >-#if USE(CF) > void GCActivityCallback::scheduleTimer(Seconds newDelay) > { > if (newDelay * timerSlop > m_delay) > return; > Seconds delta = m_delay - newDelay; > m_delay = newDelay; >- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta.seconds()); >+ if (auto timeUntilFire = this->timeUntilFire()) >+ setTimeUntilFire(*timeUntilFire - delta); >+ else >+ setTimeUntilFire(delta); > } > >-void GCActivityCallback::cancelTimer() >-{ >- m_delay = s_decade; >- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds()); >-} >- >-MonotonicTime GCActivityCallback::nextFireTime() >-{ >- return MonotonicTime::now() + Seconds(CFRunLoopTimerGetNextFireDate(m_timer.get()) - CFAbsoluteTimeGetCurrent()); >-} >-#else >-void GCActivityCallback::scheduleTimer(Seconds newDelay) >-{ >- if (newDelay * timerSlop > m_delay) >- return; >- Seconds delta = m_delay - newDelay; >- m_delay = newDelay; >- >- Seconds secondsUntilFire = m_timer.secondsUntilFire(); >- m_timer.startOneShot(std::max<Seconds>(secondsUntilFire - delta, 0_s)); >-} >- >-void GCActivityCallback::cancelTimer() >-{ >- m_delay = s_decade; >- m_timer.startOneShot(s_decade); >-} >- >-MonotonicTime GCActivityCallback::nextFireTime() >-{ >- return MonotonicTime::now() + m_timer.secondsUntilFire(); >-} >-#endif >- >-void GCActivityCallback::didAllocate(size_t bytes) >+void GCActivityCallback::didAllocate(Heap& heap, size_t bytes) > { > // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. > // We pretend it's one byte so that we don't ignore this allocation entirely. > if (!bytes) > bytes = 1; >- double bytesExpectedToReclaim = static_cast<double>(bytes) * deathRate(); >- Seconds newDelay = lastGCLength() / gcTimeSlice(bytesExpectedToReclaim); >+ double bytesExpectedToReclaim = static_cast<double>(bytes) * deathRate(heap); >+ Seconds newDelay = lastGCLength(heap) / gcTimeSlice(bytesExpectedToReclaim); > scheduleTimer(newDelay); > } > > void GCActivityCallback::willCollect() > { >- cancelTimer(); >+ cancel(); > } > > void GCActivityCallback::cancel() > { >+ m_delay = s_decade; > cancelTimer(); > } > >Index: Source/JavaScriptCore/heap/GCActivityCallback.h >=================================================================== >--- Source/JavaScriptCore/heap/GCActivityCallback.h (revision 234782) >+++ Source/JavaScriptCore/heap/GCActivityCallback.h (working copy) >@@ -48,24 +48,22 @@ public: > > GCActivityCallback(Heap*); > >- void doWork() override; >+ void doWork(VM&) override; > >- virtual void doCollection() = 0; >+ virtual void doCollection(VM&) = 0; > >- virtual void didAllocate(size_t); >- virtual void willCollect(); >- virtual void cancel(); >+ void didAllocate(Heap&, size_t); >+ void willCollect(); >+ void cancel(); > bool isEnabled() const { return m_enabled; } > void setEnabled(bool enabled) { m_enabled = enabled; } > > static bool s_shouldCreateGCTimer; > >- MonotonicTime nextFireTime(); >- > protected: >- virtual Seconds lastGCLength() = 0; >+ virtual Seconds lastGCLength(Heap&) = 0; > virtual double gcTimeSlice(size_t bytes) = 0; >- virtual double deathRate() = 0; >+ virtual double deathRate(Heap&) = 0; > > GCActivityCallback(VM* vm) > : Base(vm) >@@ -77,7 +75,6 @@ protected: > bool m_enabled; > > protected: >- void cancelTimer(); > void scheduleTimer(Seconds); > > private: >Index: Source/JavaScriptCore/heap/Heap.cpp >=================================================================== >--- Source/JavaScriptCore/heap/Heap.cpp (revision 234782) >+++ Source/JavaScriptCore/heap/Heap.cpp (working copy) >@@ -539,7 +539,7 @@ void Heap::reportAbandonedObjectGraph() > // be more profitable. Since allocation is the trigger for collection, > // we hasten the next collection by pretending that we've allocated more memory. > if (m_fullActivityCallback) { >- m_fullActivityCallback->didAllocate( >+ m_fullActivityCallback->didAllocate(*this, > m_sizeAfterLastCollect - m_sizeAfterLastFullCollect + m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect); > } > m_bytesAbandonedSinceLastFullCollect += abandonedBytes; >@@ -2194,7 +2194,7 @@ void Heap::notifyIncrementalSweeper() > m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0; > } > >- m_sweeper->startSweeping(); >+ m_sweeper->startSweeping(*this); > } > > void Heap::updateAllocationLimits() >@@ -2273,7 +2273,7 @@ void Heap::updateAllocationLimits() > dataLog("Eden: maxEdenSize = ", m_maxEdenSize, "\n"); > if (m_fullActivityCallback) { > ASSERT(currentHeapSize >= m_sizeAfterLastFullCollect); >- m_fullActivityCallback->didAllocate(currentHeapSize - m_sizeAfterLastFullCollect); >+ m_fullActivityCallback->didAllocate(*this, currentHeapSize - m_sizeAfterLastFullCollect); > } > } > >@@ -2354,7 +2354,7 @@ void Heap::setGarbageCollectionTimerEnab > void Heap::didAllocate(size_t bytes) > { > if (m_edenActivityCallback) >- m_edenActivityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect); >+ m_edenActivityCallback->didAllocate(*this, m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect); > m_bytesAllocatedThisCycle += bytes; > performIncrement(bytes); > } >Index: Source/JavaScriptCore/heap/IncrementalSweeper.cpp >=================================================================== >--- Source/JavaScriptCore/heap/IncrementalSweeper.cpp (revision 234782) >+++ Source/JavaScriptCore/heap/IncrementalSweeper.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2012, 2016 Apple Inc. All rights reserved. >+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -40,7 +40,7 @@ static const double sweepTimeMultiplier > > void IncrementalSweeper::scheduleTimer() > { >- Base::scheduleTimer(sweepTimeSlice * sweepTimeMultiplier); >+ setTimeUntilFire(sweepTimeSlice * sweepTimeMultiplier); > } > > IncrementalSweeper::IncrementalSweeper(Heap* heap) >@@ -49,14 +49,14 @@ IncrementalSweeper::IncrementalSweeper(H > { > } > >-void IncrementalSweeper::doWork() >+void IncrementalSweeper::doWork(VM& vm) > { >- doSweep(MonotonicTime::now()); >+ doSweep(vm, MonotonicTime::now()); > } > >-void IncrementalSweeper::doSweep(MonotonicTime sweepBeginTime) >+void IncrementalSweeper::doSweep(VM& vm, MonotonicTime sweepBeginTime) > { >- while (sweepNextBlock()) { >+ while (sweepNextBlock(vm)) { > Seconds elapsedTime = MonotonicTime::now() - sweepBeginTime; > if (elapsedTime < sweepTimeSlice) > continue; >@@ -72,9 +72,9 @@ void IncrementalSweeper::doSweep(Monoton > cancelTimer(); > } > >-bool IncrementalSweeper::sweepNextBlock() >+bool IncrementalSweeper::sweepNextBlock(VM& vm) > { >- m_vm->heap.stopIfNecessary(); >+ vm.heap.stopIfNecessary(); > > MarkedBlock::Handle* block = nullptr; > >@@ -85,26 +85,25 @@ bool IncrementalSweeper::sweepNextBlock( > } > > if (block) { >- DeferGCForAWhile deferGC(m_vm->heap); >+ DeferGCForAWhile deferGC(vm.heap); > block->sweep(nullptr); >- m_vm->heap.objectSpace().freeOrShrinkBlock(block); >+ vm.heap.objectSpace().freeOrShrinkBlock(block); > return true; > } > >- return m_vm->heap.sweepNextLogicallyEmptyWeakBlock(); >+ return vm.heap.sweepNextLogicallyEmptyWeakBlock(); > } > >-void IncrementalSweeper::startSweeping() >+void IncrementalSweeper::startSweeping(Heap& heap) > { > scheduleTimer(); >- m_currentDirectory = m_vm->heap.objectSpace().firstDirectory(); >+ m_currentDirectory = heap.objectSpace().firstDirectory(); > } > > void IncrementalSweeper::stopSweeping() > { > m_currentDirectory = nullptr; >- if (m_vm) >- cancelTimer(); >+ cancelTimer(); > } > > } // namespace JSC >Index: Source/JavaScriptCore/heap/IncrementalSweeper.h >=================================================================== >--- Source/JavaScriptCore/heap/IncrementalSweeper.h (revision 234782) >+++ Source/JavaScriptCore/heap/IncrementalSweeper.h (working copy) >@@ -37,15 +37,15 @@ public: > using Base = JSRunLoopTimer; > JS_EXPORT_PRIVATE explicit IncrementalSweeper(Heap*); > >- JS_EXPORT_PRIVATE void startSweeping(); >+ JS_EXPORT_PRIVATE void startSweeping(Heap&); > void freeFastMallocMemoryAfterSweeping() { m_shouldFreeFastMallocMemoryAfterSweeping = true; } > >- JS_EXPORT_PRIVATE void doWork() override; >- bool sweepNextBlock(); >- JS_EXPORT_PRIVATE void stopSweeping(); >+ void doWork(VM&) override; >+ void stopSweeping(); > > private: >- void doSweep(MonotonicTime startTime); >+ bool sweepNextBlock(VM&); >+ void doSweep(VM&, MonotonicTime startTime); > void scheduleTimer(); > > BlockDirectory* m_currentDirectory; >Index: Source/JavaScriptCore/heap/StopIfNecessaryTimer.cpp >=================================================================== >--- Source/JavaScriptCore/heap/StopIfNecessaryTimer.cpp (revision 234782) >+++ Source/JavaScriptCore/heap/StopIfNecessaryTimer.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2016 Apple Inc. All rights reserved. >+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -35,11 +35,11 @@ StopIfNecessaryTimer::StopIfNecessaryTim > { > } > >-void StopIfNecessaryTimer::doWork() >+void StopIfNecessaryTimer::doWork(VM& vm) > { > cancelTimer(); > WTF::storeStoreFence(); >- m_vm->heap.stopIfNecessary(); >+ vm.heap.stopIfNecessary(); > } > > void StopIfNecessaryTimer::scheduleSoon() >@@ -48,7 +48,7 @@ void StopIfNecessaryTimer::scheduleSoon( > WTF::loadLoadFence(); > return; > } >- scheduleTimer(0_s); >+ setTimeUntilFire(0_s); > } > > } // namespace JSC >Index: Source/JavaScriptCore/heap/StopIfNecessaryTimer.h >=================================================================== >--- Source/JavaScriptCore/heap/StopIfNecessaryTimer.h (revision 234782) >+++ Source/JavaScriptCore/heap/StopIfNecessaryTimer.h (working copy) >@@ -36,7 +36,7 @@ public: > using Base = JSRunLoopTimer; > explicit StopIfNecessaryTimer(VM*); > >- void doWork() override; >+ void doWork(VM&) override; > > void scheduleSoon(); > }; >Index: Source/JavaScriptCore/runtime/JSRunLoopTimer.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSRunLoopTimer.cpp (revision 234782) >+++ Source/JavaScriptCore/runtime/JSRunLoopTimer.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2012-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -26,13 +26,13 @@ > #include "config.h" > #include "JSRunLoopTimer.h" > >-#include "GCActivityCallback.h" > #include "IncrementalSweeper.h" > #include "JSCInlines.h" > #include "JSObject.h" > #include "JSString.h" > > #include <wtf/MainThread.h> >+#include <wtf/NoTailCalls.h> > #include <wtf/Threading.h> > > #if USE(GLIB_EVENT_LOOP) >@@ -46,107 +46,269 @@ namespace JSC { > > const Seconds JSRunLoopTimer::s_decade { 60 * 60 * 24 * 365 * 10 }; > >-void JSRunLoopTimer::timerDidFire() >+static inline JSRunLoopTimer::Manager::EpochTime epochTime(Seconds delay) > { >- JSLock* apiLock = m_apiLock.get(); >- if (!apiLock) { >- // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed. >- return; >- } >+#if USE(CF) >+ return Seconds { CFAbsoluteTimeGetCurrent() + delay.value() }; >+#else >+ return MonotonicTime::now().secondsSinceEpoch() + delay; >+#endif >+} > >- std::lock_guard<JSLock> lock(*apiLock); >- RefPtr<VM> vm = apiLock->vm(); >- if (!vm) { >- // The VM has been destroyed, so we should just give up. >- return; >- } >+#if USE(CF) >+void JSRunLoopTimer::Manager::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr) >+{ >+ static_cast<JSRunLoopTimer::Manager*>(contextPtr)->timerDidFire(); >+} >+#else >+JSRunLoopTimer::Manager::PerVMData(Manager* manager) >+ : timer(std::make_unique<RunLoop::Timer<Manager>>(RunLoop::current(), &manager, &JSRunLoopTimer::Manager::timerDidFireCallback)) >+{ >+#if USE(GLIB_EVENT_LOOP) >+ timer->setPriority(RunLoopSourcePriority::JavascriptTimer); >+ timer->setName("[JavaScriptCore] JSRunLoopTimer"); >+#endif >+} > >- doWork(); >+void JSRunLoopTimer::Manager::timerDidFireCallback() >+{ >+ timerDidFire(); > } >+#endif >+ >+void JSRunLoopTimer::Manager::timerDidFire() >+{ >+ Vector<Ref<JSRunLoopTimer>> timersToFire; >+ >+ { >+ auto locker = holdLock(m_lock); >+ auto currentRunLoop = CFRunLoopGetCurrent(); >+ auto nowTime = epochTime(0_s); >+ for (auto& entry : m_mapping) { >+ PerVMData& data = entry.value; >+ if (data.runLoop.get() != currentRunLoop) >+ continue; >+ >+ EpochTime scheduleTime = s_decade; >+ for (size_t i = 0; i < data.timers.size(); ++i) { >+ { >+ auto& pair = data.timers[i]; >+ if (pair.second > nowTime) { >+ scheduleTime = std::min(pair.second, scheduleTime); >+ continue; >+ } >+ std::swap(pair, data.timers.last()); >+ --i; >+ } >+ >+ auto pair = data.timers.takeLast(); >+ timersToFire.append(WTFMove(pair.first)); >+ } > > #if USE(CF) >+ CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); >+#else >+ data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch())); >+#endif >+ } >+ } > >-JSRunLoopTimer::JSRunLoopTimer(VM* vm) >- : m_vm(vm) >- , m_apiLock(&vm->apiLock()) >+ for (auto& timer : timersToFire) >+ timer->timerDidFire(); >+} >+ >+JSRunLoopTimer::Manager& JSRunLoopTimer::Manager::shared() > { >- m_vm->registerRunLoopTimer(this); >+ static Manager* manager; >+ static std::once_flag once; >+ std::call_once(once, [&] { >+ manager = new Manager; >+ }); >+ return *manager; > } > >-void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop) >+void JSRunLoopTimer::Manager::registerVM(VM& vm) > { >- if (m_runLoop) { >- CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); >- CFRunLoopTimerInvalidate(m_timer.get()); >- m_runLoop.clear(); >- m_timer.clear(); >+ PerVMData data { *this }; >+ data.runLoop = vm.runLoop(); >+ if (data.runLoop) { >+ memset(&data.context, 0, sizeof(CFRunLoopTimerContext)); >+ data.context.info = this; >+ data.timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), CFAbsoluteTimeGetCurrent() + s_decade.seconds(), 0, 0, JSRunLoopTimer::Manager::timerDidFireCallback, &data.context)); >+ CFRunLoopAddTimer(data.runLoop.get(), data.timer.get(), kCFRunLoopCommonModes); > } > >- m_runLoop = runLoop; >- if (runLoop) { >- memset(&m_context, 0, sizeof(CFRunLoopTimerContext)); >- m_context.info = this; >- m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), s_decade.seconds(), 0, 0, JSRunLoopTimer::timerDidFireCallback, &m_context)); >- CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); >+ auto locker = holdLock(m_lock); >+ auto addResult = m_mapping.add({ vm.apiLock() }, WTFMove(data)); >+ RELEASE_ASSERT(addResult.isNewEntry); >+} >+ >+void JSRunLoopTimer::Manager::willDestroyVM(VM& vm) >+{ >+ auto locker = holdLock(m_lock); >+ >+ auto iter = m_mapping.find({ vm.apiLock() }); >+ RELEASE_ASSERT(iter != m_mapping.end()); >+#if USE(CF) >+ PerVMData& data = iter->value; >+ if (data.runLoop) { >+ CFRunLoopRemoveTimer(data.runLoop.get(), data.timer.get(), kCFRunLoopCommonModes); >+ CFRunLoopTimerInvalidate(data.timer.get()); > } >+#endif >+ m_mapping.remove(iter); > } > >-JSRunLoopTimer::~JSRunLoopTimer() >+void JSRunLoopTimer::Manager::scheduleTimer(JSRunLoopTimer& timer, Seconds nextFireTime) > { >- JSLock* apiLock = m_apiLock.get(); >- std::lock_guard<JSLock> lock(*apiLock); >- m_vm->unregisterRunLoopTimer(this); >- m_apiLock = nullptr; >+ EpochTime fireTime = epochTime(nextFireTime); >+ >+ auto locker = holdLock(m_lock); >+ auto iter = m_mapping.find(timer.m_apiLock); >+ RELEASE_ASSERT(iter != m_mapping.end()); // We don't allow calling this after the VM dies. >+ >+ PerVMData& data = iter->value; >+ EpochTime scheduleTime = nextFireTime; >+ bool found = false; >+ for (auto& entry : data.timers) { >+ if (entry.first.ptr() == &timer) { >+ entry.second = fireTime; >+ found = true; >+ } >+ scheduleTime = std::min(scheduleTime, entry.second); >+ } >+ >+ if (!found) >+ data.timers.append({ timer, nextFireTime }); >+ >+#if USE(CF) >+ CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); >+#else >+ data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch())); >+#endif > } > >-void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr) >+void JSRunLoopTimer::Manager::cancelTimer(JSRunLoopTimer& timer) > { >- static_cast<JSRunLoopTimer*>(contextPtr)->timerDidFire(); >+ auto locker = holdLock(m_lock); >+ auto iter = m_mapping.find(timer.m_apiLock); >+ if (iter == m_mapping.end()) { >+ // It's trivial to allow this to be called after the VM dies, so we allow for it. >+ return; >+ } >+ >+ PerVMData& data = iter->value; >+ EpochTime scheduleTime = s_decade; >+ for (unsigned i = 0; i < data.timers.size(); ++i) { >+ { >+ auto& entry = data.timers[i]; >+ if (entry.first.ptr() == &timer) { >+ RELEASE_ASSERT(timer.refCount() >= 2); // If we remove it from the entry below, we should not be the last thing pointing to it! >+ std::swap(entry, data.timers.last()); >+ data.timers.removeLast(); >+ i--; >+ continue; >+ } >+ } >+ >+ scheduleTime = std::min(scheduleTime, data.timers[i].second); >+ } >+ >+#if USE(CF) >+ CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); >+#else >+ data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch())); >+#endif > } > >-void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds) >+std::optional<Seconds> JSRunLoopTimer::Manager::timeUntilFire(JSRunLoopTimer& timer) > { >- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + intervalInSeconds.seconds()); >- m_isScheduled = true; >- auto locker = holdLock(m_timerCallbacksLock); >- for (auto& task : m_timerSetCallbacks) >- task->run(); >+ auto locker = holdLock(m_lock); >+ auto iter = m_mapping.find(timer.m_apiLock); >+ RELEASE_ASSERT(iter != m_mapping.end()); // We only allow this to be called with a live VM. >+ >+ PerVMData& data = iter->value; >+ for (auto& entry : data.timers) { >+ if (entry.first.ptr() == &timer) { >+ auto nowEpochTime = epochTime(0_s); >+ return entry.second - nowEpochTime; >+ } >+ } >+ >+ return std::nullopt; > } > >-void JSRunLoopTimer::cancelTimer() >+#if USE(CF) >+void JSRunLoopTimer::Manager::didChangeRunLoop(VM& vm, CFRunLoopRef newRunLoop) > { >- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds()); >- m_isScheduled = false; >+ auto locker = holdLock(m_lock); >+ auto iter = m_mapping.find({ vm.apiLock() }); >+ RELEASE_ASSERT(iter != m_mapping.end()); >+ >+ PerVMData& data = iter->value; >+ if (data.runLoop) { >+ CFRunLoopRemoveTimer(data.runLoop.get(), data.timer.get(), kCFRunLoopCommonModes); >+ CFRunLoopTimerInvalidate(data.timer.get()); >+ } >+ >+ RELEASE_ASSERT(newRunLoop); >+ data.runLoop = newRunLoop; >+ memset(&data.context, 0, sizeof(CFRunLoopTimerContext)); >+ data.context.info = this; >+ data.timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), CFAbsoluteTimeGetCurrent() + s_decade.seconds(), 0, 0, JSRunLoopTimer::Manager::timerDidFireCallback, &data.context)); >+ CFRunLoopAddTimer(data.runLoop.get(), data.timer.get(), kCFRunLoopCommonModes); >+ >+ EpochTime scheduleTime = s_decade; >+ for (auto& pair : data.timers) >+ scheduleTime = std::min(pair.second, scheduleTime); >+ CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value()); > } >+#endif > >-#else >+void JSRunLoopTimer::timerDidFire() >+{ >+ NO_TAIL_CALLS(); >+ >+ { >+ auto locker = holdLock(m_lock); >+ if (!m_isScheduled) { >+ // We raced between this callback being called and cancel() being called. >+ // That's fine, we just don't do anything here. >+ return; >+ } >+ } >+ >+ std::lock_guard<JSLock> lock(m_apiLock.get()); >+ RefPtr<VM> vm = m_apiLock->vm(); >+ if (!vm) { >+ // The VM has been destroyed, so we should just give up. >+ return; >+ } >+ >+ doWork(*vm); >+} > > JSRunLoopTimer::JSRunLoopTimer(VM* vm) >- : m_vm(vm) >- , m_apiLock(&vm->apiLock()) >- , m_timer(RunLoop::current(), this, &JSRunLoopTimer::timerDidFireCallback) >+ : m_apiLock(vm->apiLock()) > { >-#if USE(GLIB_EVENT_LOOP) >- m_timer.setPriority(RunLoopSourcePriority::JavascriptTimer); >- m_timer.setName("[JavaScriptCore] JSRunLoopTimer"); >-#endif >- m_timer.startOneShot(s_decade); > } > > JSRunLoopTimer::~JSRunLoopTimer() > { > } > >-void JSRunLoopTimer::timerDidFireCallback() >+std::optional<Seconds> JSRunLoopTimer::timeUntilFire() > { >- m_timer.startOneShot(s_decade); >- timerDidFire(); >+ return Manager::shared().timeUntilFire(*this); > } > >-void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds) >+void JSRunLoopTimer::setTimeUntilFire(Seconds intervalInSeconds) > { >- m_timer.startOneShot(intervalInSeconds); >- m_isScheduled = true; >+ { >+ auto locker = holdLock(m_lock); >+ m_isScheduled = true; >+ Manager::shared().scheduleTimer(*this, intervalInSeconds); >+ } > > auto locker = holdLock(m_timerCallbacksLock); > for (auto& task : m_timerSetCallbacks) >@@ -155,12 +317,11 @@ void JSRunLoopTimer::scheduleTimer(Secon > > void JSRunLoopTimer::cancelTimer() > { >- m_timer.startOneShot(s_decade); >+ auto locker = holdLock(m_lock); > m_isScheduled = false; >+ Manager::shared().cancelTimer(*this); > } > >-#endif >- > void JSRunLoopTimer::addTimerSetNotification(TimerNotificationCallback callback) > { > auto locker = holdLock(m_timerCallbacksLock); >Index: Source/JavaScriptCore/runtime/JSRunLoopTimer.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSRunLoopTimer.h (revision 234782) >+++ Source/JavaScriptCore/runtime/JSRunLoopTimer.h (working copy) >@@ -47,54 +47,88 @@ public: > typedef void TimerNotificationType(); > using TimerNotificationCallback = RefPtr<WTF::SharedTask<TimerNotificationType>>; > >- JSRunLoopTimer(VM*); >+ class Manager { >+#if USE(CF) >+ static void timerDidFireCallback(CFRunLoopTimerRef, void*); >+#else >+ void timerDidFireCallback(); >+#endif >+ >+ void timerDidFire(); >+ >+ public: >+ using EpochTime = Seconds; >+ >+ static Manager& shared(); >+ void registerVM(VM&); >+ void willDestroyVM(VM&); >+ void scheduleTimer(JSRunLoopTimer&, Seconds nextFireTime); >+ void cancelTimer(JSRunLoopTimer&); >+ >+ std::optional<Seconds> timeUntilFire(JSRunLoopTimer&); >+ >+#if USE(CF) >+ void didChangeRunLoop(VM&, CFRunLoopRef newRunLoop); >+#endif >+ >+ private: >+ Lock m_lock; >+ >+ struct PerVMData { >+ PerVMData() = default; >+#if USE(CF) >+ PerVMData(Manager&) { } >+#else >+ PerVMData(Manager&); >+#endif >+ PerVMData(PerVMData&&) = default; >+ PerVMData& operator=(PerVMData&&) = default; >+ > #if USE(CF) >- static void timerDidFireCallback(CFRunLoopTimerRef, void*); >+ RetainPtr<CFRunLoopTimerRef> timer; >+ RetainPtr<CFRunLoopRef> runLoop; >+ CFRunLoopTimerContext context; > #else >- void timerDidFireCallback(); >+ std::unique_ptr<RunLoop::Timer<Manager>> timer; > #endif >+ Vector<std::pair<Ref<JSRunLoopTimer>, EpochTime>> timers; >+ }; > >+ HashMap<Ref<JSLock>, PerVMData> m_mapping; >+ }; >+ >+ JSRunLoopTimer(VM*); > JS_EXPORT_PRIVATE virtual ~JSRunLoopTimer(); >- virtual void doWork() = 0; >+ virtual void doWork(VM&) = 0; > >- void scheduleTimer(Seconds intervalInSeconds); >+ void setTimeUntilFire(Seconds intervalInSeconds); > void cancelTimer(); > bool isScheduled() const { return m_isScheduled; } > > // Note: The only thing the timer notification callback cannot do is >- // call scheduleTimer(). This will cause a deadlock. It would not >+ // call setTimeUntilFire(). This will cause a deadlock. It would not > // be hard to make this work, however, there are no clients that need > // this behavior. We should implement it only if we find that we need it. > JS_EXPORT_PRIVATE void addTimerSetNotification(TimerNotificationCallback); > JS_EXPORT_PRIVATE void removeTimerSetNotification(TimerNotificationCallback); > >-#if USE(CF) >- JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef); >-#endif // USE(CF) >+ JS_EXPORT_PRIVATE std::optional<Seconds> timeUntilFire(); > > protected: >- VM* m_vm; >- > static const Seconds s_decade; > >- RefPtr<JSLock> m_apiLock; >- bool m_isScheduled { false }; >-#if USE(CF) >- RetainPtr<CFRunLoopTimerRef> m_timer; >- RetainPtr<CFRunLoopRef> m_runLoop; >+private: >+ friend class Manager; > >- CFRunLoopTimerContext m_context; >+ void timerDidFire(); > >- Lock m_shutdownMutex; >-#else >- RunLoop::Timer<JSRunLoopTimer> m_timer; >-#endif >+ Ref<JSLock> m_apiLock; > >- Lock m_timerCallbacksLock; > HashSet<TimerNotificationCallback> m_timerSetCallbacks; >- >-private: >- void timerDidFire(); >+ Lock m_timerCallbacksLock; >+ >+ Lock m_lock; >+ bool m_isScheduled { false }; > }; > > } // namespace JSC >Index: Source/JavaScriptCore/runtime/PromiseDeferredTimer.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/PromiseDeferredTimer.cpp (revision 234782) >+++ Source/JavaScriptCore/runtime/PromiseDeferredTimer.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -43,9 +43,9 @@ PromiseDeferredTimer::PromiseDeferredTim > { > } > >-void PromiseDeferredTimer::doWork() >+void PromiseDeferredTimer::doWork(VM& vm) > { >- ASSERT(m_vm->currentThreadIsHoldingAPILock()); >+ ASSERT(vm->currentThreadIsHoldingAPILock()); > m_taskLock.lock(); > cancelTimer(); > if (!m_runTasks) { >@@ -66,7 +66,7 @@ void PromiseDeferredTimer::doWork() > m_taskLock.unlock(); > > task(); >- m_vm->drainMicrotasks(); >+ vm.drainMicrotasks(); > > m_taskLock.lock(); > m_currentlyRunningTask = false; >@@ -75,7 +75,7 @@ void PromiseDeferredTimer::doWork() > > if (m_pendingPromises.isEmpty() && m_shouldStopRunLoopWhenAllPromisesFinish) { > #if USE(CF) >- CFRunLoopStop(m_runLoop.get()); >+ CFRunLoopStop(vm.runLoop()); > #else > RunLoop::current().stop(); > #endif >@@ -86,29 +86,30 @@ void PromiseDeferredTimer::doWork() > > void PromiseDeferredTimer::runRunLoop() > { >- ASSERT(!m_vm->currentThreadIsHoldingAPILock()); >+ ASSERT(!m_apiLock->vm()->currentThreadIsHoldingAPILock()); > #if USE(CF) >- ASSERT(CFRunLoopGetCurrent() == m_runLoop.get()); >+ ASSERT(CFRunLoopGetCurrent() == m_apiLock->vm()->runLoop()); > #endif > m_shouldStopRunLoopWhenAllPromisesFinish = true; >- if (m_pendingPromises.size()) >+ if (m_pendingPromises.size()) { > #if USE(CF) > CFRunLoopRun(); > #else > RunLoop::run(); > #endif >+ } > } > >-void PromiseDeferredTimer::addPendingPromise(JSPromiseDeferred* ticket, Vector<Strong<JSCell>>&& dependencies) >+void PromiseDeferredTimer::addPendingPromise(VM& vm, JSPromiseDeferred* ticket, Vector<Strong<JSCell>>&& dependencies) > { >- ASSERT(m_vm->currentThreadIsHoldingAPILock()); >+ ASSERT(vm->currentThreadIsHoldingAPILock()); > for (unsigned i = 0; i < dependencies.size(); ++i) > ASSERT(dependencies[i].get() != ticket); > > auto result = m_pendingPromises.add(ticket, Vector<Strong<JSCell>>()); > if (result.isNewEntry) { > dataLogLnIf(PromiseDeferredTimerInternal::verbose, "Adding new pending promise: ", RawPointer(ticket)); >- dependencies.append(Strong<JSCell>(*m_vm, ticket)); >+ dependencies.append(Strong<JSCell>(vm, ticket)); > result.iterator->value = WTFMove(dependencies); > } else { > dataLogLnIf(PromiseDeferredTimerInternal::verbose, "Adding new dependencies for promise: ", RawPointer(ticket)); >@@ -151,7 +152,7 @@ void PromiseDeferredTimer::scheduleWorkS > LockHolder locker(m_taskLock); > m_tasks.append(std::make_tuple(ticket, WTFMove(task))); > if (!isScheduled() && !m_currentlyRunningTask) >- scheduleTimer(0_s); >+ setTimeUntilFire(0_s); > } > > } // namespace JSC >Index: Source/JavaScriptCore/runtime/PromiseDeferredTimer.h >=================================================================== >--- Source/JavaScriptCore/runtime/PromiseDeferredTimer.h (revision 234782) >+++ Source/JavaScriptCore/runtime/PromiseDeferredTimer.h (working copy) >@@ -44,9 +44,9 @@ public: > > PromiseDeferredTimer(VM&); > >- void doWork() override; >+ void doWork(VM&) override; > >- void addPendingPromise(JSPromiseDeferred*, Vector<Strong<JSCell>>&& dependencies); >+ void addPendingPromise(VM&, JSPromiseDeferred*, Vector<Strong<JSCell>>&& dependencies); > JS_EXPORT_PRIVATE bool hasPendingPromise(JSPromiseDeferred* ticket); > JS_EXPORT_PRIVATE bool hasDependancyInPendingPromise(JSPromiseDeferred* ticket, JSCell* dependency); > // JSPromiseDeferred should handle canceling when the promise is resolved or rejected. >Index: Source/JavaScriptCore/runtime/VM.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/VM.cpp (revision 234782) >+++ Source/JavaScriptCore/runtime/VM.cpp (working copy) >@@ -381,6 +381,8 @@ VM::VM(VMType vmType, HeapType heapType) > updateSoftReservedZoneSize(Options::softReservedZoneSize()); > setLastStackTop(stack.origin()); > >+ JSRunLoopTimer::Manager::shared().registerVM(*this); >+ > // Need to be careful to keep everything consistent here > JSLockHolder lock(this); > AtomicStringTable* existingEntryAtomicStringTable = Thread::current().setCurrentAtomicStringTable(m_atomicStringTable); >@@ -572,7 +574,7 @@ VM::~VM() > } > } > #endif // ENABLE(DFG_JIT) >- >+ > waitForAsynchronousDisassembly(); > > // Clear this first to ensure that nobody tries to remove themselves from it. >@@ -581,6 +583,9 @@ VM::~VM() > ASSERT(currentThreadIsHoldingAPILock()); > m_apiLock->willDestroyVM(this); > heap.lastChanceToFinalize(); >+ >+ // This needs to happen after lastChanceToFinalize. >+ JSRunLoopTimer::Manager::shared().willDestroyVM(*this); > > delete interpreter; > #ifndef NDEBUG >@@ -1209,27 +1214,11 @@ void VM::verifyExceptionCheckNeedIsSatis > #endif > > #if USE(CF) >-void VM::registerRunLoopTimer(JSRunLoopTimer* timer) >-{ >- ASSERT(runLoop()); >- ASSERT(!m_runLoopTimers.contains(timer)); >- m_runLoopTimers.add(timer); >- timer->setRunLoop(runLoop()); >-} >- >-void VM::unregisterRunLoopTimer(JSRunLoopTimer* timer) >-{ >- ASSERT(m_runLoopTimers.contains(timer)); >- m_runLoopTimers.remove(timer); >- timer->setRunLoop(nullptr); >-} >- > void VM::setRunLoop(CFRunLoopRef runLoop) > { > ASSERT(runLoop); > m_runLoop = runLoop; >- for (auto timer : m_runLoopTimers) >- timer->setRunLoop(runLoop); >+ JSRunLoopTimer::Manager::shared().didChangeRunLoop(*this, runLoop); > } > #endif // USE(CF) > >Index: Source/JavaScriptCore/runtime/VM.h >=================================================================== >--- Source/JavaScriptCore/runtime/VM.h (revision 234782) >+++ Source/JavaScriptCore/runtime/VM.h (working copy) >@@ -302,7 +302,6 @@ private: > RefPtr<JSLock> m_apiLock; > #if USE(CF) > // These need to be initialized before heap below. >- HashSet<JSRunLoopTimer*> m_runLoopTimers; > RetainPtr<CFRunLoopRef> m_runLoop; > #endif > >@@ -882,8 +881,6 @@ public: > > #if USE(CF) > CFRunLoopRef runLoop() const { return m_runLoop.get(); } >- void registerRunLoopTimer(JSRunLoopTimer*); >- void unregisterRunLoopTimer(JSRunLoopTimer*); > JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef); > #endif // USE(CF) > >Index: Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp (revision 234782) >+++ Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp (working copy) >@@ -91,7 +91,7 @@ static void webAssemblyModuleValidateAsy > Vector<Strong<JSCell>> dependencies; > dependencies.append(Strong<JSCell>(vm, globalObject)); > >- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies)); >+ vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); > > Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable { > vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, globalObject, result = WTFMove(result), &vm] () mutable { >@@ -173,7 +173,7 @@ static void instantiate(VM& vm, ExecStat > // The instance keeps the module alive. > dependencies.append(Strong<JSCell>(vm, instance)); > dependencies.append(Strong<JSCell>(vm, importObject)); >- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies)); >+ vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); > // Note: This completion task may or may not get called immediately. > module->module().compileAsync(&vm.wasmContext, instance->memoryMode(), createSharedTask<Wasm::CodeBlock::CallbackType>([promise, instance, module, importObject, resolveKind, creationMode, &vm] (Ref<Wasm::CodeBlock>&& refCodeBlock) mutable { > RefPtr<Wasm::CodeBlock> codeBlock = WTFMove(refCodeBlock); >@@ -194,7 +194,7 @@ static void compileAndInstantiate(VM& vm > Vector<Strong<JSCell>> dependencies; > dependencies.append(Strong<JSCell>(vm, importObject)); > dependencies.append(Strong<JSCell>(vm, moduleKeyCell)); >- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies)); >+ vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); > > Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, buffer); > RETURN_IF_EXCEPTION(scope, reject(exec, scope, promise)); >@@ -231,7 +231,7 @@ static void webAssemblyModuleInstantinat > Vector<Strong<JSCell>> dependencies; > dependencies.append(Strong<JSCell>(vm, importObject)); > dependencies.append(Strong<JSCell>(vm, globalObject)); >- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies)); >+ vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); > > Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, importObject, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable { > vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, importObject, globalObject, result = WTFMove(result), &vm] () mutable { >@@ -310,7 +310,7 @@ EncodedJSValue JSC_HOST_CALL webAssembly > > Vector<Strong<JSCell>> dependencies; > dependencies.append(Strong<JSCell>(vm, globalObject)); >- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies)); >+ vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); > > if (globalObject->globalObjectMethodTable()->compileStreaming) > globalObject->globalObjectMethodTable()->compileStreaming(globalObject, exec, promise, exec->argument(0)); >@@ -347,7 +347,7 @@ EncodedJSValue JSC_HOST_CALL webAssembly > Vector<Strong<JSCell>> dependencies; > dependencies.append(Strong<JSCell>(vm, globalObject)); > dependencies.append(Strong<JSCell>(vm, importObject)); >- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies)); >+ vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies)); > > // 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. > globalObject->globalObjectMethodTable()->instantiateStreaming(globalObject, exec, promise, exec->argument(0), importObject); >Index: Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm >=================================================================== >--- Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm (revision 234782) >+++ Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm (working copy) >@@ -248,8 +248,9 @@ void ResourceUsageThread::platformThread > > data.totalExternalSize = currentGCOwnedExternal; > >- data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime(); >- data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime(); >+ auto now = MonotonicTime::now(); >+ data.timeOfNextEdenCollection = now + vm->heap.edenActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); >+ data.timeOfNextFullCollection = now + vm->heap.fullActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); > } > > } >Index: Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp >=================================================================== >--- Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp (revision 234782) >+++ Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp (working copy) >@@ -1,5 +1,6 @@ > /* > * Copyright (C) 2017 Igalia S.L. >+ * Copyright (C) 2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -168,8 +169,9 @@ void ResourceUsageThread::platformThread > > data.totalExternalSize = currentGCOwnedExternal; > >- data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime(); >- data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime(); >+ auto now = MonotonicTime::now(); >+ data.timeOfNextEdenCollection = now + vm->heap.edenActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); >+ data.timeOfNextFullCollection = now + vm->heap.fullActivityCallback()->timeUntilFire().value_or(Seconds(std::numeric_limits<double>::infinity())); > } > > } // namespace WebCore
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ews-watchlist
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188426
:
346884
|
346885
|
346887
|
346888
|
346890
|
346891
|
346892
|
346893
|
346894
|
346929
|
346996
|
346997
|
347000
|
347001
|
347005
|
347021
|
347029
|
347030
|
347031
|
347032
|
347056
|
347065
|
347102
|
347105
|
347232
|
347584
|
347591
|
347747
|
347825