Diff
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/ChangeLog (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/ChangeLog 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/ChangeLog 2018-09-17 09:25:37 UTC (rev 236046)
@@ -1,3 +1,135 @@
+2018-08-23 Saam barati <sbar...@apple.com>
+
+ JSRunLoopTimer may run part of a member function after it's destroyed
+ https://bugs.webkit.org/show_bug.cgi?id=188426
+
+ Reviewed by Mark Lam.
+
+ When I was reading the JSRunLoopTimer code, I noticed that it is possible
+ to end up running timer code after the class had been destroyed.
+
+ The issue I spotted was in this function:
+ ```
+ void JSRunLoopTimer::timerDidFire()
+ {
+ JSLock* apiLock = m_apiLock.get();
+ if (!apiLock) {
+ // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed.
+ return;
+ }
+ // HERE
+ 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;
+ }
+
+ doWork();
+ }
+ ```
+
+ Look at the comment 'HERE'. Let's say that the timer callback thread gets context
+ switched before grabbing the API lock. Then, some other thread destroys the VM.
+ And let's say that the VM owns (perhaps transitively) this timer. Then, the
+ timer would run code and access member variables after it was destroyed.
+
+ This patch fixes this issue by introducing a new timer manager class.
+ This class manages timers on a per VM basis. When a timer is scheduled,
+ this class refs the timer. It also calls the timer callback while actively
+ maintaining a +1 ref to it. So, it's no longer possible to call the timer
+ callback after the timer has been destroyed. However, calling a timer callback
+ can still race with the VM being destroyed. We continue to detect this case and
+ bail out of the callback early.
+
+ This patch also removes a lot of duplicate code between GCActivityCallback
+ and JSRunLoopTimer.
+
+ * heap/EdenGCActivityCallback.cpp:
+ (JSC::EdenGCActivityCallback::doCollection):
+ (JSC::EdenGCActivityCallback::lastGCLength):
+ (JSC::EdenGCActivityCallback::deathRate):
+ * heap/EdenGCActivityCallback.h:
+ * heap/FullGCActivityCallback.cpp:
+ (JSC::FullGCActivityCallback::doCollection):
+ (JSC::FullGCActivityCallback::lastGCLength):
+ (JSC::FullGCActivityCallback::deathRate):
+ * heap/FullGCActivityCallback.h:
+ * heap/GCActivityCallback.cpp:
+ (JSC::GCActivityCallback::doWork):
+ (JSC::GCActivityCallback::scheduleTimer):
+ (JSC::GCActivityCallback::didAllocate):
+ (JSC::GCActivityCallback::willCollect):
+ (JSC::GCActivityCallback::cancel):
+ (JSC::GCActivityCallback::cancelTimer): Deleted.
+ (JSC::GCActivityCallback::nextFireTime): Deleted.
+ * heap/GCActivityCallback.h:
+ * heap/Heap.cpp:
+ (JSC::Heap::reportAbandonedObjectGraph):
+ (JSC::Heap::notifyIncrementalSweeper):
+ (JSC::Heap::updateAllocationLimits):
+ (JSC::Heap::didAllocate):
+ * heap/IncrementalSweeper.cpp:
+ (JSC::IncrementalSweeper::scheduleTimer):
+ (JSC::IncrementalSweeper::doWork):
+ (JSC::IncrementalSweeper::doSweep):
+ (JSC::IncrementalSweeper::sweepNextBlock):
+ (JSC::IncrementalSweeper::startSweeping):
+ (JSC::IncrementalSweeper::stopSweeping):
+ * heap/IncrementalSweeper.h:
+ * heap/StopIfNecessaryTimer.cpp:
+ (JSC::StopIfNecessaryTimer::doWork):
+ (JSC::StopIfNecessaryTimer::scheduleSoon):
+ * heap/StopIfNecessaryTimer.h:
+ * runtime/JSRunLoopTimer.cpp:
+ (JSC::epochTime):
+ (JSC::JSRunLoopTimer::Manager::timerDidFireCallback):
+ (JSC::JSRunLoopTimer::Manager::PerVMData::setRunLoop):
+ (JSC::JSRunLoopTimer::Manager::PerVMData::PerVMData):
+ (JSC::JSRunLoopTimer::Manager::PerVMData::~PerVMData):
+ (JSC::JSRunLoopTimer::Manager::timerDidFire):
+ (JSC::JSRunLoopTimer::Manager::shared):
+ (JSC::JSRunLoopTimer::Manager::registerVM):
+ (JSC::JSRunLoopTimer::Manager::unregisterVM):
+ (JSC::JSRunLoopTimer::Manager::scheduleTimer):
+ (JSC::JSRunLoopTimer::Manager::cancelTimer):
+ (JSC::JSRunLoopTimer::Manager::timeUntilFire):
+ (JSC::JSRunLoopTimer::Manager::didChangeRunLoop):
+ (JSC::JSRunLoopTimer::timerDidFire):
+ (JSC::JSRunLoopTimer::JSRunLoopTimer):
+ (JSC::JSRunLoopTimer::timeUntilFire):
+ (JSC::JSRunLoopTimer::setTimeUntilFire):
+ (JSC::JSRunLoopTimer::cancelTimer):
+ (JSC::JSRunLoopTimer::setRunLoop): Deleted.
+ (JSC::JSRunLoopTimer::timerDidFireCallback): Deleted.
+ (JSC::JSRunLoopTimer::scheduleTimer): Deleted.
+ * runtime/JSRunLoopTimer.h:
+ (JSC::JSRunLoopTimer::Manager::PerVMData::PerVMData):
+ * runtime/PromiseDeferredTimer.cpp:
+ (JSC::PromiseDeferredTimer::doWork):
+ (JSC::PromiseDeferredTimer::runRunLoop):
+ (JSC::PromiseDeferredTimer::addPendingPromise):
+ (JSC::PromiseDeferredTimer::hasPendingPromise):
+ (JSC::PromiseDeferredTimer::hasDependancyInPendingPromise):
+ (JSC::PromiseDeferredTimer::cancelPendingPromise):
+ (JSC::PromiseDeferredTimer::scheduleWorkSoon):
+ * runtime/PromiseDeferredTimer.h:
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ (JSC::VM::~VM):
+ (JSC::VM::setRunLoop):
+ (JSC::VM::registerRunLoopTimer): Deleted.
+ (JSC::VM::unregisterRunLoopTimer): Deleted.
+ * runtime/VM.h:
+ (JSC::VM::runLoop const):
+ * wasm/js/WebAssemblyPrototype.cpp:
+ (JSC::webAssemblyModuleValidateAsyncInternal):
+ (JSC::instantiate):
+ (JSC::compileAndInstantiate):
+ (JSC::webAssemblyModuleInstantinateAsyncInternal):
+ (JSC::webAssemblyCompileStreamingInternal):
+ (JSC::webAssemblyInstantiateStreamingInternal):
+
2018-08-23 Mark Lam <mark....@apple.com>
Move vmEntryGlobalObject() to VM from CallFrame.
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/EdenGCActivityCallback.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/EdenGCActivityCallback.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/EdenGCActivityCallback.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -36,21 +36,20 @@
{
}
-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) {
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/EdenGCActivityCallback.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/EdenGCActivityCallback.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/EdenGCActivityCallback.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -33,12 +33,12 @@
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)
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/FullGCActivityCallback.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/FullGCActivityCallback.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/FullGCActivityCallback.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -39,9 +39,9 @@
{
}
-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 @@
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) {
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/FullGCActivityCallback.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/FullGCActivityCallback.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/FullGCActivityCallback.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -33,15 +33,15 @@
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 };
};
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/GCActivityCallback.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/GCActivityCallback.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/GCActivityCallback.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -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,22 +45,21 @@
{
}
-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)
@@ -67,61 +66,31 @@
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(newDelay);
}
-void GCActivityCallback::cancelTimer()
+void GCActivityCallback::didAllocate(Heap& heap, size_t bytes)
{
- 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)
-{
// 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();
}
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/GCActivityCallback.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/GCActivityCallback.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/GCActivityCallback.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -48,24 +48,22 @@
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 @@
bool m_enabled;
protected:
- void cancelTimer();
void scheduleTimer(Seconds);
private:
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/Heap.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/Heap.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/Heap.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -539,7 +539,7 @@
// 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 @@
m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
}
- m_sweeper->startSweeping();
+ m_sweeper->startSweeping(*this);
}
void Heap::updateAllocationLimits()
@@ -2273,7 +2273,7 @@
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::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);
}
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/IncrementalSweeper.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/IncrementalSweeper.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/IncrementalSweeper.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -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
@@ -34,13 +34,13 @@
namespace JSC {
-static const Seconds sweepTimeSlice = 10_ms; // seconds
+static const Seconds sweepTimeSlice = 10_ms;
static const double sweepTimeTotal = .10;
static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal;
void IncrementalSweeper::scheduleTimer()
{
- Base::scheduleTimer(sweepTimeSlice * sweepTimeMultiplier);
+ setTimeUntilFire(sweepTimeSlice * sweepTimeMultiplier);
}
IncrementalSweeper::IncrementalSweeper(Heap* heap)
@@ -49,14 +49,14 @@
{
}
-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 @@
cancelTimer();
}
-bool IncrementalSweeper::sweepNextBlock()
+bool IncrementalSweeper::sweepNextBlock(VM& vm)
{
- m_vm->heap.stopIfNecessary();
+ vm.heap.stopIfNecessary();
MarkedBlock::Handle* block = nullptr;
@@ -85,26 +85,25 @@
}
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
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/IncrementalSweeper.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/IncrementalSweeper.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/IncrementalSweeper.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -37,15 +37,15 @@
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;
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/StopIfNecessaryTimer.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/StopIfNecessaryTimer.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/StopIfNecessaryTimer.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -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 @@
{
}
-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 @@
WTF::loadLoadFence();
return;
}
- scheduleTimer(0_s);
+ setTimeUntilFire(0_s);
}
} // namespace JSC
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/StopIfNecessaryTimer.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/StopIfNecessaryTimer.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/heap/StopIfNecessaryTimer.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -36,7 +36,7 @@
using Base = JSRunLoopTimer;
explicit StopIfNecessaryTimer(VM*);
- void doWork() override;
+ void doWork(VM&) override;
void scheduleSoon();
};
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/JSRunLoopTimer.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/JSRunLoopTimer.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/JSRunLoopTimer.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -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,7 +26,6 @@
#include "config.h"
#include "JSRunLoopTimer.h"
-#include "GCActivityCallback.h"
#include "IncrementalSweeper.h"
#include "JSCInlines.h"
#include "JSObject.h"
@@ -33,6 +32,7 @@
#include "JSString.h"
#include <wtf/MainThread.h>
+#include <wtf/NoTailCalls.h>
#include <wtf/Threading.h>
#if USE(GLIB_EVENT_LOOP)
@@ -46,107 +46,288 @@
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
+}
+
+#if USE(CF)
+void JSRunLoopTimer::Manager::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr)
+{
+ static_cast<JSRunLoopTimer::Manager*>(contextPtr)->timerDidFire();
+}
+
+void JSRunLoopTimer::Manager::PerVMData::setRunLoop(Manager* manager, CFRunLoopRef newRunLoop)
+{
+ if (runLoop) {
+ CFRunLoopRemoveTimer(runLoop.get(), timer.get(), kCFRunLoopCommonModes);
+ CFRunLoopTimerInvalidate(timer.get());
+ runLoop.clear();
+ timer.clear();
}
- 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 (newRunLoop) {
+ runLoop = newRunLoop;
+ memset(&context, 0, sizeof(CFRunLoopTimerContext));
+ RELEASE_ASSERT(manager);
+ context.info = manager;
+ timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), CFAbsoluteTimeGetCurrent() + s_decade.seconds(), 0, 0, JSRunLoopTimer::Manager::timerDidFireCallback, &context));
+ CFRunLoopAddTimer(runLoop.get(), timer.get(), kCFRunLoopCommonModes);
+
+ EpochTime scheduleTime = epochTime(s_decade);
+ for (auto& pair : timers)
+ scheduleTime = std::min(pair.second, scheduleTime);
+ CFRunLoopTimerSetNextFireDate(timer.get(), scheduleTime.value());
}
+}
+#else
+JSRunLoopTimer::Manager::PerVMData::PerVMData(Manager& manager)
+ : runLoop(&RunLoop::current())
+ , timer(std::make_unique<RunLoop::Timer<Manager>>(*runLoop, &manager, &JSRunLoopTimer::Manager::timerDidFireCallback))
+{
+#if USE(GLIB_EVENT_LOOP)
+ timer->setPriority(RunLoopSourcePriority::_javascript_Timer);
+ timer->setName("[_javascript_Core] JSRunLoopTimer");
+#endif
+}
- doWork();
+void JSRunLoopTimer::Manager::timerDidFireCallback()
+{
+ timerDidFire();
}
+#endif
+JSRunLoopTimer::Manager::PerVMData::~PerVMData()
+{
#if USE(CF)
+ setRunLoop(nullptr, nullptr);
+#endif
+}
-JSRunLoopTimer::JSRunLoopTimer(VM* vm)
- : m_vm(vm)
- , m_apiLock(&vm->apiLock())
+void JSRunLoopTimer::Manager::timerDidFire()
{
- m_vm->registerRunLoopTimer(this);
-}
+ Vector<Ref<JSRunLoopTimer>> timersToFire;
-void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop)
-{
- if (m_runLoop) {
- CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
- CFRunLoopTimerInvalidate(m_timer.get());
- m_runLoop.clear();
- m_timer.clear();
+ {
+ auto locker = holdLock(m_lock);
+#if USE(CF)
+ CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
+#else
+ RunLoop* currentRunLoop = &RunLoop::current();
+#endif
+ EpochTime nowEpochTime = epochTime(0_s);
+ for (auto& entry : m_mapping) {
+ PerVMData& data = ""
+#if USE(CF)
+ if (data.runLoop.get() != currentRunLoop)
+ continue;
+#else
+ if (data.runLoop != currentRunLoop)
+ continue;
+#endif
+
+ EpochTime scheduleTime = epochTime(s_decade);
+ for (size_t i = 0; i < data.timers.size(); ++i) {
+ {
+ auto& pair = data.timers[i];
+ if (pair.second > nowEpochTime) {
+ scheduleTime = std::min(pair.second, scheduleTime);
+ continue;
+ }
+ auto& last = data.timers.last();
+ if (&last != &pair)
+ std::swap(pair, 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
+ }
}
- 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);
- }
+ for (auto& timer : timersToFire)
+ timer->timerDidFire();
}
-JSRunLoopTimer::~JSRunLoopTimer()
+JSRunLoopTimer::Manager& JSRunLoopTimer::Manager::shared()
{
- JSLock* apiLock = m_apiLock.get();
- std::lock_guard<JSLock> lock(*apiLock);
- m_vm->unregisterRunLoopTimer(this);
- m_apiLock = nullptr;
+ static Manager* manager;
+ static std::once_flag once;
+ std::call_once(once, [&] {
+ manager = new Manager;
+ });
+ return *manager;
}
-void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr)
+void JSRunLoopTimer::Manager::registerVM(VM& vm)
{
- static_cast<JSRunLoopTimer*>(contextPtr)->timerDidFire();
+ PerVMData data { *this };
+#if USE(CF)
+ data.setRunLoop(this, vm.runLoop());
+#endif
+
+ auto locker = holdLock(m_lock);
+ auto addResult = m_mapping.add({ vm.apiLock() }, WTFMove(data));
+ RELEASE_ASSERT(addResult.isNewEntry);
}
-void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds)
+void JSRunLoopTimer::Manager::unregisterVM(VM& vm)
{
- 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({ vm.apiLock() });
+ RELEASE_ASSERT(iter != m_mapping.end());
+ m_mapping.remove(iter);
}
-void JSRunLoopTimer::cancelTimer()
+void JSRunLoopTimer::Manager::scheduleTimer(JSRunLoopTimer& timer, Seconds delay)
{
- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds());
- m_isScheduled = false;
+ EpochTime fireEpochTime = epochTime(delay);
+
+ 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 = ""
+ EpochTime scheduleTime = fireEpochTime;
+ bool found = false;
+ for (auto& entry : data.timers) {
+ if (entry.first.ptr() == &timer) {
+ entry.second = fireEpochTime;
+ found = true;
+ }
+ scheduleTime = std::min(scheduleTime, entry.second);
+ }
+
+ if (!found)
+ data.timers.append({ timer, fireEpochTime });
+
+#if USE(CF)
+ CFRunLoopTimerSetNextFireDate(data.timer.get(), scheduleTime.value());
+#else
+ data.timer->startOneShot(std::max(0_s, scheduleTime - MonotonicTime::now().secondsSinceEpoch()));
+#endif
}
+void JSRunLoopTimer::Manager::cancelTimer(JSRunLoopTimer& timer)
+{
+ 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 = ""
+ EpochTime scheduleTime = epochTime(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!
+ auto& last = data.timers.last();
+ if (&last != &entry)
+ std::swap(entry, 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
+}
-JSRunLoopTimer::JSRunLoopTimer(VM* vm)
- : m_vm(vm)
- , m_apiLock(&vm->apiLock())
- , m_timer(RunLoop::current(), this, &JSRunLoopTimer::timerDidFireCallback)
+std::optional<Seconds> JSRunLoopTimer::Manager::timeUntilFire(JSRunLoopTimer& timer)
{
-#if USE(GLIB_EVENT_LOOP)
- m_timer.setPriority(RunLoopSourcePriority::_javascript_Timer);
- m_timer.setName("[_javascript_Core] JSRunLoopTimer");
+ 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 = ""
+ for (auto& entry : data.timers) {
+ if (entry.first.ptr() == &timer) {
+ EpochTime nowEpochTime = epochTime(0_s);
+ return entry.second - nowEpochTime;
+ }
+ }
+
+ return std::nullopt;
+}
+
+#if USE(CF)
+void JSRunLoopTimer::Manager::didChangeRunLoop(VM& vm, CFRunLoopRef newRunLoop)
+{
+ auto locker = holdLock(m_lock);
+ auto iter = m_mapping.find({ vm.apiLock() });
+ RELEASE_ASSERT(iter != m_mapping.end());
+
+ PerVMData& data = ""
+ data.setRunLoop(this, newRunLoop);
+}
#endif
- m_timer.startOneShot(s_decade);
+
+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_apiLock(vm->apiLock())
+{
+}
+
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 +336,11 @@
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);
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/JSRunLoopTimer.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/JSRunLoopTimer.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/JSRunLoopTimer.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -47,54 +47,91 @@
typedef void TimerNotificationType();
using TimerNotificationCallback = RefPtr<WTF::SharedTask<TimerNotificationType>>;
- JSRunLoopTimer(VM*);
+ class Manager {
#if USE(CF)
- static void timerDidFireCallback(CFRunLoopTimerRef, void*);
+ static void timerDidFireCallback(CFRunLoopTimerRef, void*);
#else
- void timerDidFireCallback();
+ void timerDidFireCallback();
#endif
+ void timerDidFire();
+
+ public:
+ using EpochTime = Seconds;
+
+ static Manager& shared();
+ void registerVM(VM&);
+ void unregisterVM(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;
+
+ ~PerVMData();
+
+#if USE(CF)
+ void setRunLoop(Manager*, CFRunLoopRef);
+ RetainPtr<CFRunLoopTimerRef> timer;
+ RetainPtr<CFRunLoopRef> runLoop;
+ CFRunLoopTimerContext context;
+#else
+ RunLoop* runLoop;
+ 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;
+ Ref<JSLock> m_apiLock;
- 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
+ HashSet<TimerNotificationCallback> m_timerSetCallbacks;
+ Lock m_timerCallbacksLock;
- Lock m_timerCallbacksLock;
- HashSet<TimerNotificationCallback> m_timerSetCallbacks;
-
-private:
- void timerDidFire();
+ Lock m_lock;
+ bool m_isScheduled { false };
};
} // namespace JSC
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/PromiseDeferredTimer.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/PromiseDeferredTimer.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/PromiseDeferredTimer.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -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 @@
{
}
-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 @@
m_taskLock.unlock();
task();
- m_vm->drainMicrotasks();
+ vm.drainMicrotasks();
m_taskLock.lock();
m_currentlyRunningTask = false;
@@ -75,7 +75,7 @@
if (m_pendingPromises.isEmpty() && m_shouldStopRunLoopWhenAllPromisesFinish) {
#if USE(CF)
- CFRunLoopStop(m_runLoop.get());
+ CFRunLoopStop(vm.runLoop());
#else
RunLoop::current().stop();
#endif
@@ -86,22 +86,23 @@
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);
@@ -108,7 +109,7 @@
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));
@@ -122,13 +123,13 @@
bool PromiseDeferredTimer::hasPendingPromise(JSPromiseDeferred* ticket)
{
- ASSERT(m_vm->currentThreadIsHoldingAPILock());
+ ASSERT(ticket->vm()->currentThreadIsHoldingAPILock());
return m_pendingPromises.contains(ticket);
}
bool PromiseDeferredTimer::hasDependancyInPendingPromise(JSPromiseDeferred* ticket, JSCell* dependency)
{
- ASSERT(m_vm->currentThreadIsHoldingAPILock());
+ ASSERT(ticket->vm()->currentThreadIsHoldingAPILock());
ASSERT(m_pendingPromises.contains(ticket));
auto result = m_pendingPromises.get(ticket);
@@ -137,7 +138,7 @@
bool PromiseDeferredTimer::cancelPendingPromise(JSPromiseDeferred* ticket)
{
- ASSERT(m_vm->currentThreadIsHoldingAPILock());
+ ASSERT(ticket->vm()->currentThreadIsHoldingAPILock());
bool result = m_pendingPromises.remove(ticket);
if (result)
@@ -151,7 +152,7 @@
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
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/PromiseDeferredTimer.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/PromiseDeferredTimer.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/PromiseDeferredTimer.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -44,9 +44,9 @@
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.
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/VM.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/VM.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/VM.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -381,6 +381,8 @@
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);
@@ -581,6 +583,8 @@
ASSERT(currentThreadIsHoldingAPILock());
m_apiLock->willDestroyVM(this);
heap.lastChanceToFinalize();
+
+ JSRunLoopTimer::Manager::shared().unregisterVM(*this);
delete interpreter;
#ifndef NDEBUG
@@ -1209,27 +1213,11 @@
#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)
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/VM.h (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/VM.h 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/runtime/VM.h 2018-09-17 09:25:37 UTC (rev 236046)
@@ -307,7 +307,6 @@
RefPtr<JSLock> m_apiLock;
#if USE(CF)
// These need to be initialized before heap below.
- HashSet<JSRunLoopTimer*> m_runLoopTimers;
RetainPtr<CFRunLoopRef> m_runLoop;
#endif
@@ -887,8 +886,6 @@
#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)
Modified: releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/wasm/js/WebAssemblyPrototype.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/wasm/js/WebAssemblyPrototype.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/_javascript_Core/wasm/js/WebAssemblyPrototype.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -91,7 +91,7 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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);
Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog 2018-09-17 09:25:37 UTC (rev 236046)
@@ -1,3 +1,15 @@
+2018-08-23 Saam barati <sbar...@apple.com>
+
+ JSRunLoopTimer may run part of a member function after it's destroyed
+ https://bugs.webkit.org/show_bug.cgi?id=188426
+
+ Reviewed by Mark Lam.
+
+ * page/cocoa/ResourceUsageThreadCocoa.mm:
+ (WebCore::ResourceUsageThread::platformThreadBody):
+ * page/linux/ResourceUsageThreadLinux.cpp:
+ (WebCore::ResourceUsageThread::platformThreadBody):
+
2018-08-23 Mark Lam <mark....@apple.com>
Move vmEntryGlobalObject() to VM from CallFrame.
Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm 2018-09-17 09:25:37 UTC (rev 236046)
@@ -248,8 +248,9 @@
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()));
}
}
Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp (236045 => 236046)
--- releases/WebKitGTK/webkit-2.22/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp 2018-09-17 09:25:18 UTC (rev 236045)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp 2018-09-17 09:25:37 UTC (rev 236046)
@@ -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 @@
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