Unreviewed, rolling out r235107.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Aug 2018 01:24:52 +0000 (01:24 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Aug 2018 01:24:52 +0000 (01:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188832

"It revealed bugs in Blob code as well as regressed JS
performance tests" (Requested by saamyjoon on #webkit).

Reverted changeset:

"JSRunLoopTimer may run part of a member function after it's
destroyed"
https://bugs.webkit.org/show_bug.cgi?id=188426
https://trac.webkit.org/changeset/235107

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@235152 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp
Source/JavaScriptCore/heap/EdenGCActivityCallback.h
Source/JavaScriptCore/heap/FullGCActivityCallback.cpp
Source/JavaScriptCore/heap/FullGCActivityCallback.h
Source/JavaScriptCore/heap/GCActivityCallback.cpp
Source/JavaScriptCore/heap/GCActivityCallback.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/IncrementalSweeper.cpp
Source/JavaScriptCore/heap/IncrementalSweeper.h
Source/JavaScriptCore/heap/StopIfNecessaryTimer.cpp
Source/JavaScriptCore/heap/StopIfNecessaryTimer.h
Source/JavaScriptCore/runtime/JSRunLoopTimer.cpp
Source/JavaScriptCore/runtime/JSRunLoopTimer.h
Source/JavaScriptCore/runtime/PromiseDeferredTimer.cpp
Source/JavaScriptCore/runtime/PromiseDeferredTimer.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp
Source/WebCore/ChangeLog
Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm
Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp

index ea61d67..31482bb 100644 (file)
@@ -1,3 +1,18 @@
+2018-08-21  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r235107.
+        https://bugs.webkit.org/show_bug.cgi?id=188832
+
+        "It revealed bugs in Blob code as well as regressed JS
+        performance tests" (Requested by saamyjoon on #webkit).
+
+        Reverted changeset:
+
+        "JSRunLoopTimer may run part of a member function after it's
+        destroyed"
+        https://bugs.webkit.org/show_bug.cgi?id=188426
+        https://trac.webkit.org/changeset/235107
+
 2018-08-21  Saam barati  <sbarati@apple.com>
 
         JSRunLoopTimer may run part of a member function after it's destroyed
index 0ca5014..b6bde3d 100644 (file)
@@ -36,20 +36,21 @@ EdenGCActivityCallback::EdenGCActivityCallback(Heap* heap)
 {
 }
 
-void EdenGCActivityCallback::doCollection(VM& vm)
+void EdenGCActivityCallback::doCollection()
 {
-    vm.heap.collectAsync(CollectionScope::Eden);
+    m_vm->heap.collectAsync(CollectionScope::Eden);
 }
 
-Seconds EdenGCActivityCallback::lastGCLength(Heap& heap)
+Seconds EdenGCActivityCallback::lastGCLength()
 {
-    return heap.lastEdenGCLength();
+    return m_vm->heap.lastEdenGCLength();
 }
 
-double EdenGCActivityCallback::deathRate(Heap& heap)
+double EdenGCActivityCallback::deathRate()
 {
-    size_t sizeBefore = heap.sizeBeforeLastEdenCollection();
-    size_t sizeAfter = heap.sizeAfterLastEdenCollection();
+    Heap* heap = &m_vm->heap;
+    size_t sizeBefore = heap->sizeBeforeLastEdenCollection();
+    size_t sizeAfter = heap->sizeAfterLastEdenCollection();
     if (!sizeBefore)
         return 1.0;
     if (sizeAfter > sizeBefore) {
index 52e0a28..87482bd 100644 (file)
@@ -33,12 +33,12 @@ class JS_EXPORT_PRIVATE EdenGCActivityCallback : public GCActivityCallback {
 public:
     EdenGCActivityCallback(Heap*);
 
-    void doCollection(VM&) override;
+    void doCollection() override;
 
 protected:
-    Seconds lastGCLength(Heap&) override;
+    Seconds lastGCLength() override;
     double gcTimeSlice(size_t bytes) override;
-    double deathRate(Heap&) override;
+    double deathRate() override;
 };
 
 inline RefPtr<GCActivityCallback> GCActivityCallback::createEdenTimer(Heap* heap)
index c9ef7fe..d998a29 100644 (file)
@@ -39,9 +39,9 @@ FullGCActivityCallback::FullGCActivityCallback(Heap* heap)
 {
 }
 
-void FullGCActivityCallback::doCollection(VM& vm)
+void FullGCActivityCallback::doCollection()
 {
-    Heap& heap = vm.heap;
+    Heap& heap = m_vm->heap;
     m_didGCRecently = false;
 
 #if !PLATFORM(IOS)
@@ -56,15 +56,16 @@ void FullGCActivityCallback::doCollection(VM& vm)
     heap.collectAsync(CollectionScope::Full);
 }
 
-Seconds FullGCActivityCallback::lastGCLength(Heap& heap)
+Seconds FullGCActivityCallback::lastGCLength()
 {
-    return heap.lastFullGCLength();
+    return m_vm->heap.lastFullGCLength();
 }
 
-double FullGCActivityCallback::deathRate(Heap& heap)
+double FullGCActivityCallback::deathRate()
 {
-    size_t sizeBefore = heap.sizeBeforeLastFullCollection();
-    size_t sizeAfter = heap.sizeAfterLastFullCollection();
+    Heap* heap = &m_vm->heap;
+    size_t sizeBefore = heap->sizeBeforeLastFullCollection();
+    size_t sizeAfter = heap->sizeAfterLastFullCollection();
     if (!sizeBefore)
         return 1.0;
     if (sizeAfter > sizeBefore) {
index 5ce034a..da89c7d 100644 (file)
@@ -33,15 +33,15 @@ class JS_EXPORT_PRIVATE FullGCActivityCallback : public GCActivityCallback {
 public:
     FullGCActivityCallback(Heap*);
 
-    void doCollection(VM&) override;
+    void doCollection() override;
 
     bool didGCRecently() const { return m_didGCRecently; }
     void setDidGCRecently() { m_didGCRecently = true; }
 
 protected:
-    Seconds lastGCLength(Heap&) override;
+    Seconds lastGCLength() override;
     double gcTimeSlice(size_t bytes) override;
-    double deathRate(Heap&) override;
+    double deathRate() override;
 
     bool m_didGCRecently { false };
 };
index e5a7802..007fdd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2017 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,52 +45,83 @@ GCActivityCallback::GCActivityCallback(Heap* heap)
 {
 }
 
-void GCActivityCallback::doWork(VM& vm)
+void GCActivityCallback::doWork()
 {
+    Heap* heap = &m_vm->heap;
     if (!isEnabled())
         return;
     
-    ASSERT(vm.currentThreadIsHoldingAPILock());
-    Heap& heap = vm.heap;
-    if (heap.isDeferred()) {
+    JSLockHolder locker(m_vm);
+    if (heap->isDeferred()) {
         scheduleTimer(0_s);
         return;
     }
 
-    doCollection(vm);
+    doCollection();
 }
 
+#if USE(CF)
 void GCActivityCallback::scheduleTimer(Seconds newDelay)
 {
     if (newDelay * timerSlop > m_delay)
         return;
     Seconds delta = m_delay - newDelay;
     m_delay = newDelay;
-    if (auto timeUntilFire = this->timeUntilFire())
-        setTimeUntilFire(*timeUntilFire - delta);
-    else
-        setTimeUntilFire(delta);
+    CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta.seconds());
 }
 
-void GCActivityCallback::didAllocate(Heap& heap, size_t bytes)
+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)
 {
     // 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(heap);
-    Seconds newDelay = lastGCLength(heap) / gcTimeSlice(bytesExpectedToReclaim);
+    double bytesExpectedToReclaim = static_cast<double>(bytes) * deathRate();
+    Seconds newDelay = lastGCLength() / gcTimeSlice(bytesExpectedToReclaim);
     scheduleTimer(newDelay);
 }
 
 void GCActivityCallback::willCollect()
 {
-    cancel();
+    cancelTimer();
 }
 
 void GCActivityCallback::cancel()
 {
-    m_delay = s_decade;
     cancelTimer();
 }
 
index 9dfdd0f..4b40676 100644 (file)
@@ -48,22 +48,24 @@ public:
 
     GCActivityCallback(Heap*);
 
-    void doWork(VM&) override;
+    void doWork() override;
 
-    virtual void doCollection(VM&) = 0;
+    virtual void doCollection() = 0;
 
-    void didAllocate(Heap&, size_t);
-    void willCollect();
-    void cancel();
+    virtual void didAllocate(size_t);
+    virtual void willCollect();
+    virtual 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(Heap&) = 0;
+    virtual Seconds lastGCLength() = 0;
     virtual double gcTimeSlice(size_t bytes) = 0;
-    virtual double deathRate(Heap&) = 0;
+    virtual double deathRate() = 0;
 
     GCActivityCallback(VM* vm)
         : Base(vm)
@@ -75,6 +77,7 @@ protected:
     bool m_enabled;
 
 protected:
+    void cancelTimer();
     void scheduleTimer(Seconds);
 
 private:
index f84f7e6..c782fcb 100644 (file)
@@ -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(*this,
+        m_fullActivityCallback->didAllocate(
             m_sizeAfterLastCollect - m_sizeAfterLastFullCollect + m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
     }
     m_bytesAbandonedSinceLastFullCollect += abandonedBytes;
@@ -2194,7 +2194,7 @@ void Heap::notifyIncrementalSweeper()
             m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
     }
 
-    m_sweeper->startSweeping(*this);
+    m_sweeper->startSweeping();
 }
 
 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(*this, currentHeapSize - m_sizeAfterLastFullCollect);
+            m_fullActivityCallback->didAllocate(currentHeapSize - m_sizeAfterLastFullCollect);
         }
     }
 
@@ -2354,7 +2354,7 @@ void Heap::setGarbageCollectionTimerEnabled(bool enable)
 void Heap::didAllocate(size_t bytes)
 {
     if (m_edenActivityCallback)
-        m_edenActivityCallback->didAllocate(*this, m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
+        m_edenActivityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
     m_bytesAllocatedThisCycle += bytes;
     performIncrement(bytes);
 }
index 22d8393..e5e49dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC {
 
-static const Seconds sweepTimeSlice = 10_ms;
+static const Seconds sweepTimeSlice = 10_ms; // seconds
 static const double sweepTimeTotal = .10;
 static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal;
 
 void IncrementalSweeper::scheduleTimer()
 {
-    setTimeUntilFire(sweepTimeSlice * sweepTimeMultiplier);
+    Base::scheduleTimer(sweepTimeSlice * sweepTimeMultiplier);
 }
 
 IncrementalSweeper::IncrementalSweeper(Heap* heap)
@@ -49,14 +49,14 @@ IncrementalSweeper::IncrementalSweeper(Heap* heap)
 {
 }
 
-void IncrementalSweeper::doWork(VM& vm)
+void IncrementalSweeper::doWork()
 {
-    doSweep(vm, MonotonicTime::now());
+    doSweep(MonotonicTime::now());
 }
 
-void IncrementalSweeper::doSweep(VM& vm, MonotonicTime sweepBeginTime)
+void IncrementalSweeper::doSweep(MonotonicTime sweepBeginTime)
 {
-    while (sweepNextBlock(vm)) {
+    while (sweepNextBlock()) {
         Seconds elapsedTime = MonotonicTime::now() - sweepBeginTime;
         if (elapsedTime < sweepTimeSlice)
             continue;
@@ -72,9 +72,9 @@ void IncrementalSweeper::doSweep(VM& vm, MonotonicTime sweepBeginTime)
     cancelTimer();
 }
 
-bool IncrementalSweeper::sweepNextBlock(VM& vm)
+bool IncrementalSweeper::sweepNextBlock()
 {
-    vm.heap.stopIfNecessary();
+    m_vm->heap.stopIfNecessary();
 
     MarkedBlock::Handle* block = nullptr;
     
@@ -85,25 +85,26 @@ bool IncrementalSweeper::sweepNextBlock(VM& vm)
     }
     
     if (block) {
-        DeferGCForAWhile deferGC(vm.heap);
+        DeferGCForAWhile deferGC(m_vm->heap);
         block->sweep(nullptr);
-        vm.heap.objectSpace().freeOrShrinkBlock(block);
+        m_vm->heap.objectSpace().freeOrShrinkBlock(block);
         return true;
     }
 
-    return vm.heap.sweepNextLogicallyEmptyWeakBlock();
+    return m_vm->heap.sweepNextLogicallyEmptyWeakBlock();
 }
 
-void IncrementalSweeper::startSweeping(Heap& heap)
+void IncrementalSweeper::startSweeping()
 {
     scheduleTimer();
-    m_currentDirectory = heap.objectSpace().firstDirectory();
+    m_currentDirectory = m_vm->heap.objectSpace().firstDirectory();
 }
 
 void IncrementalSweeper::stopSweeping()
 {
     m_currentDirectory = nullptr;
-    cancelTimer();
+    if (m_vm)
+        cancelTimer();
 }
 
 } // namespace JSC
index 12646de..abd8e69 100644 (file)
@@ -37,15 +37,15 @@ public:
     using Base = JSRunLoopTimer;
     JS_EXPORT_PRIVATE explicit IncrementalSweeper(Heap*);
 
-    JS_EXPORT_PRIVATE void startSweeping(Heap&);
+    JS_EXPORT_PRIVATE void startSweeping();
     void freeFastMallocMemoryAfterSweeping() { m_shouldFreeFastMallocMemoryAfterSweeping = true; }
 
-    void doWork(VM&) override;
-    void stopSweeping();
+    JS_EXPORT_PRIVATE void doWork() override;
+    bool sweepNextBlock();
+    JS_EXPORT_PRIVATE void stopSweeping();
 
 private:
-    bool sweepNextBlock(VM&);
-    void doSweep(VM&, MonotonicTime startTime);
+    void doSweep(MonotonicTime startTime);
     void scheduleTimer();
     
     BlockDirectory* m_currentDirectory;
index 450d8d8..6239610 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 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::StopIfNecessaryTimer(VM* vm)
 {
 }
 
-void StopIfNecessaryTimer::doWork(VM& vm)
+void StopIfNecessaryTimer::doWork()
 {
     cancelTimer();
     WTF::storeStoreFence();
-    vm.heap.stopIfNecessary();
+    m_vm->heap.stopIfNecessary();
 }
 
 void StopIfNecessaryTimer::scheduleSoon()
@@ -48,7 +48,7 @@ void StopIfNecessaryTimer::scheduleSoon()
         WTF::loadLoadFence();
         return;
     }
-    setTimeUntilFire(0_s);
+    scheduleTimer(0_s);
 }
 
 } // namespace JSC
index 1f13373..e1836a1 100644 (file)
@@ -36,7 +36,7 @@ public:
     using Base = JSRunLoopTimer;
     explicit StopIfNecessaryTimer(VM*);
     
-    void doWork(VM&) override;
+    void doWork() override;
     
     void scheduleSoon();
 };
