diff modules/javafx.web/src/main/native/Source/WebCore/platform/Timer.cpp @ 11208:db2c977a840b

8220147: Cherry pick GTK WebKit 2.22.7 changes Reviewed-by: mbilla, kcr
author arajkumar
date Fri, 08 Mar 2019 14:03:47 +0530
parents ab4db0272524
children a1fb556cdd7d
line wrap: on
line diff
--- a/modules/javafx.web/src/main/native/Source/WebCore/platform/Timer.cpp	Fri Mar 01 13:54:26 2019 +0530
+++ b/modules/javafx.web/src/main/native/Source/WebCore/platform/Timer.cpp	Fri Mar 08 14:03:47 2019 +0530
@@ -50,69 +50,111 @@
 // Then we set a single shared system timer to fire at that time.
 //
 // When a timer's "next fire time" changes, we need to move it around in the priority queue.
-static Vector<TimerBase*>& threadGlobalTimerHeap()
+#if !ASSERT_DISABLED
+static ThreadTimerHeap& threadGlobalTimerHeap()
 {
     return threadGlobalData().threadTimers().timerHeap();
 }
+#endif
+
+inline ThreadTimerHeapItem::ThreadTimerHeapItem(TimerBase& timer, MonotonicTime time, unsigned insertionOrder)
+    : time(time)
+    , insertionOrder(insertionOrder)
+    , m_threadTimers(threadGlobalData().threadTimers())
+    , m_timer(&timer)
+{
+    ASSERT(m_timer);
+}
+
+inline RefPtr<ThreadTimerHeapItem> ThreadTimerHeapItem::create(TimerBase& timer, MonotonicTime time, unsigned insertionOrder)
+{
+    return adoptRef(*new ThreadTimerHeapItem { timer, time, insertionOrder });
+}
+
 // ----------------
 
 class TimerHeapPointer {
 public:
-    TimerHeapPointer(TimerBase** pointer) : m_pointer(pointer) { }
+    TimerHeapPointer(RefPtr<ThreadTimerHeapItem>* pointer)
+        : m_pointer(pointer)
+    { }
+
     TimerHeapReference operator*() const;
-    TimerBase* operator->() const { return *m_pointer; }
+    RefPtr<ThreadTimerHeapItem>& operator->() const { return *m_pointer; }
 private:
-    TimerBase** m_pointer;
+    RefPtr<ThreadTimerHeapItem>* m_pointer;
 };
 
 class TimerHeapReference {
 public:
-    TimerHeapReference(TimerBase*& reference) : m_reference(reference) { }
-    operator TimerBase*() const { return m_reference; }
+    TimerHeapReference(RefPtr<ThreadTimerHeapItem>& reference)
+        : m_reference(reference)
+    { }
+
+    TimerHeapReference(const TimerHeapReference& other)
+        : m_reference(other.m_reference)
+    { }
+
+    operator RefPtr<ThreadTimerHeapItem>&() const { return m_reference; }
     TimerHeapPointer operator&() const { return &m_reference; }
-    TimerHeapReference& operator=(TimerBase*);
-    TimerHeapReference& operator=(TimerHeapReference);
+    TimerHeapReference& operator=(TimerHeapReference&&);
+    TimerHeapReference& operator=(RefPtr<ThreadTimerHeapItem>&&);
+
+    void swap(TimerHeapReference& other);
+
+    void updateHeapIndex();
+
 private:
-    TimerBase*& m_reference;
+    RefPtr<ThreadTimerHeapItem>& m_reference;
+
+    friend void swap(TimerHeapReference a, TimerHeapReference b);
 };
 
 inline TimerHeapReference TimerHeapPointer::operator*() const
 {
-    return *m_pointer;
+    return TimerHeapReference { *m_pointer };
 }
 
-inline TimerHeapReference& TimerHeapReference::operator=(TimerBase* timer)
+inline TimerHeapReference& TimerHeapReference::operator=(TimerHeapReference&& other)
 {
-    m_reference = timer;
-    Vector<TimerBase*>& heap = timer->timerHeap();
-    if (&m_reference >= heap.data() && &m_reference < heap.data() + heap.size())
-        timer->m_heapIndex = &m_reference - heap.data();
+    m_reference = WTFMove(other.m_reference);
+    updateHeapIndex();
     return *this;
 }
 
