Bug 558306 part 2. Switch XPCOM timers to TimeDuration/TimeStamp. r=cjones, sr=brendan
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 15 Jul 2010 09:59:24 -0400
changeset 48031 3ab60fc0581dfc5f1bb3b0568e9de864444a831a
parent 48030 1a5e6a1cdea4a0ab57ffdcec884d057644f33a6a
child 48032 d225b78f6738ec58d2aa9ee075a6e4d594568555
push id14542
push userbzbarsky@mozilla.com
push dateWed, 21 Jul 2010 19:58:36 +0000
treeherdermozilla-central@d225b78f6738 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones, brendan
bugs558306
milestone2.0b3pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 558306 part 2. Switch XPCOM timers to TimeDuration/TimeStamp. r=cjones, sr=brendan
xpcom/threads/TimerThread.cpp
xpcom/threads/TimerThread.h
xpcom/threads/nsTimerImpl.cpp
xpcom/threads/nsTimerImpl.h
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -45,29 +45,30 @@
 #include "nsThreadUtils.h"
 #include "pratom.h"
 
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "nsIProxyObjectManager.h"
 #include "mozilla/Services.h"
 
+#include <math.h>
+
 NS_IMPL_THREADSAFE_ISUPPORTS2(TimerThread, nsIRunnable, nsIObserver)
 
 TimerThread::TimerThread() :
   mInitInProgress(0),
   mInitialized(PR_FALSE),
   mLock(nsnull),
   mCondVar(nsnull),
   mShutdown(PR_FALSE),
   mWaiting(PR_FALSE),
   mSleeping(PR_FALSE),
   mDelayLineCounter(0),
-  mMinTimerPeriod(0),
-  mTimeoutAdjustment(0)
+  mMinTimerPeriod(0)
 {
 }
 
 TimerThread::~TimerThread()
 {
   if (mCondVar)
     PR_DestroyCondVar(mCondVar);
   if (mLock)
@@ -186,36 +187,37 @@ nsresult TimerThread::Shutdown()
 
   PR_LOG(gTimerLog, PR_LOG_DEBUG, ("TimerThread::Shutdown end\n"));
   return NS_OK;
 }
 
 // Keep track of how early (positive slack) or late (negative slack) timers
 // are running, and use the filtered slack number to adaptively estimate how
 // early timers should fire to be "on time".