index a56e462..89edb68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #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,288 +46,107 @@ namespace JSC {
 
 const Seconds JSRunLoopTimer::s_decade { 60 * 60 * 24 * 365 * 10 };
 
-static inline JSRunLoopTimer::Manager::EpochTime epochTime(Seconds delay)
-{
-#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)
+void JSRunLoopTimer::timerDidFire()
 {
-    if (runLoop) {
-        CFRunLoopRemoveTimer(runLoop.get(), timer.get(), kCFRunLoopCommonModes);
-        CFRunLoopTimerInvalidate(timer.get());
-        runLoop.clear();
-        timer.clear();
+    JSLock* apiLock = m_apiLock.get();
+    if (!apiLock) {
+        // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed.
+        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());
+    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;
     }
-}
-#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::JavascriptTimer);
-    timer->setName("[JavaScriptCore] JSRunLoopTimer");
-#endif
-}
-
-void JSRunLoopTimer::Manager::timerDidFireCallback()
-{
-    timerDidFire();
-}
-#endif
 
-JSRunLoopTimer::Manager::PerVMData::~PerVMData()
-{
-#if USE(CF)
-    setRunLoop(nullptr, nullptr);
-#endif
+    doWork();
 }
 
-void JSRunLoopTimer::Manager::timerDidFire()
-{
-    Vector<Ref<JSRunLoopTimer>> timersToFire;
-
-    {
-        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 = entry.value;
-#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
-        }
-    }
-
-    for (auto& timer : timersToFire)
-        timer->timerDidFire();
-}
 
