Skip to content

Commit db73d44

Browse files
Gabriel CharetteCommit Bot
authored andcommitted
Bring Time(Delta)::Min/Max() and related helpers to V8.
Copied as-is modulo compile tweaks from Chromium's base. Copied tests highlighting existing overflow issues with V8's impl... TimeDelta::Max() will initially be used in V8 to flag events that never triggered in a TimedHistogram. Also constexpr'ed a few things while I was in there, it's harmless at worst and helps a little at best. Ideally would constexpr all the Time*::From*() methods like in Chromium but that has inlining implications and I don't know the impact that could have on V8. Bug: chromium:807606 Change-Id: If5aa92759d985be070e12af4dd20f0159169048b Reviewed-on: https://chromium-review.googlesource.com/899342 Reviewed-by: Hannes Payer <hpayer@chromium.org> Commit-Queue: Gabriel Charette <gab@chromium.org> Cr-Commit-Position: refs/heads/master@{#51073}
1 parent 7a0f805 commit db73d44

3 files changed

Lines changed: 309 additions & 33 deletions

File tree

src/base/platform/time.cc

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,41 +143,83 @@ TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
143143

144144

145145
int TimeDelta::InDays() const {
146+
if (IsMax()) {
147+
// Preserve max to prevent overflow.
148+
return std::numeric_limits<int>::max();
149+
}
146150
return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
147151
}
148152

149-
150153
int TimeDelta::InHours() const {
154+
if (IsMax()) {
155+
// Preserve max to prevent overflow.
156+
return std::numeric_limits<int>::max();
157+
}
151158
return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
152159
}
153160

154-
155161
int TimeDelta::InMinutes() const {
162+
if (IsMax()) {
163+
// Preserve max to prevent overflow.
164+
return std::numeric_limits<int>::max();
165+
}
156166
return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
157167
}
158168

159-
160169
double TimeDelta::InSecondsF() const {
170+
if (IsMax()) {
171+
// Preserve max to prevent overflow.
172+
return std::numeric_limits<double>::infinity();
173+
}
161174
return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
162175
}
163176

164-
165177
int64_t TimeDelta::InSeconds() const {
178+
if (IsMax()) {
179+
// Preserve max to prevent overflow.
180+
return std::numeric_limits<int64_t>::max();
181+
}
166182
return delta_ / Time::kMicrosecondsPerSecond;
167183
}
168184

169-
170185
double TimeDelta::InMillisecondsF() const {
186+
if (IsMax()) {
187+
// Preserve max to prevent overflow.
188+
return std::numeric_limits<double>::infinity();
189+
}
171190
return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
172191
}
173192

174-
175193
int64_t TimeDelta::InMilliseconds() const {
194+
if (IsMax()) {
195+
// Preserve max to prevent overflow.
196+
return std::numeric_limits<int64_t>::max();
197+
}
176198
return delta_ / Time::kMicrosecondsPerMillisecond;
177199
}
178200

201+
int64_t TimeDelta::InMillisecondsRoundedUp() const {
202+
if (IsMax()) {
203+
// Preserve max to prevent overflow.
204+
return std::numeric_limits<int64_t>::max();
205+
}
206+
return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
207+
Time::kMicrosecondsPerMillisecond;
208+
}
209+
210+
int64_t TimeDelta::InMicroseconds() const {
211+
if (IsMax()) {
212+
// Preserve max to prevent overflow.
213+
return std::numeric_limits<int64_t>::max();
214+
}
215+
return delta_;
216+
}
179217

180218
int64_t TimeDelta::InNanoseconds() const {
219+
if (IsMax()) {
220+
// Preserve max to prevent overflow.
221+
return std::numeric_limits<int64_t>::max();
222+
}
181223
return delta_ * Time::kNanosecondsPerMicrosecond;
182224
}
183225

src/base/platform/time.h

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class TimeBase;
4747