-void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
-                               PRIntervalTime aNow)
+void TimerThread::UpdateFilter(PRUint32 aDelay, TimeStamp aTimeout,
+                               TimeStamp aNow)
 {
-  PRInt32 slack = (PRInt32) (aTimeout - aNow);
+  TimeDuration slack = aTimeout - aNow;
   double smoothSlack = 0;
   PRUint32 i, filterLength;
-  static PRIntervalTime kFilterFeedbackMaxTicks =
-    PR_MillisecondsToInterval(FILTER_FEEDBACK_MAX);
+  static TimeDuration kFilterFeedbackMaxTicks =
+    TimeDuration::FromMilliseconds(FILTER_FEEDBACK_MAX);
+  static TimeDuration kFilterFeedbackMinTicks =
+    TimeDuration::FromMilliseconds(-FILTER_FEEDBACK_MAX);
 
-  if (slack > 0) {
-    if (slack > (PRInt32)kFilterFeedbackMaxTicks)
-      slack = kFilterFeedbackMaxTicks;
-  } else {
-    if (slack < -(PRInt32)kFilterFeedbackMaxTicks)
-      slack = -(PRInt32)kFilterFeedbackMaxTicks;
-  }
-  mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] = slack;
+  if (slack > kFilterFeedbackMaxTicks)
+    slack = kFilterFeedbackMaxTicks;
+  else if (slack < kFilterFeedbackMinTicks)
+    slack = kFilterFeedbackMinTicks;
+
+  mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] =
+    slack.ToMilliseconds();
   if (++mDelayLineCounter < DELAY_LINE_LENGTH) {
     // Startup mode: accumulate a full delay line before filtering.
-    PR_ASSERT(mTimeoutAdjustment == 0);
+    PR_ASSERT(mTimeoutAdjustment.ToSeconds() == 0);
     filterLength = 0;
   } else {
     // Past startup: compute number of filter taps based on mMinTimerPeriod.
     if (mMinTimerPeriod == 0) {
       mMinTimerPeriod = (aDelay != 0) ? aDelay : 1;
     } else if (aDelay != 0 && aDelay < mMinTimerPeriod) {
       mMinTimerPeriod = aDelay;
     }
@@ -226,67 +228,65 @@ void TimerThread::UpdateFilter(PRUint32 
     else if (filterLength < 4)
       filterLength = 4;
 
     for (i = 1; i <= filterLength; i++)
       smoothSlack += mDelayLine[(mDelayLineCounter-i) & DELAY_LINE_LENGTH_MASK];
     smoothSlack /= filterLength;
 
     // XXXbe do we need amplification?  hacking a fudge factor, need testing...
-    mTimeoutAdjustment = (PRInt32) (smoothSlack * 1.5);
+    mTimeoutAdjustment = TimeDuration::FromMilliseconds(smoothSlack * 1.5);
   }
 
 #ifdef DEBUG_TIMERS
   PR_LOG(gTimerLog, PR_LOG_DEBUG,
          ("UpdateFilter: smoothSlack = %g, filterLength = %u\n",
           smoothSlack, filterLength));
 #endif
 }
 
 /* void Run(); */
 NS_IMETHODIMP TimerThread::Run()
 {
   nsAutoLock lock(mLock);
 
   while (!mShutdown) {
+    // Have to use PRIntervalTime here, since PR_WaitCondVar takes it
     PRIntervalTime waitFor;
 
     if (mSleeping) {
       // Sleep for 0.1 seconds while not firing timers.
       waitFor = PR_MillisecondsToInterval(100);
     } else {
       waitFor = PR_INTERVAL_NO_TIMEOUT;
-      PRIntervalTime now = PR_IntervalNow();
+      TimeStamp now = TimeStamp::Now();
       nsTimerImpl *timer = nsnull;
 
       if (!mTimers.IsEmpty()) {
         timer = mTimers[0];
 
-        if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) {
+        if (now >= timer->mTimeout + mTimeoutAdjustment) {
     next:
           // NB: AddRef before the Release under RemoveTimerInternal to avoid
           // mRefCnt passing through zero, in case all other refs than the one
           // from mTimers have gone away (the last non-mTimers[i]-ref's Release
           // must be racing with us, blocked in gThread->RemoveTimer waiting
           // for TimerThread::mLock, under nsTimerImpl::Release.
 
           NS_ADDREF(timer);
           RemoveTimerInternal(timer);
 
           // We release mLock around the Fire call to avoid deadlock.
           lock.unlock();
 
 #ifdef DEBUG_TIMERS
           if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
             PR_LOG(gTimerLog, PR_LOG_DEBUG,
-                   ("Timer thread woke up %dms from when it was supposed to\n",
-                    (now >= timer->mTimeout)
-                    ? PR_IntervalToMilliseconds(now - timer->mTimeout)
-                    : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now))
-                  );
+                   ("Timer thread woke up %fms from when it was supposed to\n",
+                    fabs((now - timer->mTimeout).ToMilliseconds())));
           }
 #endif
 
           // We are going to let the call to PostTimerEvent here handle the
           // release of the timer so that we don't end up releasing the timer
           // on the TimerThread instead of on the thread it targets.
           if (NS_FAILED(timer->PostTimerEvent())) {
             nsrefcnt rc;
@@ -308,30 +308,30 @@ NS_IMETHODIMP TimerThread::Run()
           timer = nsnull;
 
           lock.lock();
           if (mShutdown)
             break;
 
           // Update now, as PostTimerEvent plus the locking may have taken a
           // tick or two, and we may goto next below.
-          now = PR_IntervalNow();
+          now = TimeStamp::Now();
         }
       }
 
       if (!mTimers.IsEmpty()) {
         timer = mTimers[0];
 
-        PRIntervalTime timeout = timer->mTimeout + mTimeoutAdjustment;
+        TimeStamp timeout = timer->mTimeout + mTimeoutAdjustment;
 
         // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer
         // is due now or overdue.
-        if (!TIMER_LESS_THAN(now, timeout))
+        if (now >= timeout)
           goto next;
-        waitFor = timeout - now;
+        waitFor = PR_MillisecondsToInterval((timeout - now).ToMilliseconds());
       }
 
 #ifdef DEBUG_TIMERS
       if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
         if (waitFor == PR_INTERVAL_NO_TIMEOUT)
           PR_LOG(gTimerLog, PR_LOG_DEBUG,
                  ("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
         else
@@ -406,33 +406,32 @@ nsresult TimerThread::RemoveTimer(nsTime
 }
 
 // This function must be called from within a lock
 PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
 {
   if (mShutdown)
     return -1;
 
-  PRIntervalTime now = PR_IntervalNow();
+  TimeStamp now = TimeStamp::Now();
   PRUint32 count = mTimers.Length();
   PRUint32 i = 0;
   for (; i < count; i++) {
     nsTimerImpl *timer = mTimers[i];
 
-    // Don't break till we have skipped any overdue timers.  Do not include
-    // mTimeoutAdjustment here, because we are really trying to avoid calling
-    // TIMER_LESS_THAN(t, u), where the t is now + DELAY_INTERVAL_MAX, u is
-    // now - overdue, and DELAY_INTERVAL_MAX + overdue > DELAY_INTERVAL_LIMIT.
-    // In other words, we want to use now-based time, now adjusted time, even
-    // though "overdue" ultimately depends on adjusted time.
+    // Don't break till we have skipped any overdue timers.
+
+    // XXXbz why?  Given our definition of overdue in terms of
+    // mTimeoutAdjustment, aTimer might be overdue already!  Why not
+    // just fire timers in order?
 
     // XXX does this hold for TYPE_REPEATING_PRECISE?  /be
 
-    if (TIMER_LESS_THAN(now, timer->mTimeout) &&
-        TIMER_LESS_THAN(aTimer->mTimeout, timer->mTimeout)) {
+    if (now < timer->mTimeout + mTimeoutAdjustment &&
+        aTimer->mTimeout < timer->mTimeout) {
       break;
     }
   }
 
   if (!mTimers.InsertElementAt(i, aTimer))
     return -1;
 
   aTimer->mArmed = PR_TRUE;
@@ -468,17 +467,17 @@ void TimerThread::DoAfterSleep()
     nsTimerImpl *timer = mTimers[i];
     // get and set the delay to cause its timeout to be recomputed
     PRUint32 delay;
     timer->GetDelay(&delay);
     timer->SetDelay(delay);
   }
 
   // nuke the stored adjustments, so they get recalibrated
-  mTimeoutAdjustment = 0;
+  mTimeoutAdjustment = TimeDuration(0);
   mDelayLineCounter = 0;
   mSleeping = PR_FALSE;
 }
 
 
 /* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
 NS_IMETHODIMP
 TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const PRUnichar* /* aData */)
--- a/xpcom/threads/TimerThread.h
+++ b/xpcom/threads/TimerThread.h
@@ -45,23 +45,26 @@
 #include "nsIRunnable.h"
 #include "nsIThread.h"
 
 #include "nsTimerImpl.h"
 
 #include "nsTArray.h"
 
 #include "prcvar.h"
-#include "prinrval.h"
+#include "mozilla/TimeStamp.h"
 #include "prlock.h"
 
 class TimerThread : public nsIRunnable,
                     public nsIObserver
 {
 public:
+  typedef mozilla::TimeStamp TimeStamp;
+  typedef mozilla::TimeDuration TimeDuration;
+
   TimerThread();
   NS_HIDDEN_(nsresult) InitLocks();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSIOBSERVER
   
   NS_HIDDEN_(nsresult) Init();
@@ -69,18 +72,18 @@ public:
 
   nsresult AddTimer(nsTimerImpl *aTimer);
   nsresult TimerDelayChanged(nsTimerImpl *aTimer);
   nsresult RemoveTimer(nsTimerImpl *aTimer);
 
 #define FILTER_DURATION         1e3     /* one second */
 #define FILTER_FEEDBACK_MAX     100     /* 1/10th of a second */
 
-  void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
-                    PRIntervalTime aNow);
+  void UpdateFilter(PRUint32 aDelay, TimeStamp aTimeout,
+                    TimeStamp aNow);
 
   void DoBeforeSleep();
   void DoAfterSleep();
 
 private:
   ~TimerThread();
 
   PRInt32 mInitInProgress;
@@ -102,15 +105,15 @@ private:
   PRPackedBool mSleeping;
   
   nsTArray<nsTimerImpl*> mTimers;
 
 #define DELAY_LINE_LENGTH_LOG2  5
 #define DELAY_LINE_LENGTH_MASK  PR_BITMASK(DELAY_LINE_LENGTH_LOG2)
 #define DELAY_LINE_LENGTH       PR_BIT(DELAY_LINE_LENGTH_LOG2)
 
-  PRInt32  mDelayLine[DELAY_LINE_LENGTH];
+  PRInt32  mDelayLine[DELAY_LINE_LENGTH]; // milliseconds
   PRUint32 mDelayLineCounter;
   PRUint32 mMinTimerPeriod;     // milliseconds
-  PRInt32  mTimeoutAdjustment;
+  TimeDuration mTimeoutAdjustment;
 };
 
 #endif /* TimerThread_h___ */
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -41,16 +41,19 @@
 #include "nsTimerImpl.h"
 #include "TimerThread.h"
 #include "nsAutoLock.h"
 #include "nsAutoPtr.h"
 #include "nsThreadManager.h"
 #include "nsThreadUtils.h"
 #include "prmem.h"
 
+using mozilla::TimeDuration;
+using mozilla::TimeStamp;
+
 static PRInt32          gGenerator = 0;
 static TimerThread*     gThread = nsnull;
 
 #ifdef DEBUG_TIMERS
 #include <math.h>
 
 double nsTimerImpl::sDeltaSumSquared = 0;
 double nsTimerImpl::sDeltaSum = 0;
@@ -137,28 +140,22 @@ NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Re
 
 nsTimerImpl::nsTimerImpl() :
   mClosure(nsnull),
   mCallbackType(CALLBACK_TYPE_UNKNOWN),
   mFiring(PR_FALSE),
   mArmed(PR_FALSE),
   mCanceled(PR_FALSE),
   mGeneration(0),
-  mDelay(0),
-  mTimeout(0)
+  mDelay(0)
 {
   // XXXbsmedberg: shouldn't this be in Init()?
   mEventTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread());
 
   mCallback.c = nsnull;
-
-#ifdef DEBUG_TIMERS
-  mStart = 0;
-  mStart2 = 0;
-#endif
 }
 
 nsTimerImpl::~nsTimerImpl()
 {
   ReleaseCallback();
 }
 
 //static