-JSRunLoopTimer::Manager& JSRunLoopTimer::Manager::shared()
-{
-    static Manager* manager;
-    static std::once_flag once;
-    std::call_once(once, [&] {
-        manager = new Manager;
-    });
-    return *manager;
-}
-
-void JSRunLoopTimer::Manager::registerVM(VM& vm)
-{
-    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::Manager::unregisterVM(VM& vm)
+JSRunLoopTimer::JSRunLoopTimer(VM* vm)
+    : m_vm(vm)
+    , m_apiLock(&vm->apiLock())
 {
-    auto locker = holdLock(m_lock);
-
-    auto iter = m_mapping.find({ vm.apiLock() });
-    RELEASE_ASSERT(iter != m_mapping.end());
-    m_mapping.remove(iter);
+    m_vm->registerRunLoopTimer(this);
 }
 
-void JSRunLoopTimer::Manager::scheduleTimer(JSRunLoopTimer& timer, Seconds delay)
+void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop)
 {
-    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 = iter->value;
-    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 (m_runLoop) {
+        CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
+        CFRunLoopTimerInvalidate(m_timer.get());
+        m_runLoop.clear();
+        m_timer.clear();
     }
 
-    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
+    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);
+    }
 }
 
-void JSRunLoopTimer::Manager::cancelTimer(JSRunLoopTimer& timer)
+JSRunLoopTimer::~JSRunLoopTimer()
 {
-    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 = 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
+    JSLock* apiLock = m_apiLock.get();
+    std::lock_guard<JSLock> lock(*apiLock);
+    m_vm->unregisterRunLoopTimer(this);
+    m_apiLock = nullptr;
 }
 