4848
class V8_BASE_EXPORT TimeDelta final {
4949
public:
50-
TimeDelta() : delta_(0) {}
50+
constexpr TimeDelta() : delta_(0) {}
5151

5252
// Converts units of time to TimeDeltas.
5353
static TimeDelta FromDays(int days);
@@ -60,6 +60,27 @@ class V8_BASE_EXPORT TimeDelta final {
6060
}
6161
static TimeDelta FromNanoseconds(int64_t nanoseconds);
6262

63+
// Returns the maximum time delta, which should be greater than any reasonable
64+
// time delta we might compare it to. Adding or subtracting the maximum time
65+
// delta to a time or another time delta has an undefined result.
66+
static constexpr TimeDelta Max();
67+
68+
// Returns the minimum time delta, which should be less than than any
69+
// reasonable time delta we might compare it to. Adding or subtracting the
70+
// minimum time delta to a time or another time delta has an undefined result.
71+
static constexpr TimeDelta Min();
72+
73+
// Returns true if the time delta is zero.
74+
constexpr bool IsZero() const { return delta_ == 0; }
75+
76+
// Returns true if the time delta is the maximum/minimum time delta.
77+
constexpr bool IsMax() const {
78+
return delta_ == std::numeric_limits<int64_t>::max();
79+
}
80+
constexpr bool IsMin() const {
81+
return delta_ == std::numeric_limits<int64_t>::min();
82+
}
83+
6384
// Returns the time delta in some unit. The F versions return a floating
6485
// point value, the "regular" versions return a rounded-down value.
6586
//
@@ -73,7 +94,7 @@ class V8_BASE_EXPORT TimeDelta final {
7394
double InMillisecondsF() const;
7495
int64_t InMilliseconds() const;
7596
int64_t InMillisecondsRoundedUp() const;
76-
int64_t InMicroseconds() const { return delta_; }
97+
int64_t InMicroseconds() const;
7798
int64_t InNanoseconds() const;
7899

79100
// Converts to/from Mach time specs.
@@ -105,9 +126,7 @@ class V8_BASE_EXPORT TimeDelta final {
105126
delta_ -= other.delta_;
106127
return *this;
107128
}
108-
TimeDelta operator-() const {
109-
return TimeDelta(-delta_);
110-
}
129+
constexpr TimeDelta operator-() const { return TimeDelta(-delta_); }
111130

112131
double TimesOf(const TimeDelta& other) const {
113132
return static_cast<double>(delta_) / static_cast<double>(other.delta_);
@@ -137,22 +156,22 @@ class V8_BASE_EXPORT TimeDelta final {
137156
}
138157

139158
// Comparison operators.
140-
bool operator==(const TimeDelta& other) const {
159+
constexpr bool operator==(const TimeDelta& other) const {
141160
return delta_ == other.delta_;
142161
}
143-
bool operator!=(const TimeDelta& other) const {
162+
constexpr bool operator!=(const TimeDelta& other) const {
144163
return delta_ != other.delta_;
145164
}
146-
bool operator<(const TimeDelta& other) const {
165+
constexpr bool operator<(const TimeDelta& other) const {
147166
return delta_ < other.delta_;
148167
}
149-
bool operator<=(const TimeDelta& other) const {
168+
constexpr bool operator<=(const TimeDelta& other) const {
150169
return delta_ <= other.delta_;
151170
}
152-
bool operator>(const TimeDelta& other) const {
171+
constexpr bool operator>(const TimeDelta& other) const {
153172
return delta_ > other.delta_;
154173
}
155-
bool operator>=(const TimeDelta& other) const {
174+
constexpr bool operator>=(const TimeDelta& other) const {
156175
return delta_ >= other.delta_;
157176
}
158177

@@ -161,12 +180,21 @@ class V8_BASE_EXPORT TimeDelta final {
161180
// Constructs a delta given the duration in microseconds. This is private
162181
// to avoid confusion by callers with an integer constructor. Use
163182
// FromSeconds, FromMilliseconds, etc. instead.
164-
explicit TimeDelta(int64_t delta) : delta_(delta) {}
183+
explicit constexpr TimeDelta(int64_t delta) : delta_(delta) {}
165184

166185
// Delta in microseconds.
167186
int64_t delta_;
168187
};
169188

189+
// static
190+
constexpr TimeDelta TimeDelta::Max() {
191+
return TimeDelta(std::numeric_limits<int64_t>::max());
192+
}
193+
194+
// static
195+
constexpr TimeDelta TimeDelta::Min() {
196+
return TimeDelta(std::numeric_limits<int64_t>::min());
197+
}
170198

171199
namespace time_internal {
172200

@@ -207,12 +235,24 @@ class TimeBase {
207235
// Warning: Be careful when writing code that performs math on time values,
208236
// since it's possible to produce a valid "zero" result that should not be
209237
// interpreted as a "null" value.
210-
bool IsNull() const {
211-
return us_ == 0;
238+
constexpr bool IsNull() const { return us_ == 0; }
239+
240+
// Returns the maximum/minimum times, which should be greater/less than any
241+
// reasonable time with which we might compare it.
242+
static TimeClass Max() {
243+
return TimeClass(std::numeric_limits<int64_t>::max());
244+
}
245+
static TimeClass Min() {
246+
return TimeClass(std::numeric_limits<int64_t>::min());
212247
}
213248

214-
// Returns true if this object represents the maximum time.
215-
bool IsMax() const { return us_ == std::numeric_limits<int64_t>::max(); }
249+
// Returns true if this object represents the maximum/minimum time.
250+
constexpr bool IsMax() const {
251+
return us_ == std::numeric_limits<int64_t>::max();
252+
}
253+
constexpr bool IsMin() const {
254+
return us_ == std::numeric_limits<int64_t>::min();
255+
}
216256

217257
// For serializing only. Use FromInternalValue() to reconstitute. Please don't
218258
// use this and do arithmetic on it, as it is more error prone than using the
@@ -272,7 +312,7 @@ class TimeBase {
272312
static TimeClass FromInternalValue(int64_t us) { return TimeClass(us); }
273313

274314
protected:
275-
explicit TimeBase(int64_t us) : us_(us) {}
315+
explicit constexpr TimeBase(int64_t us) : us_(us) {}
276316

277317
// Time value in a microsecond timebase.
278318
int64_t us_;
@@ -290,7 +330,7 @@ class TimeBase {
290330
class V8_BASE_EXPORT Time final : public time_internal::TimeBase<Time> {
291331
public:
292332
// Contains the nullptr time. Use Time::Now() to get the current time.
293-
Time() : TimeBase(0) {}
333+
constexpr Time() : TimeBase(0) {}
294334

295335
// Returns the current time. Watch out, the system might adjust its clock
296336
// in which case time will actually go backwards. We don't guarantee that
@@ -306,10 +346,6 @@ class V8_BASE_EXPORT Time final : public time_internal::TimeBase<Time> {
306346
// Returns the time for epoch in Unix-like system (Jan 1, 1970).
307347
static Time UnixEpoch() { return Time(0); }
308348

309-
// Returns the maximum time, which should be greater than any reasonable time
310-
// with which we might compare it.
311-
static Time Max() { return Time(std::numeric_limits<int64_t>::max()); }
312-
313349
// Converts to/from POSIX time specs.
314350
static Time FromTimespec(struct timespec ts);
315351
struct timespec ToTimespec() const;
@@ -329,7 +365,7 @@ class V8_BASE_EXPORT Time final : public time_internal::TimeBase<Time> {
329365

330366
private:
331367
friend class time_internal::TimeBase<Time>;
332-
explicit Time(int64_t us) : TimeBase(us) {}
368+
explicit constexpr Time(int64_t us) : TimeBase(us) {}
333369
};
334370

335371
V8_BASE_EXPORT std::ostream& operator<<(std::ostream&, const Time&);
@@ -352,7 +388,7 @@ inline Time operator+(const TimeDelta& delta, const Time& time) {
352388
class V8_BASE_EXPORT TimeTicks final
353389
: public time_internal::TimeBase<TimeTicks> {
354390
public:
355-
TimeTicks() : TimeBase(0) {}
391+
constexpr TimeTicks() : TimeBase(0) {}
356392

357393
// Platform-dependent tick count representing "right now." When
358394
// IsHighResolution() returns false, the resolution of the clock could be as
@@ -374,7 +410,7 @@ class V8_BASE_EXPORT TimeTicks final
374410

375411
// Please use Now() to create a new object. This is for internal use
376412
// and testing. Ticks are in microseconds.
377-
explicit TimeTicks(int64_t ticks) : TimeBase(ticks) {}
413+
explicit constexpr TimeTicks(int64_t ticks) : TimeBase(ticks) {}
378414
};
379415

380416
inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) {
@@ -389,7 +425,7 @@ inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) {
389425
class V8_BASE_EXPORT ThreadTicks final
390426
: public time_internal::TimeBase<ThreadTicks> {
391427
public:
392-
ThreadTicks() : TimeBase(0) {}
428+
constexpr ThreadTicks() : TimeBase(0) {}
393429

394430
// Returns true if ThreadTicks::Now() is supported on this system.
395431
static bool IsSupported();
@@ -424,7 +460,7 @@ class V8_BASE_EXPORT ThreadTicks final
424460

425461
// Please use Now() or GetForThread() to create a new object. This is for
426462
// internal use and testing. Ticks are in microseconds.
427-
explicit ThreadTicks(int64_t ticks) : TimeBase(ticks) {}
463+
explicit constexpr ThreadTicks(int64_t ticks) : TimeBase(ticks) {}
428464

429465
#if V8_OS_WIN
430466
// Returns the frequency of the TSC in ticks per second, or 0 if it hasn't

0 commit comments

Comments
 (0)