@@ -296,18 +293,18 @@ NS_IMETHODIMP nsTimerImpl::SetDelay(PRUi
     // by re-setting delay instead of reinitializing the timer.
     NS_ERROR("nsITimer->SetDelay() called when the "
              "one-shot timer is not set up.");
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // If we're already repeating precisely, update mTimeout now so that the
   // new delay takes effect in the future.
-  if (mTimeout != 0 && mType == TYPE_REPEATING_PRECISE)
-    mTimeout = PR_IntervalNow();
+  if (!mTimeout.IsNull() && mType == TYPE_REPEATING_PRECISE)
+    mTimeout = TimeStamp::Now();
 
   SetDelayInternal(aDelay);
 
   if (!mFiring && gThread)
     gThread->TimerDelayChanged(this);
 
   return NS_OK;
 }
@@ -374,41 +371,42 @@ NS_IMETHODIMP nsTimerImpl::SetTarget(nsI
 }
 
 
 void nsTimerImpl::Fire()
 {
   if (mCanceled)
     return;
 
-  PRIntervalTime now = PR_IntervalNow();
+  TimeStamp now = TimeStamp::Now();
 #ifdef DEBUG_TIMERS
   if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
-    PRIntervalTime a = now - mStart; // actual delay in intervals
-    PRUint32       b = PR_MillisecondsToInterval(mDelay); // expected delay in intervals
-    PRUint32       d = PR_IntervalToMilliseconds((a > b) ? a - b : b - a); // delta in ms
+    TimeDuration   a = now - mStart; // actual delay in intervals
+    TimeDuration   b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals
+    TimeDuration   delta = (a > b) ? a - b : b - a;
+    PRUint32       d = delta.ToMilliseconds(); // delta in ms
     sDeltaSum += d;
     sDeltaSumSquared += double(d) * double(d);
     sDeltaNum++;
 
-    PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4dms\n", this, mDelay));
-    PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time   %4dms\n", this, PR_IntervalToMilliseconds(a)));
+    PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4ums\n", this, mDelay));
+    PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time   %fms\n", this, a.ToMilliseconds()));
     PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d)       -------\n", this, mType));
     PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p]     delta           %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d));
 
     mStart = mStart2;