-std::optional<Seconds> JSRunLoopTimer::Manager::timeUntilFire(JSRunLoopTimer& timer)
+void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr)
 {
-    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) {
-            EpochTime nowEpochTime = epochTime(0_s);
-            return entry.second - nowEpochTime;
-        }
-    }
-
-    return std::nullopt;
+    static_cast<JSRunLoopTimer*>(contextPtr)->timerDidFire();
 }
 
-#if USE(CF)
-void JSRunLoopTimer::Manager::didChangeRunLoop(VM& vm, CFRunLoopRef newRunLoop)
+void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds)
 {
-    auto locker = holdLock(m_lock);
-    auto iter = m_mapping.find({ vm.apiLock() });
-    RELEASE_ASSERT(iter != m_mapping.end());
-
-    PerVMData& data = iter->value;
-    data.setRunLoop(this, newRunLoop);
+    CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + intervalInSeconds.seconds());
+    m_isScheduled = true;
+    auto locker = holdLock(m_timerCallbacksLock);
+    for (auto& task : m_timerSetCallbacks)
+        task->run();
 }
-#endif
 
-void JSRunLoopTimer::timerDidFire()
+void JSRunLoopTimer::cancelTimer()
 {
-    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);
+    CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds());
+    m_isScheduled = false;
 }
 