-inline TimerHeapReference& TimerHeapReference::operator=(TimerHeapReference b)
+inline TimerHeapReference& TimerHeapReference::operator=(RefPtr<ThreadTimerHeapItem>&& item)
 {
-    TimerBase* timer = b;
-    return *this = timer;
+    m_reference = WTFMove(item);
+    updateHeapIndex();
+    return *this;
+}
+
+inline void TimerHeapReference::swap(TimerHeapReference& other)
+{
+    m_reference.swap(other.m_reference);
+    updateHeapIndex();
+    other.updateHeapIndex();
+}
+
+inline void TimerHeapReference::updateHeapIndex()
+{
+    auto& heap = m_reference->timerHeap();
+    if (&m_reference >= heap.data() && &m_reference < heap.data() + heap.size())
+        m_reference->setHeapIndex(&m_reference - heap.data());
 }
 
 inline void swap(TimerHeapReference a, TimerHeapReference b)
 {
-    TimerBase* timerA = a;
-    TimerBase* timerB = b;
-
-    // Invoke the assignment operator, since that takes care of updating m_heapIndex.
-    a = timerB;
-    b = timerA;
+    a.swap(b);
 }
 
 // ----------------
 
 // Class to represent iterators in the heap when calling the standard library heap algorithms.
 // Uses a custom pointer and reference type that update indices for pointers in the heap.
-class TimerHeapIterator : public std::iterator<std::random_access_iterator_tag, TimerBase*, ptrdiff_t, TimerHeapPointer, TimerHeapReference> {
+class TimerHeapIterator : public std::iterator<std::random_access_iterator_tag, RefPtr<ThreadTimerHeapItem>, ptrdiff_t, TimerHeapPointer, TimerHeapReference> {
 public:
-    explicit TimerHeapIterator(TimerBase** pointer) : m_pointer(pointer) { checkConsistency(); }
+    explicit TimerHeapIterator(RefPtr<ThreadTimerHeapItem>* pointer) : m_pointer(pointer) { checkConsistency(); }
 
     TimerHeapIterator& operator++() { checkConsistency(); ++m_pointer; checkConsistency(); return *this; }
     TimerHeapIterator operator++(int) { checkConsistency(1); return TimerHeapIterator(m_pointer++); }
@@ -125,7 +167,7 @@
 
     TimerHeapReference operator*() const { return TimerHeapReference(*m_pointer); }
     TimerHeapReference operator[](ptrdiff_t i) const { return TimerHeapReference(m_pointer[i]); }
-    TimerBase* operator->() const { return *m_pointer; }
+    RefPtr<ThreadTimerHeapItem>& operator->() const { return *m_pointer; }
 
 private:
     void checkConsistency(ptrdiff_t offset = 0) const
@@ -149,7 +191,7 @@
     friend TimerHeapIterator operator-(TimerHeapIterator, size_t);
     friend ptrdiff_t operator-(TimerHeapIterator, TimerHeapIterator);
 
-    TimerBase** m_pointer;
+    RefPtr<ThreadTimerHeapItem>* m_pointer;
 };
 
 inline bool operator==(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer == b.m_pointer; }
@@ -169,23 +211,34 @@
 
 class TimerHeapLessThanFunction {
 public:
-    bool operator()(const TimerBase*, const TimerBase*) const;
-};
+    static bool compare(const TimerBase& a, const RefPtr<ThreadTimerHeapItem>& b)
+    {
+        return compare(a.m_heapItem->time, a.m_heapItem->insertionOrder, b->time, b->insertionOrder);
+    }
 
-inline bool TimerHeapLessThanFunction::operator()(const TimerBase* a, const TimerBase* b) const
-{
+    static bool compare(const RefPtr<ThreadTimerHeapItem>& a, const TimerBase& b)
+    {
+        return compare(a->time, a->insertionOrder, b.m_heapItem->time, b.m_heapItem->insertionOrder);
+    }
+
+    bool operator()(const RefPtr<ThreadTimerHeapItem>& a, const RefPtr<ThreadTimerHeapItem>& b) const
+    {
+        return compare(a->time, a->insertionOrder, b->time, b->insertionOrder);
+    }
+
+private:
+    static bool compare(MonotonicTime aTime, unsigned aOrder, MonotonicTime bTime, unsigned bOrder)
+    {
     // The comparisons below are "backwards" because the heap puts the largest
     // element first and we want the lowest time to be the first one in the heap.
-    MonotonicTime aFireTime = a->m_nextFireTime;
-    MonotonicTime bFireTime = b->m_nextFireTime;
-    if (bFireTime != aFireTime)
-        return bFireTime < aFireTime;
-
+        if (bTime != aTime)
+            return bTime < aTime;
     // We need to look at the difference of the insertion orders instead of comparing the two
     // outright in case of overflow.
-    unsigned difference = a->m_heapInsertionOrder - b->m_heapInsertionOrder;
+        unsigned difference = aOrder - bOrder;
     return difference < std::numeric_limits<unsigned>::max() / 2;
-}
+    }
+};
 
 // ----------------
 