-    mStart2 = 0;
+    mStart2 = TimeStamp::TimeStamp();
   }
 #endif
 
-  PRIntervalTime timeout = mTimeout;
+  TimeStamp timeout = mTimeout;
   if (mType == TYPE_REPEATING_PRECISE) {
     // Precise repeating timers advance mTimeout by mDelay without fail before
     // calling Fire().
-    timeout -= PR_MillisecondsToInterval(mDelay);
+    timeout -= TimeDuration::FromMilliseconds(mDelay);
   }
   if (gThread)
     gThread->UpdateFilter(mDelay, timeout, now);
 
   if (mCallbackType == CALLBACK_TYPE_INTERFACE)
     mTimerCallbackWhileFiring = mCallback.i;
   mFiring = PR_TRUE;
   
@@ -452,18 +450,18 @@ void nsTimerImpl::Fire()
   }
 
   mFiring = PR_FALSE;
   mTimerCallbackWhileFiring = nsnull;
 
 #ifdef DEBUG_TIMERS
   if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
     PR_LOG(gTimerLog, PR_LOG_DEBUG,
-           ("[this=%p] Took %dms to fire timer callback\n",
-            this, PR_IntervalToMilliseconds(PR_IntervalNow() - now)));
+           ("[this=%p] Took %fms to fire timer callback\n",
+            this, (TimeStamp::Now() - now).ToMilliseconds()));
   }
 #endif
 
   // Reschedule REPEATING_SLACK timers, but make sure that we aren't armed
   // already (which can happen if the callback reinitialized the timer).
   if (mType == TYPE_REPEATING_SLACK && !mArmed) {
     SetDelayInternal(mDelay); // force mTimeout to be recomputed.
     if (gThread)
@@ -478,17 +476,17 @@ public:
 
   nsTimerEvent(nsTimerImpl *timer, PRInt32 generation)
     : mTimer(timer), mGeneration(generation) {
     // timer is already addref'd for us
     MOZ_COUNT_CTOR(nsTimerEvent);
   }
 
 #ifdef DEBUG_TIMERS
-  PRIntervalTime mInitTime;
+  TimeStamp mInitTime;
 #endif
 
 private:
   ~nsTimerEvent() { 
 #ifdef DEBUG
     if (mTimer)
       NS_WARNING("leaking reference to nsTimerImpl");
 #endif
@@ -504,20 +502,20 @@ NS_IMETHODIMP nsTimerEvent::Run()
   nsRefPtr<nsTimerImpl> timer;
   timer.swap(mTimer);
 
   if (mGeneration != timer->GetGeneration())
     return NS_OK;
 
 #ifdef DEBUG_TIMERS
   if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
-    PRIntervalTime now = PR_IntervalNow();
+    TimeStamp now = TimeStamp::Now();
     PR_LOG(gTimerLog, PR_LOG_DEBUG,
-           ("[this=%p] time between PostTimerEvent() and Fire(): %dms\n",
-            this, PR_IntervalToMilliseconds(now - mInitTime)));
+           ("[this=%p] time between PostTimerEvent() and Fire(): %fms\n",
+            this, (now - mInitTime).ToMilliseconds()));
   }
 #endif
 
   timer->Fire();
 
   return NS_OK;
 }
 
