[JSC][Temporal] Implement Temporal.ZonedDateTime
SVG transform mutations now batch and flush once per frame — but the flush fires BEFORE the re-entrancy guard during a higher layout.
// JSTests/stress/temporal-boundary-values.js
{
const maxNs = 8640000000000000000000n;
const zdt = new Temporal.ZonedDateTime(maxNs, "UTC");
shouldBe(zdt.epochNanoseconds, maxNs, "max epoch ns");
}
shouldThrow(() => new Temporal.ZonedDateTime(8640000000000000000001n, "UTC"));
shouldThrow(() => new Temporal.ZonedDateTime(-8640000000000000000001n, "UTC"));
// intl-canonical-iana-time-zone.js — FIXMEs removed:
for (const [legacy, primary] of pairs) {
shouldBeTrue(new Temporal.ZonedDateTime(0n, legacy).equals(new Temporal.ZonedDateTime(0n, primary)));
}
Temporal is TC39's date/time replacement for the legacy Date object; ZonedDateTime is its most complex type, storing an absolute instant as a BigInt epoch-nanosecond value (range ±8.64×10²¹ ns) paired with a named IANA time zone and an optional non-ISO calendar. JSC integrates ICU for non-Gregorian calendars like Japanese (which carries era/eraYear semantics on top of year) and uses dedicated time-zone infrastructure for DST gap/fold disambiguation.
This commit implements the constructor, prototype with all getters and methods, Temporal.Now.zonedDateTimeISO, and Duration.round/total/compare with ZonedDateTime as relativeTo. Bundled correctness fixes are revealing: several static_cast<int32_t>(double) conversions become clampTo<int32_t> (a double outside [INT32_MIN, INT32_MAX] cast to int32_t is C++ UB and on optimizing compilers can produce adversary-influenced bit patterns), a JSC heap object owning a String member is migrated from cellHeapCellType to destructibleCellHeapCellType (fixing a StringImpl leak from a silently-skipped destructor), and DurationArithmetic::computeNudgeWindow corrects a wrong spec shortcut that checked r1 == 0 instead of DateDurationSign(startDuration) == 0.
Significance
The bundled UB fixes and a pre-existing GC destructor omission are signals that the prior Temporal codebase had latent defects; where several instances were found, more likely remain. The commit introduces the most complex type in the TC39 Temporal proposal — BigInt epoch arithmetic, DST-aware time zone resolution, and ICU calendar integration — creating substantial new attack surface in JSC reachable from any page.
Audit directions
- Remaining direct double-to-integer casts in Temporal C++. Year/month/day/hour fields are potential UB sites; grep
static_cast<int32_t>andstatic_cast<uint8_t>in the Temporal source. destructibleCellHeapCellTypeomissions across the Temporal subtree. AuditTemporalInstant,TemporalPlainDate,TemporalTimeZoneetc. — any JSC heap object owning aStringor other non-trivially-destructible member but using plaincellHeapCellTypewill leak (and may UAF if a destructor relies on the type info).- The
CalendarICUBridgeoptional<int32_t> yearparameter change silently alters behavior at all call sites: callers that previously passed a year unintentionally will skip theNonISOResolveFieldsconsistency check — verify all callers passnulloptcorrectly. - DST fold disambiguation in
ZonedDateTime.prototype.with()and arithmetic methods is a known source of edge-case bugs (the newtemporal-zdt-large-fold-disambiguationtest confirms one was already found); fuzz with times in DST gaps and folds across ambiguous transitions. - BigInt-to-epoch-nanosecond conversion in the constructor and any arithmetic that produces a new epoch value should be checked for off-by-one at the ±8.64×10²¹ boundary.