+#else
+
 JSRunLoopTimer::JSRunLoopTimer(VM* vm)
-    : m_apiLock(vm->apiLock())
+    : m_vm(vm)
+    , m_apiLock(&vm->apiLock())
+    , m_timer(RunLoop::current(), this, &JSRunLoopTimer::timerDidFireCallback)
 {
+#if USE(GLIB_EVENT_LOOP)
+    m_timer.setPriority(RunLoopSourcePriority::JavascriptTimer);
+    m_timer.setName("[JavaScriptCore] JSRunLoopTimer");
+#endif
+    m_timer.startOneShot(s_decade);
 }
 
 JSRunLoopTimer::~JSRunLoopTimer()
 {
 }
 
-std::optional<Seconds> JSRunLoopTimer::timeUntilFire()
+void JSRunLoopTimer::timerDidFireCallback()
 {
-    return Manager::shared().timeUntilFire(*this);
+    m_timer.startOneShot(s_decade);
+    timerDidFire();
 }
 
-void JSRunLoopTimer::setTimeUntilFire(Seconds intervalInSeconds)
+void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds)
 {
-    {
-        auto locker = holdLock(m_lock);
-        m_isScheduled = true;
-        Manager::shared().scheduleTimer(*this, intervalInSeconds);
-    }
+    m_timer.startOneShot(intervalInSeconds);
+    m_isScheduled = true;
 
     auto locker = holdLock(m_timerCallbacksLock);
     for (auto& task : m_timerSetCallbacks)
@@ -336,11 +155,12 @@ void JSRunLoopTimer::setTimeUntilFire(Seconds intervalInSeconds)
 
 void JSRunLoopTimer::cancelTimer()
 {
-    auto locker = holdLock(m_lock);
+    m_timer.startOneShot(s_decade);
     m_isScheduled = false;
-    Manager::shared().cancelTimer(*this);
 }
 
+#endif
+
 void JSRunLoopTimer::addTimerSetNotification(TimerNotificationCallback callback)
 {
     auto locker = holdLock(m_timerCallbacksLock);
index 6651672..06c5f17 100644 (file)
@@ -47,91 +47,54 @@ public:
     typedef void TimerNotificationType();
     using TimerNotificationCallback = RefPtr<WTF::SharedTask<TimerNotificationType>>;
 
-    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 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();
-
+    JSRunLoopTimer(VM*);
 #if USE(CF)
-            void setRunLoop(Manager*, CFRunLoopRef);
-            RetainPtr<CFRunLoopTimerRef> timer;
-            RetainPtr<CFRunLoopRef> runLoop;
-            CFRunLoopTimerContext context;
+    static void timerDidFireCallback(CFRunLoopTimerRef, void*);
 #else
-            RunLoop* runLoop;
-            std::unique_ptr<RunLoop::Timer<Manager>> timer;
+    void timerDidFireCallback();
 #endif
-            Vector<std::pair<Ref<JSRunLoopTimer>, EpochTime>> timers;
-        };
 
-        HashMap<Ref<JSLock>, PerVMData> m_mapping;
-    };
-
-    JSRunLoopTimer(VM*);
     JS_EXPORT_PRIVATE virtual ~JSRunLoopTimer();