@@ -531,17 +529,17 @@ nsresult nsTimerImpl::PostTimerEvent()
   // re-initialized after being canceled.
 
   nsRefPtr<nsTimerEvent> event = new nsTimerEvent(this, mGeneration);
   if (!event)
     return NS_ERROR_OUT_OF_MEMORY;
 
 #ifdef DEBUG_TIMERS
   if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
-    event->mInitTime = PR_IntervalNow();
+    event->mInitTime = TimeStamp::Now();
   }
 #endif
 
   // If this is a repeating precise timer, we need to calculate the time for
   // the next timer to fire before we make the callback.
   if (mType == TYPE_REPEATING_PRECISE) {
     SetDelayInternal(mDelay);
     if (gThread) {
@@ -554,33 +552,29 @@ nsresult nsTimerImpl::PostTimerEvent()
   nsresult rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
   if (NS_FAILED(rv) && gThread)
     gThread->RemoveTimer(this);
   return rv;
 }
 
 void nsTimerImpl::SetDelayInternal(PRUint32 aDelay)
 {
-  PRIntervalTime delayInterval = PR_MillisecondsToInterval(aDelay);
-  if (delayInterval > DELAY_INTERVAL_MAX) {
-    delayInterval = DELAY_INTERVAL_MAX;
-    aDelay = PR_IntervalToMilliseconds(delayInterval);
-  }
+  TimeDuration delayInterval = TimeDuration::FromMilliseconds(aDelay);
 
   mDelay = aDelay;
 
-  PRIntervalTime now = PR_IntervalNow();
-  if (mTimeout == 0 || mType != TYPE_REPEATING_PRECISE)
+  TimeStamp now = TimeStamp::Now();
+  if (mTimeout.IsNull() || mType != TYPE_REPEATING_PRECISE)
     mTimeout = now;
 
   mTimeout += delayInterval;
 
 #ifdef DEBUG_TIMERS
   if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
-    if (mStart == 0)
+    if (mStart.IsNull())
       mStart = now;
     else
       mStart2 = now;
   }
 #endif
 }
 
 // NOT FOR PUBLIC CONSUMPTION!
