comparison 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
comparison
equal deleted inserted replaced
4:7b8ca92de7aa 5:f57615a91c3a
48 // Timers are stored in a heap data structure, used to implement a priority queue. 48 // Timers are stored in a heap data structure, used to implement a priority queue.
49 // This allows us to efficiently determine which timer needs to fire the soonest. 49 // This allows us to efficiently determine which timer needs to fire the soonest.
50 // Then we set a single shared system timer to fire at that time. 50 // Then we set a single shared system timer to fire at that time.
51 // 51 //
52 // When a timer's "next fire time" changes, we need to move it around in the priority queue. 52 // When a timer's "next fire time" changes, we need to move it around in the priority queue.
53 static Vector<TimerBase*>& threadGlobalTimerHeap() 53 #if !ASSERT_DISABLED
54 static ThreadTimerHeap& threadGlobalTimerHeap()
54 { 55 {
55 return threadGlobalData().threadTimers().timerHeap(); 56 return threadGlobalData().threadTimers().timerHeap();
56 } 57 }
58 #endif
59
60 inline ThreadTimerHeapItem::ThreadTimerHeapItem(TimerBase& timer, MonotonicTime time, unsigned insertionOrder)
61 : time(time)
62 , insertionOrder(insertionOrder)
63 , m_threadTimers(threadGlobalData().threadTimers())
64 , m_timer(&timer)
65 {
66 ASSERT(m_timer);
67 }
68
69 inline RefPtr<ThreadTimerHeapItem> ThreadTimerHeapItem::create(TimerBase& timer, MonotonicTime time, unsigned insertionOrder)
70 {
71 return adoptRef(*new ThreadTimerHeapItem { timer, time, insertionOrder });
72 }
73
57 // ---------------- 74 // ----------------
58 75
59 class TimerHeapPointer { 76 class TimerHeapPointer {
60 public: 77 public:
61 TimerHeapPointer(TimerBase** pointer) : m_pointer(pointer) { } 78 TimerHeapPointer(RefPtr<ThreadTimerHeapItem>* pointer)
79 : m_pointer(pointer)
80 { }
81
62 TimerHeapReference operator*() const; 82 TimerHeapReference operator*() const;
63 TimerBase* operator->() const { return *m_pointer; } 83 RefPtr<ThreadTimerHeapItem>& operator->() const { return *m_pointer; }
64 private: 84 private:
65 TimerBase** m_pointer; 85 RefPtr<ThreadTimerHeapItem>* m_pointer;
66 }; 86 };
67 87
68 class TimerHeapReference { 88 class TimerHeapReference {
69 public: 89 public:
70 TimerHeapReference(TimerBase*& reference) : m_reference(reference) { } 90 TimerHeapReference(RefPtr<ThreadTimerHeapItem>& reference)
71 operator TimerBase*() const { return m_reference; } 91 : m_reference(reference)
92 { }
93
94 TimerHeapReference(const TimerHeapReference& other)
95 : m_reference(other.m_reference)
96 { }
97
98 operator RefPtr<ThreadTimerHeapItem>&() const { return m_reference; }
72 TimerHeapPointer operator&() const { return &m_reference; } 99 TimerHeapPointer operator&() const { return &m_reference; }
73 TimerHeapReference& operator=(TimerBase*); 100 TimerHeapReference& operator=(TimerHeapReference&&);
74 TimerHeapReference& operator=(TimerHeapReference); 101 TimerHeapReference& operator=(RefPtr<ThreadTimerHeapItem>&&);
102
103 void swap(TimerHeapReference& other);
104
105 void updateHeapIndex();
106
75 private: 107 private:
76 TimerBase*& m_reference; 108 RefPtr<ThreadTimerHeapItem>& m_reference;
109
110 friend void swap(TimerHeapReference a, TimerHeapReference b);
77 }; 111 };
78 112
79 inline TimerHeapReference TimerHeapPointer::operator*() const 113 inline TimerHeapReference TimerHeapPointer::operator*() const
80 { 114 {
81 return *m_pointer; 115 return TimerHeapReference { *m_pointer };
82 } 116 }
83 117
84 inline TimerHeapReference& TimerHeapReference::operator=(TimerBase* timer) 118 inline TimerHeapReference& TimerHeapReference::operator=(TimerHeapReference&& other)
85 { 119 {
86 m_reference = timer; 120 m_reference = WTFMove(other.m_reference);
87 Vector<TimerBase*>& heap = timer->timerHeap(); 121 updateHeapIndex();
122 return *this;
123 }
124
125 inline TimerHeapReference& TimerHeapReference::operator=(RefPtr<ThreadTimerHeapItem>&& item)
126 {
127 m_reference = WTFMove(item);
128 updateHeapIndex();
129 return *this;
130 }
131
132 inline void TimerHeapReference::swap(TimerHeapReference& other)
133 {
134 m_reference.swap(other.m_reference);
135 updateHeapIndex();
136 other.updateHeapIndex();
137 }
138
139 inline void TimerHeapReference::updateHeapIndex()
140 {
141 auto& heap = m_reference->timerHeap();
88 if (&m_reference >= heap.data() && &m_reference < heap.data() + heap.size()) 142 if (&m_reference >= heap.data() && &m_reference < heap.data() + heap.size())
89 timer->m_heapIndex = &m_reference - heap.data(); 143 m_reference->setHeapIndex(&m_reference - heap.data());
90 return *this;
91 }
92
93 inline TimerHeapReference& TimerHeapReference::operator=(TimerHeapReference b)
94 {
95 TimerBase* timer = b;
96 return *this = timer;
97 } 144 }
98 145
99 inline void swap(TimerHeapReference a, TimerHeapReference b) 146 inline void swap(TimerHeapReference a, TimerHeapReference b)
100 { 147 {
101 TimerBase* timerA = a; 148 a.swap(b);
102 TimerBase* timerB = b;
103
104 // Invoke the assignment operator, since that takes care of updating m_heapIndex.
105 a = timerB;
106 b = timerA;
107 } 149 }
108 150
109 // ---------------- 151 // ----------------
110 152
111 // Class to represent iterators in the heap when calling the standard library heap algorithms. 153 // Class to represent iterators in the heap when calling the standard library heap algorithms.
112 // Uses a custom pointer and reference type that update indices for pointers in the heap. 154 // Uses a custom pointer and reference type that update indices for pointers in the heap.
113 class TimerHeapIterator : public std::iterator<std::random_access_iterator_tag, TimerBase*, ptrdiff_t, TimerHeapPointer, TimerHeapReference> { 155 class TimerHeapIterator : public std::iterator<std::random_access_iterator_tag, RefPtr<ThreadTimerHeapItem>, ptrdiff_t, TimerHeapPointer, TimerHeapReference> {
114 public: 156 public:
115 explicit TimerHeapIterator(TimerBase** pointer) : m_pointer(pointer) { checkConsistency(); } 157 explicit TimerHeapIterator(RefPtr<ThreadTimerHeapItem>* pointer) : m_pointer(pointer) { checkConsistency(); }
116 158
117 TimerHeapIterator& operator++() { checkConsistency(); ++m_pointer; checkConsistency(); return *this; } 159 TimerHeapIterator& operator++() { checkConsistency(); ++m_pointer; checkConsistency(); return *this; }
118 TimerHeapIterator operator++(int) { checkConsistency(1); return TimerHeapIterator(m_pointer++); } 160 TimerHeapIterator operator++(int) { checkConsistency(1); return TimerHeapIterator(m_pointer++); }
119 161
120 TimerHeapIterator& operator--() { checkConsistency(); --m_pointer; checkConsistency(); return *this; } 162 TimerHeapIterator& operator--() { checkConsistency(); --m_pointer; checkConsistency(); return *this; }
123 TimerHeapIterator& operator+=(ptrdiff_t i) { checkConsistency(); m_pointer += i; checkConsistency(); return *this; } 165 TimerHeapIterator& operator+=(ptrdiff_t i) { checkConsistency(); m_pointer += i; checkConsistency(); return *this; }
124 TimerHeapIterator& operator-=(ptrdiff_t i) { checkConsistency(); m_pointer -= i; checkConsistency(); return *this; } 166 TimerHeapIterator& operator-=(ptrdiff_t i) { checkConsistency(); m_pointer -= i; checkConsistency(); return *this; }
125 167
126 TimerHeapReference operator*() const { return TimerHeapReference(*m_pointer); } 168 TimerHeapReference operator*() const { return TimerHeapReference(*m_pointer); }
127 TimerHeapReference operator[](ptrdiff_t i) const { return TimerHeapReference(m_pointer[i]); } 169 TimerHeapReference operator[](ptrdiff_t i) const { return TimerHeapReference(m_pointer[i]); }
128 TimerBase* operator->() const { return *m_pointer; } 170 RefPtr<ThreadTimerHeapItem>& operator->() const { return *m_pointer; }
129 171
130 private: 172 private:
131 void checkConsistency(ptrdiff_t offset = 0) const 173 void checkConsistency(ptrdiff_t offset = 0) const
132 { 174 {
133 ASSERT(m_pointer >= threadGlobalTimerHeap().data()); 175 ASSERT(m_pointer >= threadGlobalTimerHeap().data());
147 friend TimerHeapIterator operator+(size_t, TimerHeapIterator); 189 friend TimerHeapIterator operator+(size_t, TimerHeapIterator);
148 190
149 friend TimerHeapIterator operator-(TimerHeapIterator, size_t); 191 friend TimerHeapIterator operator-(TimerHeapIterator, size_t);
150 friend ptrdiff_t operator-(TimerHeapIterator, TimerHeapIterator); 192 friend ptrdiff_t operator-(TimerHeapIterator, TimerHeapIterator);
151 193
152 TimerBase** m_pointer; 194 RefPtr<ThreadTimerHeapItem>* m_pointer;
153 }; 195 };
154 196
155 inline bool operator==(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer == b.m_pointer; } 197 inline bool operator==(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer == b.m_pointer; }
156 inline bool operator!=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer != b.m_pointer; } 198 inline bool operator!=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer != b.m_pointer; }
157 inline bool operator<(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer < b.m_pointer; } 199 inline bool operator<(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer < b.m_pointer; }
167 209
168 // ---------------- 210 // ----------------
169 211
170 class TimerHeapLessThanFunction { 212 class TimerHeapLessThanFunction {
171 public: 213 public:
172 bool operator()(const TimerBase*, const TimerBase*) const; 214 static bool compare(const TimerBase& a, const RefPtr<ThreadTimerHeapItem>& b)
173 }; 215 {
174 216 return compare(a.m_heapItem->time, a.m_heapItem->insertionOrder, b->time, b->insertionOrder);
175 inline bool TimerHeapLessThanFunction::operator()(const TimerBase* a, const TimerBase* b) const 217 }
176 { 218
219 static bool compare(const RefPtr<ThreadTimerHeapItem>& a, const TimerBase& b)
220 {
221 return compare(a->time, a->insertionOrder, b.m_heapItem->time, b.m_heapItem->insertionOrder);
222 }
223
224 bool operator()(const RefPtr<ThreadTimerHeapItem>& a, const RefPtr<ThreadTimerHeapItem>& b) const
225 {
226 return compare(a->time, a->insertionOrder, b->time, b->insertionOrder);
227 }
228
229 private:
230 static bool compare(MonotonicTime aTime, unsigned aOrder, MonotonicTime bTime, unsigned bOrder)
231 {
177 // The comparisons below are "backwards" because the heap puts the largest 232 // The comparisons below are "backwards" because the heap puts the largest
178 // element first and we want the lowest time to be the first one in the heap. 233 // element first and we want the lowest time to be the first one in the heap.
179 MonotonicTime aFireTime = a->m_nextFireTime; 234 if (bTime != aTime)
180 MonotonicTime bFireTime = b->m_nextFireTime; 235 return bTime < aTime;
181 if (bFireTime != aFireTime)
182 return bFireTime < aFireTime;
183
184 // We need to look at the difference of the insertion orders instead of comparing the two 236 // We need to look at the difference of the insertion orders instead of comparing the two
185 // outright in case of overflow. 237 // outright in case of overflow.
186 unsigned difference = a->m_heapInsertionOrder - b->m_heapInsertionOrder; 238 unsigned difference = aOrder - bOrder;
187 return difference < std::numeric_limits<unsigned>::max() / 2; 239 return difference < std::numeric_limits<unsigned>::max() / 2;
188 } 240 }
241 };
189 242
190 // ---------------- 243 // ----------------
191 244
192 static bool shouldSuppressThreadSafetyCheck() 245 static bool shouldSuppressThreadSafetyCheck()
193 { 246 {
199 return false; 252 return false;
200 #endif 253 #endif
201 } 254 }
202 255
203 TimerBase::TimerBase() 256 TimerBase::TimerBase()
204 : m_heapIndex(-1) 257 : m_wasDeleted(false)
205 , m_wasDeleted(false)
206 { 258 {
207 } 259 }
208 260
209 TimerBase::~TimerBase() 261 TimerBase::~TimerBase()
210 { 262 {
211 ASSERT(canAccessThreadLocalDataForThread(m_thread.get())); 263 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
212 RELEASE_ASSERT(canAccessThreadLocalDataForThread(m_thread.get()) || shouldSuppressThreadSafetyCheck()); 264 RELEASE_ASSERT(canAccessThreadLocalDataForThread(m_thread.get()) || shouldSuppressThreadSafetyCheck());
265 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(canAccessThreadLocalDataForThread(m_thread.get()));
213 stop(); 266 stop();
214 ASSERT(!inHeap()); 267 ASSERT(!inHeap());
268 if (m_heapItem) {
269 m_heapItem->clearTimer();
270 m_heapItem = nullptr;
271 }
215 m_wasDeleted = true; 272 m_wasDeleted = true;
216 } 273 }
217 274
218 void TimerBase::start(Seconds nextFireInterval, Seconds repeatInterval) 275 void TimerBase::start(Seconds nextFireInterval, Seconds repeatInterval)
219 { 276 {
228 ASSERT(canAccessThreadLocalDataForThread(m_thread.get())); 285 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
229 286
230 m_repeatInterval = 0_s; 287 m_repeatInterval = 0_s;
231 setNextFireTime(MonotonicTime { }); 288 setNextFireTime(MonotonicTime { });
232 289
233 ASSERT(!static_cast<bool>(m_nextFireTime)); 290 ASSERT(!static_cast<bool>(nextFireTime()));
234 ASSERT(m_repeatInterval == 0_s); 291 ASSERT(m_repeatInterval == 0_s);
235 ASSERT(!inHeap()); 292 ASSERT(!inHeap());
236 } 293 }
237 294
238 Seconds TimerBase::nextFireInterval() const 295 Seconds TimerBase::nextFireInterval() const
239 { 296 {
240 ASSERT(isActive()); 297 ASSERT(isActive());
298 ASSERT(m_heapItem);
241 MonotonicTime current = MonotonicTime::now(); 299 MonotonicTime current = MonotonicTime::now();
242 if (m_nextFireTime < current) 300 auto fireTime = nextFireTime();
301 if (fireTime < current)
243 return 0_s; 302 return 0_s;
244 return m_nextFireTime - current; 303 return fireTime - current;
245 } 304 }
246 305
247 inline void TimerBase::checkHeapIndex() const 306 inline void TimerBase::checkHeapIndex() const
248 { 307 {
249 ASSERT(timerHeap() == threadGlobalTimerHeap()); 308 #if !ASSERT_DISABLED
250 ASSERT(!timerHeap().isEmpty()); 309 ASSERT(m_heapItem);
251 ASSERT(m_heapIndex >= 0); 310 auto& heap = m_heapItem->timerHeap();
252 ASSERT(m_heapIndex < static_cast<int>(timerHeap().size())); 311 ASSERT(&heap == &threadGlobalTimerHeap());
253 ASSERT(timerHeap()[m_heapIndex] == this); 312 ASSERT(!heap.isEmpty());
313 ASSERT(m_heapItem->isInHeap());
314 ASSERT(m_heapItem->heapIndex() < m_heapItem->timerHeap().size());
315 ASSERT(heap[m_heapItem->heapIndex()] == m_heapItem);
316 for (unsigned i = 0, size = heap.size(); i < size; i++)
317 ASSERT(heap[i]->heapIndex() == i);
318 #endif
254 } 319 }
255 320
256 inline void TimerBase::checkConsistency() const 321 inline void TimerBase::checkConsistency() const
257 { 322 {
258 // Timers should be in the heap if and only if they have a non-zero next fire time. 323 // Timers should be in the heap if and only if they have a non-zero next fire time.
259 ASSERT(inHeap() == static_cast<bool>(m_nextFireTime)); 324 ASSERT(inHeap() == static_cast<bool>(nextFireTime()));
260 if (inHeap()) 325 if (inHeap())
261 checkHeapIndex(); 326 checkHeapIndex();
262 } 327 }
263 328
264 void TimerBase::heapDecreaseKey() 329 void TimerBase::heapDecreaseKey()
265 { 330 {
266 ASSERT(static_cast<bool>(m_nextFireTime)); 331 ASSERT(static_cast<bool>(nextFireTime()));
332 ASSERT(m_heapItem);
267 checkHeapIndex(); 333 checkHeapIndex();
268 TimerBase** heapData = timerHeap().data(); 334 auto* heapData = m_heapItem->timerHeap().data();
269 push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapIndex + 1), TimerHeapLessThanFunction()); 335 push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapItem->heapIndex() + 1), TimerHeapLessThanFunction());
270 checkHeapIndex(); 336 checkHeapIndex();
271 } 337 }
272 338
273 inline void TimerBase::heapDelete() 339 inline void TimerBase::heapDelete()
274 { 340 {
275 ASSERT(!static_cast<bool>(m_nextFireTime)); 341 ASSERT(!static_cast<bool>(nextFireTime()));
276 heapPop(); 342 heapPop();
277 timerHeap().removeLast(); 343 m_heapItem->timerHeap().removeLast();
278 m_heapIndex = -1; 344 m_heapItem->setNotInHeap();
279 } 345 }
280 346
281 void TimerBase::heapDeleteMin() 347 void TimerBase::heapDeleteMin()
282 { 348 {
283 ASSERT(!static_cast<bool>(m_nextFireTime)); 349 ASSERT(!static_cast<bool>(nextFireTime()));
284 heapPopMin(); 350 heapPopMin();
285 timerHeap().removeLast(); 351 m_heapItem->timerHeap().removeLast();
286 m_heapIndex = -1; 352 m_heapItem->setNotInHeap();
287 } 353 }
288 354
289 inline void TimerBase::heapIncreaseKey() 355 inline void TimerBase::heapIncreaseKey()
290 { 356 {
291 ASSERT(static_cast<bool>(m_nextFireTime)); 357 ASSERT(static_cast<bool>(nextFireTime()));
292 heapPop(); 358 heapPop();
293 heapDecreaseKey(); 359 heapDecreaseKey();
294 } 360 }
295 361
296 inline void TimerBase::heapInsert() 362 inline void TimerBase::heapInsert()
297 { 363 {
298 ASSERT(!inHeap()); 364 ASSERT(!inHeap());
299 timerHeap().append(this); 365 ASSERT(m_heapItem);
300 m_heapIndex = timerHeap().size() - 1; 366 auto& heap = m_heapItem->timerHeap();
367 heap.append(m_heapItem.copyRef());
368 m_heapItem->setHeapIndex(heap.size() - 1);
301 heapDecreaseKey(); 369 heapDecreaseKey();
302 } 370 }
303 371
304 inline void TimerBase::heapPop() 372 inline void TimerBase::heapPop()
305 { 373 {
374 ASSERT(m_heapItem);
306 // Temporarily force this timer to have the minimum key so we can pop it. 375 // Temporarily force this timer to have the minimum key so we can pop it.
307 MonotonicTime fireTime = m_nextFireTime; 376 MonotonicTime fireTime = m_heapItem->time;
308 m_nextFireTime = -MonotonicTime::infinity(); 377 m_heapItem->time = -MonotonicTime::infinity();
309 heapDecreaseKey(); 378 heapDecreaseKey();
310 heapPopMin(); 379 heapPopMin();
311 m_nextFireTime = fireTime; 380 m_heapItem->time = fireTime;
312 } 381 }
313 382
314 void TimerBase::heapPopMin() 383 void TimerBase::heapPopMin()
315 { 384 {
316 ASSERT(this == timerHeap().first()); 385 ASSERT(m_heapItem == m_heapItem->timerHeap().first());
317 checkHeapIndex(); 386 checkHeapIndex();
318 Vector<TimerBase*>& heap = timerHeap(); 387 auto& heap = m_heapItem->timerHeap();
319 TimerBase** heapData = heap.data(); 388 auto* heapData = heap.data();
320 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction()); 389 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
321 checkHeapIndex(); 390 checkHeapIndex();
322 ASSERT(this == timerHeap().last()); 391 ASSERT(m_heapItem == m_heapItem->timerHeap().last());
323 } 392 }
324 393
325 static inline bool parentHeapPropertyHolds(const TimerBase* current, const Vector<TimerBase*>& heap, unsigned currentIndex) 394 void TimerBase::heapDeleteNullMin(ThreadTimerHeap& heap)
395 {
396 RELEASE_ASSERT(!heap.first()->hasTimer());
397 heap.first()->time = -MonotonicTime::infinity();
398 auto* heapData = heap.data();
399 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
400 heap.removeLast();
401 }
402
403 static inline bool parentHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned currentIndex)
326 { 404 {
327 if (!currentIndex) 405 if (!currentIndex)
328 return true; 406 return true;
329 unsigned parentIndex = (currentIndex - 1) / 2; 407 unsigned parentIndex = (currentIndex - 1) / 2;
330 TimerHeapLessThanFunction compareHeapPosition; 408 return TimerHeapLessThanFunction::compare(*current, heap[parentIndex]);
331 return compareHeapPosition(current, heap[parentIndex]); 409 }
332 } 410
333 411 static inline bool childHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned childIndex)
334 static inline bool childHeapPropertyHolds(const TimerBase* current, const Vector<TimerBase*>& heap, unsigned childIndex)
335 { 412 {
336 if (childIndex >= heap.size()) 413 if (childIndex >= heap.size())
337 return true; 414 return true;
338 TimerHeapLessThanFunction compareHeapPosition; 415 return TimerHeapLessThanFunction::compare(heap[childIndex], *current);
339 return compareHeapPosition(heap[childIndex], current);
340 } 416 }
341 417
342 bool TimerBase::hasValidHeapPosition() const 418 bool TimerBase::hasValidHeapPosition() const
343 { 419 {
344 ASSERT(m_nextFireTime); 420 ASSERT(nextFireTime());
421 ASSERT(m_heapItem);
345 if (!inHeap()) 422 if (!inHeap())
346 return false; 423 return false;
347 // Check if the heap property still holds with the new fire time. If it does we don't need to do anything. 424 // Check if the heap property still holds with the new fire time. If it does we don't need to do anything.
348 // This assumes that the STL heap is a standard binary heap. In an unlikely event it is not, the assertions 425 // This assumes that the STL heap is a standard binary heap. In an unlikely event it is not, the assertions
349 // in updateHeapIfNeeded() will get hit. 426 // in updateHeapIfNeeded() will get hit.
350 const Vector<TimerBase*>& heap = timerHeap(); 427 const auto& heap = m_heapItem->timerHeap();
351 if (!parentHeapPropertyHolds(this, heap, m_heapIndex)) 428 unsigned heapIndex = m_heapItem->heapIndex();
429 if (!parentHeapPropertyHolds(this, heap, heapIndex))
352 return false; 430 return false;
353 unsigned childIndex1 = 2 * m_heapIndex + 1; 431 unsigned childIndex1 = 2 * heapIndex + 1;
354 unsigned childIndex2 = childIndex1 + 1; 432 unsigned childIndex2 = childIndex1 + 1;
355 return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyHolds(this, heap, childIndex2); 433 return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyHolds(this, heap, childIndex2);
356 } 434 }
357 435
358 void TimerBase::updateHeapIfNeeded(MonotonicTime oldTime) 436 void TimerBase::updateHeapIfNeeded(MonotonicTime oldTime)
359 { 437 {
360 if (m_nextFireTime && hasValidHeapPosition()) 438 auto fireTime = nextFireTime();
439 if (fireTime && hasValidHeapPosition())
361 return; 440 return;
362 #ifndef NDEBUG 441
363 int oldHeapIndex = m_heapIndex; 442 #if !ASSERT_DISABLED
443 Optional<unsigned> oldHeapIndex;
444 if (m_heapItem->isInHeap())
445 oldHeapIndex = m_heapItem->heapIndex();
364 #endif 446 #endif
447
365 if (!oldTime) 448 if (!oldTime)
366 heapInsert(); 449 heapInsert();
367 else if (!m_nextFireTime) 450 else if (!fireTime)
368 heapDelete(); 451 heapDelete();
369 else if (m_nextFireTime < oldTime) 452 else if (fireTime < oldTime)
370 heapDecreaseKey(); 453 heapDecreaseKey();
371 else 454 else
372 heapIncreaseKey(); 455 heapIncreaseKey();
373 ASSERT(m_heapIndex != oldHeapIndex); 456
457 #if !ASSERT_DISABLED
458 Optional<unsigned> newHeapIndex;
459 if (m_heapItem->isInHeap())
460 newHeapIndex = m_heapItem->heapIndex();
461 ASSERT(newHeapIndex != oldHeapIndex);
462 #endif
463
374 ASSERT(!inHeap() || hasValidHeapPosition()); 464 ASSERT(!inHeap() || hasValidHeapPosition());
375 } 465 }
376 466
377 void TimerBase::setNextFireTime(MonotonicTime newTime) 467 void TimerBase::setNextFireTime(MonotonicTime newTime)
378 { 468 {
381 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!m_wasDeleted); 471 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!m_wasDeleted);
382 472
383 if (m_unalignedNextFireTime != newTime) 473 if (m_unalignedNextFireTime != newTime)
384 m_unalignedNextFireTime = newTime; 474 m_unalignedNextFireTime = newTime;
385 475
386 // Accessing thread global data is slow. Cache the heap pointer.
387 if (!m_cachedThreadGlobalTimerHeap)
388 m_cachedThreadGlobalTimerHeap = &threadGlobalTimerHeap();
389
390 // Keep heap valid while changing the next-fire time. 476 // Keep heap valid while changing the next-fire time.
391 MonotonicTime oldTime = m_nextFireTime; 477 MonotonicTime oldTime = nextFireTime();
392 // Don't realign zero-delay timers. 478 // Don't realign zero-delay timers.
393 if (newTime) { 479 if (newTime) {
394 if (auto newAlignedTime = alignedFireTime(newTime)) 480 if (auto newAlignedTime = alignedFireTime(newTime))
395 newTime = newAlignedTime.value(); 481 newTime = newAlignedTime.value();
396 } 482 }
397 483
398 if (oldTime != newTime) { 484 if (oldTime != newTime) {
399 m_nextFireTime = newTime;
400 // FIXME: This should be part of ThreadTimers, or another per-thread structure. 485 // FIXME: This should be part of ThreadTimers, or another per-thread structure.
401 static std::atomic<unsigned> currentHeapInsertionOrder; 486 static std::atomic<unsigned> currentHeapInsertionOrder;
402 m_heapInsertionOrder = currentHeapInsertionOrder++; 487 auto newOrder = currentHeapInsertionOrder++;
403 488
404 bool wasFirstTimerInHeap = m_heapIndex == 0; 489 if (!m_heapItem)
490 m_heapItem = ThreadTimerHeapItem::create(*this, newTime, 0);
491 m_heapItem->time = newTime;
492 m_heapItem->insertionOrder = newOrder;
493
494 bool wasFirstTimerInHeap = m_heapItem->isFirstInHeap();
405 495
406 updateHeapIfNeeded(oldTime); 496 updateHeapIfNeeded(oldTime);
407 497
408 bool isFirstTimerInHeap = m_heapIndex == 0; 498 bool isFirstTimerInHeap = m_heapItem->isFirstInHeap();
409 499
410 if (wasFirstTimerInHeap || isFirstTimerInHeap) 500 if (wasFirstTimerInHeap || isFirstTimerInHeap)
411 threadGlobalData().threadTimers().updateSharedTimer(); 501 threadGlobalData().threadTimers().updateSharedTimer();
412 } 502 }
413 503