@@ -201,8 +254,7 @@
 }
 
 TimerBase::TimerBase()
-    : m_heapIndex(-1)
-    , m_wasDeleted(false)
+    : m_wasDeleted(false)
 {
 }
 
@@ -210,8 +262,13 @@
 {
     ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
     RELEASE_ASSERT(canAccessThreadLocalDataForThread(m_thread.get()) || shouldSuppressThreadSafetyCheck());
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(canAccessThreadLocalDataForThread(m_thread.get()));
     stop();
     ASSERT(!inHeap());
+    if (m_heapItem) {
+        m_heapItem->clearTimer();
+        m_heapItem = nullptr;
+    }
     m_wasDeleted = true;
 }
 
@@ -230,7 +287,7 @@
     m_repeatInterval = 0_s;
     setNextFireTime(MonotonicTime { });
 
-    ASSERT(!static_cast<bool>(m_nextFireTime));
+    ASSERT(!static_cast<bool>(nextFireTime()));
     ASSERT(m_repeatInterval == 0_s);
     ASSERT(!inHeap());
 }
@@ -238,57 +295,66 @@
 Seconds TimerBase::nextFireInterval() const
 {
     ASSERT(isActive());
+    ASSERT(m_heapItem);
     MonotonicTime current = MonotonicTime::now();
-    if (m_nextFireTime < current)
+    auto fireTime = nextFireTime();
+    if (fireTime < current)
         return 0_s;
-    return m_nextFireTime - current;
+    return fireTime - current;
 }
 
 inline void TimerBase::checkHeapIndex() const
 {
-    ASSERT(timerHeap() == threadGlobalTimerHeap());
-    ASSERT(!timerHeap().isEmpty());
-    ASSERT(m_heapIndex >= 0);
-    ASSERT(m_heapIndex < static_cast<int>(timerHeap().size()));
-    ASSERT(timerHeap()[m_heapIndex] == this);
+#if !ASSERT_DISABLED
+    ASSERT(m_heapItem);
+    auto& heap = m_heapItem->timerHeap();
+    ASSERT(&heap == &threadGlobalTimerHeap());
+    ASSERT(!heap.isEmpty());
+    ASSERT(m_heapItem->isInHeap());
+    ASSERT(m_heapItem->heapIndex() < m_heapItem->timerHeap().size());
+    ASSERT(heap[m_heapItem->heapIndex()] == m_heapItem);
+    for (unsigned i = 0, size = heap.size(); i < size; i++)
+        ASSERT(heap[i]->heapIndex() == i);
+#endif
 }
 
 inline void TimerBase::checkConsistency() const
 {
     // Timers should be in the heap if and only if they have a non-zero next fire time.
-    ASSERT(inHeap() == static_cast<bool>(m_nextFireTime));
+    ASSERT(inHeap() == static_cast<bool>(nextFireTime()));
     if (inHeap())
         checkHeapIndex();
 }
 
 void TimerBase::heapDecreaseKey()
 {
-    ASSERT(static_cast<bool>(m_nextFireTime));
+    ASSERT(static_cast<bool>(nextFireTime()));
+    ASSERT(m_heapItem);
     checkHeapIndex();
-    TimerBase** heapData = timerHeap().data();
-    push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapIndex + 1), TimerHeapLessThanFunction());
+    auto* heapData = m_heapItem->timerHeap().data();
+    push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapItem->heapIndex() + 1), TimerHeapLessThanFunction());
     checkHeapIndex();
 }
 
 inline void TimerBase::heapDelete()
 {
-    ASSERT(!static_cast<bool>(m_nextFireTime));
+    ASSERT(!static_cast<bool>(nextFireTime()));
     heapPop();
-    timerHeap().removeLast();
-    m_heapIndex = -1;
+    m_heapItem->timerHeap().removeLast();
+    m_heapItem->setNotInHeap();
 }
 
 void TimerBase::heapDeleteMin()
 {
-    ASSERT(!static_cast<bool>(m_nextFireTime));
+    ASSERT(!static_cast<bool>(nextFireTime()));
     heapPopMin();
-    timerHeap().removeLast();
-    m_heapIndex = -1;
+    m_heapItem->timerHeap().removeLast();
+    m_heapItem->setNotInHeap();
 }
 
 inline void TimerBase::heapIncreaseKey()
 {
-    ASSERT(static_cast<bool>(m_nextFireTime));
+    ASSERT(static_cast<bool>(nextFireTime()));
     heapPop();
     heapDecreaseKey();
 }