--- a/xpcom/threads/nsTimerImpl.h
+++ b/xpcom/threads/nsTimerImpl.h
@@ -45,16 +45,17 @@
 
 #include "nsITimer.h"
 #include "nsIEventTarget.h"
 #include "nsIObserver.h"
 
 #include "nsCOMPtr.h"
 
 #include "prlog.h"
+#include "mozilla/TimeStamp.h"
 
 #if defined(PR_LOGGING)
 static PRLogModuleInfo *gTimerLog = PR_NewLogModule("nsTimerImpl");
 #define DEBUG_TIMERS 1
 #else
 #undef DEBUG_TIMERS
 #endif
 
@@ -69,28 +70,20 @@ static PRLogModuleInfo *gTimerLog = PR_N
 
 enum {
   CALLBACK_TYPE_UNKNOWN   = 0,
   CALLBACK_TYPE_INTERFACE = 1,
   CALLBACK_TYPE_FUNC      = 2,
   CALLBACK_TYPE_OBSERVER  = 3
 };
 
-// Two timer deadlines must differ by less than half the PRIntervalTime domain.
-#define DELAY_INTERVAL_LIMIT    PR_BIT(8 * sizeof(PRIntervalTime) - 1)
-
-// Maximum possible delay (XXX rework to use ms rather than interval ticks).
-#define DELAY_INTERVAL_MAX      (DELAY_INTERVAL_LIMIT - 1)
-
-// Is interval-time t less than u, even if t has wrapped PRIntervalTime?
-#define TIMER_LESS_THAN(t, u)   ((t) - (u) > DELAY_INTERVAL_LIMIT)
-
 class nsTimerImpl : public nsITimer
 {
 public:
+  typedef mozilla::TimeStamp TimeStamp;
 
   nsTimerImpl();
 
   static NS_HIDDEN_(nsresult) Startup();
   static NS_HIDDEN_(void) Shutdown();
 
   friend class TimerThread;
 
@@ -152,20 +145,20 @@ private:
   PRBool                mCanceled;
 
   // The generation number of this timer, re-generated each time the timer is
   // initialized so one-shot timers can be canceled and re-initialized by the
   // arming thread without any bad race conditions.
   PRInt32               mGeneration;
 
   PRUint32              mDelay;
-  PRIntervalTime        mTimeout;
+  TimeStamp             mTimeout;
 
 #ifdef DEBUG_TIMERS
-  PRIntervalTime        mStart, mStart2;
+  TimeStamp             mStart, mStart2;
   static double         sDeltaSum;
   static double         sDeltaSumSquared;
   static double         sDeltaNum;
 #endif
 
 };
 
 #endif /* nsTimerImpl_h___ */