-    virtual void doWork(VM&) = 0;
+    virtual void doWork() = 0;
 
-    void setTimeUntilFire(Seconds intervalInSeconds);
+    void scheduleTimer(Seconds intervalInSeconds);
     void cancelTimer();
     bool isScheduled() const { return m_isScheduled; }
 
     // Note: The only thing the timer notification callback cannot do is
-    // call setTimeUntilFire(). This will cause a deadlock. It would not
+    // call scheduleTimer(). 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);
 
-    JS_EXPORT_PRIVATE std::optional<Seconds> timeUntilFire();
+#if USE(CF)
+    JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef);
+#endif // USE(CF)
 
 protected:
+    VM* m_vm;
+
     static const Seconds s_decade;
-    Ref<JSLock> m_apiLock;
 
-private:
-    friend class Manager;
+    RefPtr<JSLock> m_apiLock;
+    bool m_isScheduled { false };
+#if USE(CF)
+    RetainPtr<CFRunLoopTimerRef> m_timer;
+    RetainPtr<CFRunLoopRef> m_runLoop;
 
-    void timerDidFire();
+    CFRunLoopTimerContext m_context;
 
-    HashSet<TimerNotificationCallback> m_timerSetCallbacks;
-    Lock m_timerCallbacksLock;
+    Lock m_shutdownMutex;
+#else
+    RunLoop::Timer<JSRunLoopTimer> m_timer;
+#endif
 
-    Lock m_lock;
-    bool m_isScheduled { false };
+    Lock m_timerCallbacksLock;
+    HashSet<TimerNotificationCallback> m_timerSetCallbacks;
+    
+private:
+    void timerDidFire();
 };
     
 } // namespace JSC
index 343ee2a..db851dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2017 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::PromiseDeferredTimer(VM& vm)
 {
 }
 
