TimeStamp.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set ts=8 sts=2 et sw=2 tw=80: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #ifndef mozilla_TimeStamp_h
  7. #define mozilla_TimeStamp_h
  8. #include <stdint.h>
  9. #include "mozilla/Assertions.h"
  10. #include "mozilla/Attributes.h"
  11. #include "mozilla/FloatingPoint.h"
  12. #include "mozilla/TypeTraits.h"
  13. #include "mozilla/Types.h"
  14. namespace IPC {
  15. template<typename T> struct ParamTraits;
  16. } // namespace IPC
  17. #ifdef XP_WIN
  18. // defines TimeStampValue as a complex value keeping both
  19. // GetTickCount and QueryPerformanceCounter values
  20. #include "TimeStamp_windows.h"
  21. #endif
  22. namespace mozilla {
  23. #ifndef XP_WIN
  24. typedef uint64_t TimeStampValue;
  25. #endif
  26. class TimeStamp;
  27. /**
  28. * Platform-specific implementation details of BaseTimeDuration.
  29. */
  30. class BaseTimeDurationPlatformUtils
  31. {
  32. public:
  33. static MFBT_API double ToSeconds(int64_t aTicks);
  34. static MFBT_API double ToSecondsSigDigits(int64_t aTicks);
  35. static MFBT_API int64_t TicksFromMilliseconds(double aMilliseconds);
  36. static MFBT_API int64_t ResolutionInTicks();
  37. };
  38. /**
  39. * Instances of this class represent the length of an interval of time.
  40. * Negative durations are allowed, meaning the end is before the start.
  41. *
  42. * Internally the duration is stored as a int64_t in units of
  43. * PR_TicksPerSecond() when building with NSPR interval timers, or a
  44. * system-dependent unit when building with system clocks. The
  45. * system-dependent unit must be constant, otherwise the semantics of
  46. * this class would be broken.
  47. *
  48. * The ValueCalculator template parameter determines how arithmetic
  49. * operations are performed on the integer count of ticks (mValue).
  50. */
  51. template <typename ValueCalculator>
  52. class BaseTimeDuration
  53. {
  54. public:
  55. // The default duration is 0.
  56. constexpr BaseTimeDuration() : mValue(0) {}
  57. // Allow construction using '0' as the initial value, for readability,
  58. // but no other numbers (so we don't have any implicit unit conversions).
  59. struct _SomethingVeryRandomHere;
  60. MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0)
  61. {
  62. MOZ_ASSERT(!aZero, "Who's playing funny games here?");
  63. }
  64. // Default copy-constructor and assignment are OK
  65. // Converting copy-constructor and assignment operator
  66. template <typename E>
  67. explicit BaseTimeDuration(const BaseTimeDuration<E>& aOther)
  68. : mValue(aOther.mValue)
  69. { }
  70. template <typename E>
  71. BaseTimeDuration& operator=(const BaseTimeDuration<E>& aOther)
  72. {
  73. mValue = aOther.mValue;
  74. return *this;
  75. }
  76. double ToSeconds() const
  77. {
  78. if (mValue == INT64_MAX) {
  79. return PositiveInfinity<double>();
  80. }
  81. if (mValue == INT64_MIN) {
  82. return NegativeInfinity<double>();
  83. }
  84. return BaseTimeDurationPlatformUtils::ToSeconds(mValue);
  85. }
  86. // Return a duration value that includes digits of time we think to
  87. // be significant. This method should be used when displaying a
  88. // time to humans.
  89. double ToSecondsSigDigits() const
  90. {
  91. if (mValue == INT64_MAX) {
  92. return PositiveInfinity<double>();
  93. }
  94. if (mValue == INT64_MIN) {
  95. return NegativeInfinity<double>();
  96. }
  97. return BaseTimeDurationPlatformUtils::ToSecondsSigDigits(mValue);
  98. }
  99. double ToMilliseconds() const { return ToSeconds() * 1000.0; }
  100. double ToMicroseconds() const { return ToMilliseconds() * 1000.0; }
  101. // Using a double here is safe enough; with 53 bits we can represent
  102. // durations up to over 280,000 years exactly. If the units of
  103. // mValue do not allow us to represent durations of that length,
  104. // long durations are clamped to the max/min representable value
  105. // instead of overflowing.
  106. static inline BaseTimeDuration FromSeconds(double aSeconds)
  107. {
  108. return FromMilliseconds(aSeconds * 1000.0);
  109. }
  110. static BaseTimeDuration FromMilliseconds(double aMilliseconds)
  111. {
  112. if (aMilliseconds == PositiveInfinity<double>()) {
  113. return Forever();
  114. }
  115. if (aMilliseconds == NegativeInfinity<double>()) {
  116. return FromTicks(INT64_MIN);
  117. }
  118. return FromTicks(
  119. BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds));
  120. }
  121. static inline BaseTimeDuration FromMicroseconds(double aMicroseconds)
  122. {
  123. return FromMilliseconds(aMicroseconds / 1000.0);
  124. }
  125. static BaseTimeDuration Forever()
  126. {
  127. return FromTicks(INT64_MAX);
  128. }
  129. BaseTimeDuration operator+(const BaseTimeDuration& aOther) const
  130. {
  131. return FromTicks(ValueCalculator::Add(mValue, aOther.mValue));
  132. }
  133. BaseTimeDuration operator-(const BaseTimeDuration& aOther) const
  134. {
  135. return FromTicks(ValueCalculator::Subtract(mValue, aOther.mValue));
  136. }
  137. BaseTimeDuration& operator+=(const BaseTimeDuration& aOther)
  138. {
  139. mValue = ValueCalculator::Add(mValue, aOther.mValue);
  140. return *this;
  141. }
  142. BaseTimeDuration& operator-=(const BaseTimeDuration& aOther)
  143. {
  144. mValue = ValueCalculator::Subtract(mValue, aOther.mValue);
  145. return *this;
  146. }
  147. BaseTimeDuration operator-() const
  148. {
  149. // We don't just use FromTicks(ValueCalculator::Subtract(0, mValue))
  150. // since that won't give the correct result for -TimeDuration::Forever().
  151. int64_t ticks;
  152. if (mValue == INT64_MAX) {
  153. ticks = INT64_MIN;
  154. } else if (mValue == INT64_MIN) {
  155. ticks = INT64_MAX;
  156. } else {
  157. ticks = -mValue;
  158. }
  159. return FromTicks(ticks);
  160. }
  161. private:
  162. // Block double multiplier (slower, imprecise if long duration) - Bug 853398.
  163. // If required, use MultDouble explicitly and with care.
  164. BaseTimeDuration operator*(const double aMultiplier) const = delete;
  165. // Block double divisor (for the same reason, and because dividing by
  166. // fractional values would otherwise invoke the int64_t variant, and rounding
  167. // the passed argument can then cause divide-by-zero) - Bug 1147491.
  168. BaseTimeDuration operator/(const double aDivisor) const = delete;
  169. public:
  170. BaseTimeDuration MultDouble(double aMultiplier) const
  171. {
  172. return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
  173. }
  174. BaseTimeDuration operator*(const int32_t aMultiplier) const
  175. {
  176. return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
  177. }
  178. BaseTimeDuration operator*(const uint32_t aMultiplier) const
  179. {
  180. return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
  181. }
  182. BaseTimeDuration operator*(const int64_t aMultiplier) const
  183. {
  184. return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
  185. }
  186. BaseTimeDuration operator*(const uint64_t aMultiplier) const
  187. {
  188. if (aMultiplier > INT64_MAX) {
  189. return Forever();
  190. }
  191. return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
  192. }
  193. BaseTimeDuration operator/(const int64_t aDivisor) const
  194. {
  195. MOZ_ASSERT(aDivisor != 0, "Division by zero");
  196. return FromTicks(ValueCalculator::Divide(mValue, aDivisor));
  197. }
  198. double operator/(const BaseTimeDuration& aOther) const
  199. {
  200. #ifndef MOZ_B2G
  201. // Bug 1066388 - This fails on B2G ICS Emulator
  202. MOZ_ASSERT(aOther.mValue != 0, "Division by zero");
  203. #endif
  204. return ValueCalculator::DivideDouble(mValue, aOther.mValue);
  205. }
  206. BaseTimeDuration operator%(const BaseTimeDuration& aOther) const
  207. {
  208. MOZ_ASSERT(aOther.mValue != 0, "Division by zero");
  209. return FromTicks(ValueCalculator::Modulo(mValue, aOther.mValue));
  210. }
  211. template<typename E>
  212. bool operator<(const BaseTimeDuration<E>& aOther) const
  213. {
  214. return mValue < aOther.mValue;
  215. }
  216. template<typename E>
  217. bool operator<=(const BaseTimeDuration<E>& aOther) const
  218. {
  219. return mValue <= aOther.mValue;
  220. }
  221. template<typename E>
  222. bool operator>=(const BaseTimeDuration<E>& aOther) const
  223. {
  224. return mValue >= aOther.mValue;
  225. }
  226. template<typename E>
  227. bool operator>(const BaseTimeDuration<E>& aOther) const
  228. {
  229. return mValue > aOther.mValue;
  230. }
  231. template<typename E>
  232. bool operator==(const BaseTimeDuration<E>& aOther) const
  233. {
  234. return mValue == aOther.mValue;
  235. }
  236. template<typename E>
  237. bool operator!=(const BaseTimeDuration<E>& aOther) const
  238. {
  239. return mValue != aOther.mValue;
  240. }
  241. bool IsZero() const
  242. {
  243. return mValue == 0;
  244. }
  245. explicit operator bool() const
  246. {
  247. return mValue != 0;
  248. }
  249. // Return a best guess at the system's current timing resolution,
  250. // which might be variable. BaseTimeDurations below this order of
  251. // magnitude are meaningless, and those at the same order of
  252. // magnitude or just above are suspect.
  253. static BaseTimeDuration Resolution() {
  254. return FromTicks(BaseTimeDurationPlatformUtils::ResolutionInTicks());
  255. }
  256. // We could define additional operators here:
  257. // -- convert to/from other time units
  258. // -- scale duration by a float
  259. // but let's do that on demand.
  260. // Comparing durations for equality will only lead to bugs on
  261. // platforms with high-resolution timers.
  262. private:
  263. friend class TimeStamp;
  264. friend struct IPC::ParamTraits<mozilla::BaseTimeDuration<ValueCalculator>>;
  265. template <typename>
  266. friend class BaseTimeDuration;
  267. static BaseTimeDuration FromTicks(int64_t aTicks)
  268. {
  269. BaseTimeDuration t;
  270. t.mValue = aTicks;
  271. return t;
  272. }
  273. static BaseTimeDuration FromTicks(double aTicks)
  274. {
  275. // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX))
  276. // overflows and gives INT64_MIN.
  277. if (aTicks >= double(INT64_MAX)) {
  278. return FromTicks(INT64_MAX);
  279. }
  280. // This MUST be a <= test.
  281. if (aTicks <= double(INT64_MIN)) {
  282. return FromTicks(INT64_MIN);
  283. }
  284. return FromTicks(int64_t(aTicks));
  285. }
  286. // Duration, result is implementation-specific difference of two TimeStamps
  287. int64_t mValue;
  288. };
  289. /**
  290. * Perform arithmetic operations on the value of a BaseTimeDuration without
  291. * doing strict checks on the range of values.
  292. */
  293. class TimeDurationValueCalculator
  294. {
  295. public:
  296. static int64_t Add(int64_t aA, int64_t aB) { return aA + aB; }
  297. static int64_t Subtract(int64_t aA, int64_t aB) { return aA - aB; }
  298. template <typename T>
  299. static int64_t Multiply(int64_t aA, T aB)
  300. {
  301. static_assert(IsIntegral<T>::value,
  302. "Using integer multiplication routine with non-integer type."
  303. " Further specialization required");
  304. return aA * static_cast<int64_t>(aB);
  305. }
  306. static int64_t Divide(int64_t aA, int64_t aB) { return aA / aB; }
  307. static double DivideDouble(int64_t aA, int64_t aB)
  308. {
  309. return static_cast<double>(aA) / aB;
  310. }
  311. static int64_t Modulo(int64_t aA, int64_t aB) { return aA % aB; }
  312. };
  313. template <>
  314. inline int64_t
  315. TimeDurationValueCalculator::Multiply<double>(int64_t aA, double aB)
  316. {
  317. return static_cast<int64_t>(aA * aB);
  318. }
  319. /**
  320. * Specialization of BaseTimeDuration that uses TimeDurationValueCalculator for
  321. * arithmetic on the mValue member.
  322. *
  323. * Use this class for time durations that are *not* expected to hold values of
  324. * Forever (or the negative equivalent) or when such time duration are *not*
  325. * expected to be used in arithmetic operations.
  326. */
  327. typedef BaseTimeDuration<TimeDurationValueCalculator> TimeDuration;
  328. /**
  329. * Instances of this class represent moments in time, or a special
  330. * "null" moment. We do not use the non-monotonic system clock or
  331. * local time, since they can be reset, causing apparent backward
  332. * travel in time, which can confuse algorithms. Instead we measure
  333. * elapsed time according to the system. This time can never go
  334. * backwards (i.e. it never wraps around, at least not in less than
  335. * five million years of system elapsed time). It might not advance
  336. * while the system is sleeping. If TimeStamp::SetNow() is not called
  337. * at all for hours or days, we might not notice the passage of some
  338. * of that time.
  339. *
  340. * We deliberately do not expose a way to convert TimeStamps to some
  341. * particular unit. All you can do is compute a difference between two
  342. * TimeStamps to get a TimeDuration. You can also add a TimeDuration
  343. * to a TimeStamp to get a new TimeStamp. You can't do something
  344. * meaningless like add two TimeStamps.
  345. *
  346. * Internally this is implemented as either a wrapper around
  347. * - high-resolution, monotonic, system clocks if they exist on this
  348. * platform
  349. * - PRIntervalTime otherwise. We detect wraparounds of
  350. * PRIntervalTime and work around them.
  351. *
  352. * This class is similar to C++11's time_point, however it is
  353. * explicitly nullable and provides an IsNull() method. time_point
  354. * is initialized to the clock's epoch and provides a
  355. * time_since_epoch() method that functions similiarly. i.e.
  356. * t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero();
  357. */
  358. class TimeStamp
  359. {
  360. public:
  361. /**
  362. * Initialize to the "null" moment
  363. */
  364. constexpr TimeStamp() : mValue(0) {}
  365. // Default copy-constructor and assignment are OK
  366. /**
  367. * The system timestamps are the same as the TimeStamp
  368. * retrieved by mozilla::TimeStamp. Since we need this for
  369. * vsync timestamps, we enable the creation of mozilla::TimeStamps
  370. * on platforms that support vsync aligned refresh drivers / compositors
  371. * Verified true as of Jan 31, 2015: B2G and OS X
  372. * False on Windows 7
  373. * UNTESTED ON OTHER PLATFORMS
  374. */
  375. #if defined(MOZ_WIDGET_GONK) || defined(XP_DARWIN)
  376. static TimeStamp FromSystemTime(int64_t aSystemTime)
  377. {
  378. static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue),
  379. "System timestamp should be same units as TimeStampValue");
  380. return TimeStamp(aSystemTime);
  381. }
  382. #endif
  383. /**
  384. * Return true if this is the "null" moment
  385. */
  386. bool IsNull() const { return mValue == 0; }
  387. /**
  388. * Return true if this is not the "null" moment, may be used in tests, e.g.:
  389. * |if (timestamp) { ... }|
  390. */
  391. explicit operator bool() const
  392. {
  393. return mValue != 0;
  394. }
  395. /**
  396. * Return a timestamp reflecting the current elapsed system time. This
  397. * is monotonically increasing (i.e., does not decrease) over the
  398. * lifetime of this process' XPCOM session.
  399. *
  400. * Now() is trying to ensure the best possible precision on each platform,
  401. * at least one millisecond.
  402. *
  403. * NowLoRes() has been introduced to workaround performance problems of
  404. * QueryPerformanceCounter on the Windows platform. NowLoRes() is giving
  405. * lower precision, usually 15.6 ms, but with very good performance benefit.
  406. * Use it for measurements of longer times, like >200ms timeouts.
  407. */
  408. static TimeStamp Now() { return Now(true); }
  409. static TimeStamp NowLoRes() { return Now(false); }
  410. /**
  411. * Return a timestamp representing the time when the current process was
  412. * created which will be comparable with other timestamps taken with this
  413. * class. If the actual process creation time is detected to be inconsistent
  414. * the @a aIsInconsistent parameter will be set to true, the returned
  415. * timestamp however will still be valid though inaccurate.
  416. *
  417. * @param aIsInconsistent Set to true if an inconsistency was detected in the
  418. * process creation time
  419. * @returns A timestamp representing the time when the process was created,
  420. * this timestamp is always valid even when errors are reported
  421. */
  422. static MFBT_API TimeStamp ProcessCreation(bool& aIsInconsistent);
  423. /**
  424. * Records a process restart. After this call ProcessCreation() will return
  425. * the time when the browser was restarted instead of the actual time when
  426. * the process was created.
  427. */
  428. static MFBT_API void RecordProcessRestart();
  429. /**
  430. * Compute the difference between two timestamps. Both must be non-null.
  431. */
  432. TimeDuration operator-(const TimeStamp& aOther) const
  433. {
  434. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  435. MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
  436. static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check");
  437. int64_t ticks = int64_t(mValue - aOther.mValue);
  438. // Check for overflow.
  439. if (mValue > aOther.mValue) {
  440. if (ticks < 0) {
  441. ticks = INT64_MAX;
  442. }
  443. } else {
  444. if (ticks > 0) {
  445. ticks = INT64_MIN;
  446. }
  447. }
  448. return TimeDuration::FromTicks(ticks);
  449. }
  450. TimeStamp operator+(const TimeDuration& aOther) const
  451. {
  452. TimeStamp result = *this;
  453. result += aOther;
  454. return result;
  455. }
  456. TimeStamp operator-(const TimeDuration& aOther) const
  457. {
  458. TimeStamp result = *this;
  459. result -= aOther;
  460. return result;
  461. }
  462. TimeStamp& operator+=(const TimeDuration& aOther)
  463. {
  464. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  465. TimeStampValue value = mValue + aOther.mValue;
  466. // Check for underflow.
  467. // (We don't check for overflow because it's not obvious what the error
  468. // behavior should be in that case.)
  469. if (aOther.mValue < 0 && value > mValue) {
  470. value = 0;
  471. }
  472. mValue = value;
  473. return *this;
  474. }
  475. TimeStamp& operator-=(const TimeDuration& aOther)
  476. {
  477. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  478. TimeStampValue value = mValue - aOther.mValue;
  479. // Check for underflow.
  480. // (We don't check for overflow because it's not obvious what the error
  481. // behavior should be in that case.)
  482. if (aOther.mValue > 0 && value > mValue) {
  483. value = 0;
  484. }
  485. mValue = value;
  486. return *this;
  487. }
  488. bool operator<(const TimeStamp& aOther) const
  489. {
  490. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  491. MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
  492. return mValue < aOther.mValue;
  493. }
  494. bool operator<=(const TimeStamp& aOther) const
  495. {
  496. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  497. MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
  498. return mValue <= aOther.mValue;
  499. }
  500. bool operator>=(const TimeStamp& aOther) const
  501. {
  502. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  503. MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
  504. return mValue >= aOther.mValue;
  505. }
  506. bool operator>(const TimeStamp& aOther) const
  507. {
  508. MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
  509. MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
  510. return mValue > aOther.mValue;
  511. }
  512. bool operator==(const TimeStamp& aOther) const
  513. {
  514. return IsNull()
  515. ? aOther.IsNull()
  516. : !aOther.IsNull() && mValue == aOther.mValue;
  517. }
  518. bool operator!=(const TimeStamp& aOther) const
  519. {
  520. return !(*this == aOther);
  521. }
  522. // Comparing TimeStamps for equality should be discouraged. Adding
  523. // two TimeStamps, or scaling TimeStamps, is nonsense and must never
  524. // be allowed.
  525. static MFBT_API void Startup();
  526. static MFBT_API void Shutdown();
  527. private:
  528. friend struct IPC::ParamTraits<mozilla::TimeStamp>;
  529. friend void StartupTimelineRecordExternal(int, uint64_t);
  530. MOZ_IMPLICIT TimeStamp(TimeStampValue aValue) : mValue(aValue) {}
  531. static MFBT_API TimeStamp Now(bool aHighResolution);
  532. /**
  533. * Computes the uptime of the current process in microseconds. The result
  534. * is platform-dependent and needs to be checked against existing timestamps
  535. * for consistency.
  536. *
  537. * @returns The number of microseconds since the calling process was started
  538. * or 0 if an error was encountered while computing the uptime
  539. */
  540. static MFBT_API uint64_t ComputeProcessUptime();
  541. /**
  542. * When built with PRIntervalTime, a value of 0 means this instance
  543. * is "null". Otherwise, the low 32 bits represent a PRIntervalTime,
  544. * and the high 32 bits represent a counter of the number of
  545. * rollovers of PRIntervalTime that we've seen. This counter starts
  546. * at 1 to avoid a real time colliding with the "null" value.
  547. *
  548. * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum
  549. * time to wrap around is about 2^64/100000 seconds, i.e. about
  550. * 5,849,424 years.
  551. *
  552. * When using a system clock, a value is system dependent.
  553. */
  554. TimeStampValue mValue;
  555. };
  556. } // namespace mozilla
  557. #endif /* mozilla_TimeStamp_h */