Index: Source/platform/Timer.h |
diff --git a/Source/platform/Timer.h b/Source/platform/Timer.h |
index 58d96925a3673d41573c07d2b4229131645b83ad..59652252f317784d2b6960da579848ce1865f2e8 100644 |
--- a/Source/platform/Timer.h |
+++ b/Source/platform/Timer.h |
@@ -43,7 +43,7 @@ public: |
TimerBase(); |
virtual ~TimerBase(); |
- void start(double nextFireInterval, double repeatInterval, const TraceLocation&); |
+ virtual void start(double nextFireInterval, double repeatInterval, const TraceLocation&); |
void startRepeating(double repeatInterval, const TraceLocation& caller) |
{ |
@@ -54,7 +54,7 @@ public: |
start(interval, 0, caller); |
} |
- void stop(); |
+ virtual void stop(); |
bool isActive() const; |
const TraceLocation& location() const { return m_location; } |
@@ -71,6 +71,9 @@ public: |
static void fireTimersInNestedEventLoop(); |
+protected: |
+ virtual void setNextFireTime(double); |
+ |
private: |
virtual void fired() = 0; |
@@ -79,8 +82,6 @@ private: |
void checkConsistency() const; |
void checkHeapIndex() const; |
- void setNextFireTime(double); |
- |
bool inHeap() const { return m_heapIndex != -1; } |
bool hasValidHeapPosition() const; |
@@ -113,16 +114,99 @@ private: |
friend class TimerHeapReference; |
}; |
+class PLATFORM_EXPORT TimerInstanceTracker { |
+public: |
+ using TraceMethodTrampoline = void (*)(Visitor*, void*); |
+ |
+ static void remove(const void*); |
+ static void add(const void*, TraceMethodTrampoline); |
+}; |
+ |
+template<typename T, bool = IsGarbageCollectedType<T>::value> |
+class TimerKeepAliveTrait { |
+public: |
+ static bool protect(bool, const T*) { return false; } |
+ static bool unprotect(bool, const void*) { return false; } |
+}; |
+ |
+#if ENABLE(OILPAN) |
+template<typename T> |
+class TimerKeepAliveTrait<T, true> { |
+public: |
+ static bool protect(bool needsProtection, const T* object) |
+ { |
+ if (needsProtection) |
+ TimerInstanceTracker::add(object, &trampoline); |
+ |
+ return needsProtection; |
+ } |
+ |
+ static bool unprotect(bool doesNotNeedProtection, const void* object) |
+ { |
+ if (doesNotNeedProtection) |
+ TimerInstanceTracker::remove(object); |
+ |
+ return doesNotNeedProtection; |
+ } |
+ |
+private: |
+ static void trampoline(Visitor* visitor, void* self) { (reinterpret_cast<T*>(self)->trace)(visitor); } |
+}; |
+#else |
+// FIXME: Oilpan: remove this specialization when lazy sweeping is enabled on trunk. |
+template<typename T> |
+class TimerKeepAliveTrait<T, true> { |
+public: |
+ static bool protect(bool, const T*) { return false; } |
+ static bool unprotect(bool, const void*) { return false; } |
+}; |
+#endif |
+ |
template <typename TimerFiredClass> |
class Timer final : public TimerBase { |
public: |
typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*); |
Timer(TimerFiredClass* o, TimerFiredFunction f) |
- : m_object(o), m_function(f) { } |
+ : m_object(o) |
+ , m_function(f) |
+ , m_isKeptAlive(false) |
+ { |
+ } |
+ |
+ ~Timer() override |
+ { |
+ TimerKeepAliveTrait<TimerFiredClass>::unprotect(m_isKeptAlive, m_object); |
+ } |
+ |
+ void start(double nextFireInterval, double repeatInterval, const TraceLocation& caller) override |
+ { |
+ TimerBase::start(nextFireInterval, repeatInterval, caller); |
+ if (TimerKeepAliveTrait<TimerFiredClass>::protect(!m_isKeptAlive && isActive(), m_object)) |
+ m_isKeptAlive = true; |
+ } |
+ |
+ void stop() override |
+ { |
+ TimerBase::stop(); |
+ if (TimerKeepAliveTrait<TimerFiredClass>::unprotect(m_isKeptAlive && !isActive(), m_object)) |
+ m_isKeptAlive = false; |
+ } |
private: |
- virtual void fired() override { (m_object->*m_function)(this); } |
+ void fired() override |
+ { |
+ if (TimerKeepAliveTrait<TimerFiredClass>::unprotect(m_isKeptAlive && !isActive(), m_object)) |
+ m_isKeptAlive = false; |
+ (m_object->*m_function)(this); |
+ } |
+ |
+ void setNextFireTime(double newUnalignedTime) override |
+ { |
+ TimerBase::setNextFireTime(newUnalignedTime); |
+ if (TimerKeepAliveTrait<TimerFiredClass>::unprotect(m_isKeptAlive && !isActive(), m_object)) |
+ m_isKeptAlive = false; |
+ } |
// FIXME: oilpan: TimerBase should be moved to the heap and m_object should be traced. |
// This raw pointer is safe as long as Timer<X> is held by the X itself (That's the case |
@@ -130,6 +214,7 @@ private: |
GC_PLUGIN_IGNORE("363031") |
TimerFiredClass* m_object; |
TimerFiredFunction m_function; |
+ bool m_isKeptAlive; |
}; |
inline bool TimerBase::isActive() const |
@@ -138,6 +223,6 @@ inline bool TimerBase::isActive() const |
return m_nextFireTime; |
} |
-} |
+} // namespace blink |
-#endif |
+#endif // Timer_h |