-void PromiseDeferredTimer::doWork(VM& vm)
+void PromiseDeferredTimer::doWork()
 {
-    ASSERT(vm.currentThreadIsHoldingAPILock());
+    ASSERT(m_vm->currentThreadIsHoldingAPILock());
     m_taskLock.lock();
     cancelTimer();
     if (!m_runTasks) {
@@ -66,7 +66,7 @@ void PromiseDeferredTimer::doWork(VM& vm)
             m_taskLock.unlock(); 
 
             task();
-            vm.drainMicrotasks();
+            m_vm->drainMicrotasks();
 
             m_taskLock.lock();
             m_currentlyRunningTask = false;
@@ -75,7 +75,7 @@ void PromiseDeferredTimer::doWork(VM& vm)
 
     if (m_pendingPromises.isEmpty() && m_shouldStopRunLoopWhenAllPromisesFinish) {
 #if USE(CF)
-        CFRunLoopStop(vm.runLoop());
+        CFRunLoopStop(m_runLoop.get());
 #else
         RunLoop::current().stop();
 #endif
@@ -86,30 +86,29 @@ void PromiseDeferredTimer::doWork(VM& vm)
 
 void PromiseDeferredTimer::runRunLoop()
 {
-    ASSERT(!m_apiLock->vm()->currentThreadIsHoldingAPILock());
+    ASSERT(!m_vm->currentThreadIsHoldingAPILock());
 #if USE(CF)
-    ASSERT(CFRunLoopGetCurrent() == m_apiLock->vm()->runLoop());
+    ASSERT(CFRunLoopGetCurrent() == m_runLoop.get());
 #endif
     m_shouldStopRunLoopWhenAllPromisesFinish = true;
-    if (m_pendingPromises.size()) {
+    if (m_pendingPromises.size())
 #if USE(CF)
         CFRunLoopRun();
 #else
         RunLoop::run();
 #endif
-    }
 }
 
-void PromiseDeferredTimer::addPendingPromise(VM& vm, JSPromiseDeferred* ticket, Vector<Strong<JSCell>>&& dependencies)
+void PromiseDeferredTimer::addPendingPromise(JSPromiseDeferred* ticket, Vector<Strong<JSCell>>&& dependencies)
 {
-    ASSERT(vm.currentThreadIsHoldingAPILock());
+    ASSERT(m_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>(vm, ticket));
+        dependencies.append(Strong<JSCell>(*m_vm, ticket));
         result.iterator->value = WTFMove(dependencies);
     } else {
         dataLogLnIf(PromiseDeferredTimerInternal::verbose, "Adding new dependencies for promise: ", RawPointer(ticket));
@@ -123,13 +122,13 @@ void PromiseDeferredTimer::addPendingPromise(VM& vm, JSPromiseDeferred* ticket,
 
 bool PromiseDeferredTimer::hasPendingPromise(JSPromiseDeferred* ticket)
 {
-    ASSERT(ticket->vm()->currentThreadIsHoldingAPILock());
+    ASSERT(m_vm->currentThreadIsHoldingAPILock());
     return m_pendingPromises.contains(ticket);
 }
 
 bool PromiseDeferredTimer::hasDependancyInPendingPromise(JSPromiseDeferred* ticket, JSCell* dependency)
 {
-    ASSERT(ticket->vm()->currentThreadIsHoldingAPILock());
+    ASSERT(m_vm->currentThreadIsHoldingAPILock());
     ASSERT(m_pendingPromises.contains(ticket));
 
     auto result = m_pendingPromises.get(ticket);
@@ -138,7 +137,7 @@ bool PromiseDeferredTimer::hasDependancyInPendingPromise(JSPromiseDeferred* tick
 
 bool PromiseDeferredTimer::cancelPendingPromise(JSPromiseDeferred* ticket)
 {
-    ASSERT(ticket->vm()->currentThreadIsHoldingAPILock());
+    ASSERT(m_vm->currentThreadIsHoldingAPILock());
     bool result = m_pendingPromises.remove(ticket);
 
     if (result)
@@ -152,7 +151,7 @@ void PromiseDeferredTimer::scheduleWorkSoon(JSPromiseDeferred* ticket, Task&& ta
     LockHolder locker(m_taskLock);
     m_tasks.append(std::make_tuple(ticket, WTFMove(task)));
     if (!isScheduled() && !m_currentlyRunningTask)
-        setTimeUntilFire(0_s);
+        scheduleTimer(0_s);
 }
 
 } // namespace JSC
index a52eb64..615b087 100644 (file)
@@ -44,9 +44,9 @@ public:
 
     PromiseDeferredTimer(VM&);
 
-    void doWork(VM&) override;
+    void doWork() override;
 
-    void addPendingPromise(VM&, JSPromiseDeferred*, Vector<Strong<JSCell>>&& dependencies);
+    void addPendingPromise(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 b9a9036..f10ffdb 100644 (file)
@@ -381,8 +381,6 @@ 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);
@@ -583,8 +581,6 @@ VM::~VM()
     ASSERT(currentThreadIsHoldingAPILock());
     m_apiLock->willDestroyVM(this);
     heap.lastChanceToFinalize();
-
-    JSRunLoopTimer::Manager::shared().unregisterVM(*this);
     
     delete interpreter;
 #ifndef NDEBUG
@@ -1213,11 +1209,27 @@ void VM::verifyExceptionCheckNeedIsSatisfied(unsigned recursionDepth, ExceptionE
 #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;
-    JSRunLoopTimer::Manager::shared().didChangeRunLoop(*this, runLoop);
+    for (auto timer : m_runLoopTimers)
+        timer->setRunLoop(runLoop);
 }
 #endif // USE(CF)
 
index 8d6a8f8..f1b9101 100644 (file)
@@ -302,6 +302,7 @@ 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
 
@@ -881,6 +882,8 @@ 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 96d4c14..0866aaf 100644 (file)
@@ -91,7 +91,7 @@ static void webAssemblyModuleValidateAsyncInternal(ExecState* exec, JSPromiseDef
     Vector<Strong<JSCell>> dependencies;
     dependencies.append(Strong<JSCell>(vm, globalObject));
 
-    vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies));
+    vm.promiseDeferredTimer->addPendingPromise(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, ExecState* exec, JSPromiseDeferred* promise, JSW
     // The instance keeps the module alive.
     dependencies.append(Strong<JSCell>(vm, instance));
     dependencies.append(Strong<JSCell>(vm, importObject));
-    vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies));
+    vm.promiseDeferredTimer->addPendingPromise(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, ExecState* exec, JSPromiseDeferred* pr
     Vector<Strong<JSCell>> dependencies;
     dependencies.append(Strong<JSCell>(vm, importObject));
     dependencies.append(Strong<JSCell>(vm, moduleKeyCell));
-    vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies));
+    vm.promiseDeferredTimer->addPendingPromise(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 webAssemblyModuleInstantinateAsyncInternal(ExecState* exec, JSPromis
     Vector<Strong<JSCell>> dependencies;
     dependencies.append(Strong<JSCell>(vm, importObject));
     dependencies.append(Strong<JSCell>(vm, globalObject));
-    vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies));
+    vm.promiseDeferredTimer->addPendingPromise(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 webAssemblyCompileStreamingInternal(ExecState* exec
 
     Vector<Strong<JSCell>> dependencies;
     dependencies.append(Strong<JSCell>(vm, globalObject));
-    vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies));
+    vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
 
     if (globalObject->globalObjectMethodTable()->compileStreaming)
         globalObject->globalObjectMethodTable()->compileStreaming(globalObject, exec, promise, exec->argument(0));
@@ -347,7 +347,7 @@ EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateStreamingInternal(ExecState*
                 Vector<Strong<JSCell>> dependencies;
                 dependencies.append(Strong<JSCell>(vm, globalObject));
                 dependencies.append(Strong<JSCell>(vm, importObject));
-                vm.promiseDeferredTimer->addPendingPromise(vm, promise, WTFMove(dependencies));
+                vm.promiseDeferredTimer->addPendingPromise(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 cc7d46d..603644c 100644 (file)
@@ -1,3 +1,18 @@
+2018-08-21  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r235107.
+        https://bugs.webkit.org/show_bug.cgi?id=188832
+
+        "It revealed bugs in Blob code as well as regressed JS
+        performance tests" (Requested by saamyjoon on #webkit).
+
+        Reverted changeset:
+
+        "JSRunLoopTimer may run part of a member function after it's
+        destroyed"
+        https://bugs.webkit.org/show_bug.cgi?id=188426
+        https://trac.webkit.org/changeset/235107
+
 2018-08-21  Megan Gardner  <megan_gardner@apple.com>
 
         Use VisiblePosition to calculate selection ranges
index fe5af8d..7e48224 100644 (file)
@@ -248,9 +248,8 @@ void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& dat
 
     data.totalExternalSize = currentGCOwnedExternal;
 
-    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()));
+    data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime();
+    data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime();
 }
 
 }
index dcafb6f..70f0d69 100644 (file)
@@ -1,6 +1,5 @@
 /*
  * 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
@@ -169,9 +168,8 @@ void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& dat
 
     data.totalExternalSize = currentGCOwnedExternal;
 
-    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()));
+    data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime();
+    data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime();
 }
 
 } // namespace WebCore