@@ -296,81 +362,105 @@
 inline void TimerBase::heapInsert()
 {
     ASSERT(!inHeap());
-    timerHeap().append(this);
-    m_heapIndex = timerHeap().size() - 1;
+    ASSERT(m_heapItem);
+    auto& heap = m_heapItem->timerHeap();
+    heap.append(m_heapItem.copyRef());
+    m_heapItem->setHeapIndex(heap.size() - 1);
     heapDecreaseKey();
 }
 
 inline void TimerBase::heapPop()
 {
+    ASSERT(m_heapItem);
     // Temporarily force this timer to have the minimum key so we can pop it.
-    MonotonicTime fireTime = m_nextFireTime;
-    m_nextFireTime = -MonotonicTime::infinity();
+    MonotonicTime fireTime = m_heapItem->time;
+    m_heapItem->time = -MonotonicTime::infinity();
     heapDecreaseKey();
     heapPopMin();
-    m_nextFireTime = fireTime;
+    m_heapItem->time = fireTime;
 }
 
 void TimerBase::heapPopMin()
 {
-    ASSERT(this == timerHeap().first());
+    ASSERT(m_heapItem == m_heapItem->timerHeap().first());
     checkHeapIndex();
-    Vector<TimerBase*>& heap = timerHeap();
-    TimerBase** heapData = heap.data();
+    auto& heap = m_heapItem->timerHeap();
+    auto* heapData = heap.data();
     pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
     checkHeapIndex();
-    ASSERT(this == timerHeap().last());
+    ASSERT(m_heapItem == m_heapItem->timerHeap().last());
 }
 
-static inline bool parentHeapPropertyHolds(const TimerBase* current, const Vector<TimerBase*>& heap, unsigned currentIndex)
+void TimerBase::heapDeleteNullMin(ThreadTimerHeap& heap)
+{
+    RELEASE_ASSERT(!heap.first()->hasTimer());
+    heap.first()->time = -MonotonicTime::infinity();
+    auto* heapData = heap.data();
+    pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
+    heap.removeLast();
+}
+
+static inline bool parentHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned currentIndex)
 {
     if (!currentIndex)
         return true;
     unsigned parentIndex = (currentIndex - 1) / 2;
-    TimerHeapLessThanFunction compareHeapPosition;
-    return compareHeapPosition(current, heap[parentIndex]);
+    return TimerHeapLessThanFunction::compare(*current, heap[parentIndex]);
 }
 
-static inline bool childHeapPropertyHolds(const TimerBase* current, const Vector<TimerBase*>& heap, unsigned childIndex)
+static inline bool childHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned childIndex)
 {
     if (childIndex >= heap.size())
         return true;
-    TimerHeapLessThanFunction compareHeapPosition;
-    return compareHeapPosition(heap[childIndex], current);
+    return TimerHeapLessThanFunction::compare(heap[childIndex], *current);
 }
 
 bool TimerBase::hasValidHeapPosition() const
 {
-    ASSERT(m_nextFireTime);
+    ASSERT(nextFireTime());
+    ASSERT(m_heapItem);
     if (!inHeap())
         return false;
     // Check if the heap property still holds with the new fire time. If it does we don't need to do anything.
     // This assumes that the STL heap is a standard binary heap. In an unlikely event it is not, the assertions
     // in updateHeapIfNeeded() will get hit.
-    const Vector<TimerBase*>& heap = timerHeap();
-    if (!parentHeapPropertyHolds(this, heap, m_heapIndex))
+    const auto& heap = m_heapItem->timerHeap();
+    unsigned heapIndex = m_heapItem->heapIndex();
+    if (!parentHeapPropertyHolds(this, heap, heapIndex))
         return false;
-    unsigned childIndex1 = 2 * m_heapIndex + 1;
+    unsigned childIndex1 = 2 * heapIndex + 1;
     unsigned childIndex2 = childIndex1 + 1;
     return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyHolds(this, heap, childIndex2);
 }
 
 void TimerBase::updateHeapIfNeeded(MonotonicTime oldTime)
 {
-    if (m_nextFireTime && hasValidHeapPosition())
+    auto fireTime = nextFireTime();
+    if (fireTime && hasValidHeapPosition())
         return;
-#ifndef NDEBUG
-    int oldHeapIndex = m_heapIndex;
+
+#if !ASSERT_DISABLED
+    Optional<unsigned> oldHeapIndex;
+    if (m_heapItem->isInHeap())
+        oldHeapIndex = m_heapItem->heapIndex();
 #endif
+
     if (!oldTime)
         heapInsert();
-    else if (!m_nextFireTime)
+    else if (!fireTime)
         heapDelete();
-    else if (m_nextFireTime < oldTime)
+    else if (fireTime < oldTime)
         heapDecreaseKey();
     else
         heapIncreaseKey();
-    ASSERT(m_heapIndex != oldHeapIndex);
+
+#if !ASSERT_DISABLED
+    Optional<unsigned> newHeapIndex;
+    if (m_heapItem->isInHeap())
+        newHeapIndex = m_heapItem->heapIndex();
+    ASSERT(newHeapIndex != oldHeapIndex);
+#endif
+
     ASSERT(!inHeap() || hasValidHeapPosition());
 }
 
@@ -383,12 +473,8 @@
     if (m_unalignedNextFireTime != newTime)
         m_unalignedNextFireTime = newTime;
 
-    // Accessing thread global data is slow. Cache the heap pointer.
-    if (!m_cachedThreadGlobalTimerHeap)
-        m_cachedThreadGlobalTimerHeap = &threadGlobalTimerHeap();
-
     // Keep heap valid while changing the next-fire time.
-    MonotonicTime oldTime = m_nextFireTime;
+    MonotonicTime oldTime = nextFireTime();
     // Don't realign zero-delay timers.
     if (newTime) {
         if (auto newAlignedTime = alignedFireTime(newTime))
@@ -396,16 +482,20 @@
     }
 
     if (oldTime != newTime) {
-        m_nextFireTime = newTime;
         // FIXME: This should be part of ThreadTimers, or another per-thread structure.
         static std::atomic<unsigned> currentHeapInsertionOrder;
-        m_heapInsertionOrder = currentHeapInsertionOrder++;
+        auto newOrder = currentHeapInsertionOrder++;
 
-        bool wasFirstTimerInHeap = m_heapIndex == 0;
+        if (!m_heapItem)
+            m_heapItem = ThreadTimerHeapItem::create(*this, newTime, 0);
+        m_heapItem->time = newTime;
+        m_heapItem->insertionOrder = newOrder;
+
+        bool wasFirstTimerInHeap = m_heapItem->isFirstInHeap();
 
         updateHeapIfNeeded(oldTime);
 
-        bool isFirstTimerInHeap = m_heapIndex == 0;
+        bool isFirstTimerInHeap = m_heapItem->isFirstInHeap();
 
         if (wasFirstTimerInHeap || isFirstTimerInHeap)
             threadGlobalData().threadTimers().updateSharedTimer();