LCOV - code coverage report
Current view: top level - js/src - jsdate.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 223 1419 15.7 %
Date: 2017-07-14 16:53:18 Functions: 40 165 24.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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             : 
       7             : /*
       8             :  * JS date methods.
       9             :  *
      10             :  * "For example, OS/360 devotes 26 bytes of the permanently
      11             :  *  resident date-turnover routine to the proper handling of
      12             :  *  December 31 on leap years (when it is Day 366).  That
      13             :  *  might have been left to the operator."
      14             :  *
      15             :  * Frederick Brooks, 'The Second-System Effect'.
      16             :  */
      17             : 
      18             : #include "jsdate.h"
      19             : 
      20             : #include "mozilla/ArrayUtils.h"
      21             : #include "mozilla/Atomics.h"
      22             : #include "mozilla/FloatingPoint.h"
      23             : #include "mozilla/Sprintf.h"
      24             : 
      25             : #include <ctype.h>
      26             : #include <math.h>
      27             : #include <string.h>
      28             : 
      29             : #include "jsapi.h"
      30             : #include "jscntxt.h"
      31             : #include "jsnum.h"
      32             : #include "jsobj.h"
      33             : #include "jsprf.h"
      34             : #include "jsstr.h"
      35             : #include "jstypes.h"
      36             : #include "jsutil.h"
      37             : #include "jswrapper.h"
      38             : 
      39             : #include "js/Conversions.h"
      40             : #include "js/Date.h"
      41             : #include "vm/DateTime.h"
      42             : #include "vm/GlobalObject.h"
      43             : #include "vm/Interpreter.h"
      44             : #include "vm/String.h"
      45             : #include "vm/StringBuffer.h"
      46             : #include "vm/Time.h"
      47             : 
      48             : #include "jsobjinlines.h"
      49             : 
      50             : using namespace js;
      51             : 
      52             : using mozilla::Atomic;
      53             : using mozilla::ArrayLength;
      54             : using mozilla::IsFinite;
      55             : using mozilla::IsNaN;
      56             : using mozilla::NumbersAreIdentical;
      57             : using mozilla::ReleaseAcquire;
      58             : 
      59             : using JS::AutoCheckCannotGC;
      60             : using JS::ClippedTime;
      61             : using JS::GenericNaN;
      62             : using JS::TimeClip;
      63             : using JS::ToInteger;
      64             : 
      65             : // When this value is non-zero, we'll round the time by this resolution.
      66             : static Atomic<uint32_t, ReleaseAcquire> sResolutionUsec;
      67             : 
      68             : /*
      69             :  * The JS 'Date' object is patterned after the Java 'Date' object.
      70             :  * Here is a script:
      71             :  *
      72             :  *    today = new Date();
      73             :  *
      74             :  *    print(today.toLocaleString());
      75             :  *
      76             :  *    weekDay = today.getDay();
      77             :  *
      78             :  *
      79             :  * These Java (and ECMA-262) methods are supported:
      80             :  *
      81             :  *     UTC
      82             :  *     getDate (getUTCDate)
      83             :  *     getDay (getUTCDay)
      84             :  *     getHours (getUTCHours)
      85             :  *     getMinutes (getUTCMinutes)
      86             :  *     getMonth (getUTCMonth)
      87             :  *     getSeconds (getUTCSeconds)
      88             :  *     getMilliseconds (getUTCMilliseconds)
      89             :  *     getTime
      90             :  *     getTimezoneOffset
      91             :  *     getYear
      92             :  *     getFullYear (getUTCFullYear)
      93             :  *     parse
      94             :  *     setDate (setUTCDate)
      95             :  *     setHours (setUTCHours)
      96             :  *     setMinutes (setUTCMinutes)
      97             :  *     setMonth (setUTCMonth)
      98             :  *     setSeconds (setUTCSeconds)
      99             :  *     setMilliseconds (setUTCMilliseconds)
     100             :  *     setTime
     101             :  *     setYear (setFullYear, setUTCFullYear)
     102             :  *     toGMTString (toUTCString)
     103             :  *     toLocaleString
     104             :  *     toString
     105             :  *
     106             :  *
     107             :  * These Java methods are not supported
     108             :  *
     109             :  *     setDay
     110             :  *     before
     111             :  *     after
     112             :  *     equals
     113             :  *     hashCode
     114             :  */
     115             : 
     116             : static inline double
     117           2 : Day(double t)
     118             : {
     119           2 :     return floor(t / msPerDay);
     120             : }
     121             : 
     122             : static double
     123           1 : TimeWithinDay(double t)
     124             : {
     125           1 :     double result = fmod(t, msPerDay);
     126           1 :     if (result < 0)
     127           0 :         result += msPerDay;
     128           1 :     return result;
     129             : }
     130             : 
     131             : /* ES5 15.9.1.3. */
     132             : static inline bool
     133           6 : IsLeapYear(double year)
     134             : {
     135           6 :     MOZ_ASSERT(ToInteger(year) == year);
     136           6 :     return fmod(year, 4) == 0 && (fmod(year, 100) != 0 || fmod(year, 400) == 0);
     137             : }
     138             : 
     139             : static inline double
     140           4 : DaysInYear(double year)
     141             : {
     142           4 :     if (!IsFinite(year))
     143           0 :         return GenericNaN();
     144           4 :     return IsLeapYear(year) ? 366 : 365;
     145             : }
     146             : 
     147             : static inline double
     148           6 : DayFromYear(double y)
     149             : {
     150          12 :     return 365 * (y - 1970) +
     151          12 :            floor((y - 1969) / 4.0) -
     152           6 :            floor((y - 1901) / 100.0) +
     153           6 :            floor((y - 1601) / 400.0);
     154             : }
     155             : 
     156             : static inline double
     157           5 : TimeFromYear(double y)
     158             : {
     159           5 :     return DayFromYear(y) * msPerDay;
     160             : }
     161             : 
     162             : static double
     163           3 : YearFromTime(double t)
     164             : {
     165           3 :     if (!IsFinite(t))
     166           0 :         return GenericNaN();
     167             : 
     168           3 :     MOZ_ASSERT(ToInteger(t) == t);
     169             : 
     170           3 :     double y = floor(t / (msPerDay * 365.2425)) + 1970;
     171           3 :     double t2 = TimeFromYear(y);
     172             : 
     173             :     /*
     174             :      * Adjust the year if the approximation was wrong.  Since the year was
     175             :      * computed using the average number of ms per year, it will usually
     176             :      * be wrong for dates within several hours of a year transition.
     177             :      */
     178           3 :     if (t2 > t) {
     179           0 :         y--;
     180             :     } else {
     181           3 :         if (t2 + msPerDay * DaysInYear(y) <= t)
     182           0 :             y++;
     183             :     }
     184           3 :     return y;
     185             : }
     186             : 
     187             : static inline int
     188           1 : DaysInFebruary(double year)
     189             : {
     190           1 :     return IsLeapYear(year) ? 29 : 28;
     191             : }
     192             : 
     193             : /* ES5 15.9.1.4. */
     194             : static inline double
     195           1 : DayWithinYear(double t, double year)
     196             : {
     197           1 :     MOZ_ASSERT_IF(IsFinite(t), YearFromTime(t) == year);
     198           1 :     return Day(t) - DayFromYear(year);
     199             : }
     200             : 
     201             : static double
     202           1 : MonthFromTime(double t)
     203             : {
     204           1 :     if (!IsFinite(t))
     205           0 :         return GenericNaN();
     206             : 
     207           1 :     double year = YearFromTime(t);
     208           1 :     double d = DayWithinYear(t, year);
     209             : 
     210             :     int step;
     211           1 :     if (d < (step = 31))
     212           0 :         return 0;
     213           1 :     if (d < (step += DaysInFebruary(year)))
     214           0 :         return 1;
     215           1 :     if (d < (step += 31))
     216           0 :         return 2;
     217           1 :     if (d < (step += 30))
     218           0 :         return 3;
     219           1 :     if (d < (step += 31))
     220           0 :         return 4;
     221           1 :     if (d < (step += 30))
     222           0 :         return 5;
     223           1 :     if (d < (step += 31))
     224           1 :         return 6;
     225           0 :     if (d < (step += 31))
     226           0 :         return 7;
     227           0 :     if (d < (step += 30))
     228           0 :         return 8;
     229           0 :     if (d < (step += 31))
     230           0 :         return 9;
     231           0 :     if (d < (step += 30))
     232           0 :         return 10;
     233           0 :     return 11;
     234             : }
     235             : 
     236             : /* ES5 15.9.1.5. */
     237             : static double
     238           0 : DateFromTime(double t)
     239             : {
     240           0 :     if (!IsFinite(t))
     241           0 :         return GenericNaN();
     242             : 
     243           0 :     double year = YearFromTime(t);
     244           0 :     double d = DayWithinYear(t, year);
     245             : 
     246             :     int next;
     247           0 :     if (d <= (next = 30))
     248           0 :         return d + 1;
     249           0 :     int step = next;
     250           0 :     if (d <= (next += DaysInFebruary(year)))
     251           0 :         return d - step;
     252           0 :     step = next;
     253           0 :     if (d <= (next += 31))
     254           0 :         return d - step;
     255           0 :     step = next;
     256           0 :     if (d <= (next += 30))
     257           0 :         return d - step;
     258           0 :     step = next;
     259           0 :     if (d <= (next += 31))
     260           0 :         return d - step;
     261           0 :     step = next;
     262           0 :     if (d <= (next += 30))
     263           0 :         return d - step;
     264           0 :     step = next;
     265           0 :     if (d <= (next += 31))
     266           0 :         return d - step;
     267           0 :     step = next;
     268           0 :     if (d <= (next += 31))
     269           0 :         return d - step;
     270           0 :     step = next;
     271           0 :     if (d <= (next += 30))
     272           0 :         return d - step;
     273           0 :     step = next;
     274           0 :     if (d <= (next += 31))
     275           0 :         return d - step;
     276           0 :     step = next;
     277           0 :     if (d <= (next += 30))
     278           0 :         return d - step;
     279           0 :     step = next;
     280           0 :     return d - step;
     281             : }
     282             : 
     283             : /* ES5 15.9.1.6. */
     284             : static int
     285           1 : WeekDay(double t)
     286             : {
     287             :     /*
     288             :      * We can't assert TimeClip(t) == t because we call this function with
     289             :      * local times, which can be offset outside TimeClip's permitted range.
     290             :      */
     291           1 :     MOZ_ASSERT(ToInteger(t) == t);
     292           1 :     int result = (int(Day(t)) + 4) % 7;
     293           1 :     if (result < 0)
     294           0 :         result += 7;
     295           1 :     return result;
     296             : }
     297             : 
     298             : static inline int
     299           1 : DayFromMonth(int month, bool isLeapYear)
     300             : {
     301             :     /*
     302             :      * The following array contains the day of year for the first day of
     303             :      * each month, where index 0 is January, and day 0 is January 1.
     304             :      */
     305             :     static const int firstDayOfMonth[2][13] = {
     306             :         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
     307             :         {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
     308             :     };
     309             : 
     310           1 :     MOZ_ASSERT(0 <= month && month <= 12);
     311           1 :     return firstDayOfMonth[isLeapYear][month];
     312             : }
     313             : 
     314             : template<typename T>
     315             : static inline int
     316             : DayFromMonth(T month, bool isLeapYear) = delete;
     317             : 
     318             : /* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */
     319             : static double
     320           1 : MakeDay(double year, double month, double date)
     321             : {
     322             :     /* Step 1. */
     323           1 :     if (!IsFinite(year) || !IsFinite(month) || !IsFinite(date))
     324           0 :         return GenericNaN();
     325             : 
     326             :     /* Steps 2-4. */
     327           1 :     double y = ToInteger(year);
     328           1 :     double m = ToInteger(month);
     329           1 :     double dt = ToInteger(date);
     330             : 
     331             :     /* Step 5. */
     332           1 :     double ym = y + floor(m / 12);
     333             : 
     334             :     /* Step 6. */
     335           1 :     int mn = int(fmod(m, 12.0));
     336           1 :     if (mn < 0)
     337           0 :         mn += 12;
     338             : 
     339             :     /* Steps 7-8. */
     340           1 :     bool leap = IsLeapYear(ym);
     341             : 
     342           1 :     double yearday = floor(TimeFromYear(ym) / msPerDay);
     343           1 :     double monthday = DayFromMonth(mn, leap);
     344             : 
     345           1 :     return yearday + monthday + dt - 1;
     346             : }
     347             : 
     348             : /* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */
     349             : static inline double
     350           1 : MakeDate(double day, double time)
     351             : {
     352             :     /* Step 1. */
     353           1 :     if (!IsFinite(day) || !IsFinite(time))
     354           0 :         return GenericNaN();
     355             : 
     356             :     /* Step 2. */
     357           1 :     return day * msPerDay + time;
     358             : }
     359             : 
     360             : JS_PUBLIC_API(double)
     361           0 : JS::MakeDate(double year, unsigned month, unsigned day)
     362             : {
     363           0 :     MOZ_ASSERT(month <= 11);
     364           0 :     MOZ_ASSERT(day >= 1 && day <= 31);
     365             : 
     366           0 :     return ::MakeDate(MakeDay(year, month, day), 0);
     367             : }
     368             : 
     369             : JS_PUBLIC_API(double)
     370           0 : JS::MakeDate(double year, unsigned month, unsigned day, double time)
     371             : {
     372           0 :     MOZ_ASSERT(month <= 11);
     373           0 :     MOZ_ASSERT(day >= 1 && day <= 31);
     374             : 
     375           0 :     return ::MakeDate(MakeDay(year, month, day), time);
     376             : }
     377             : 
     378             : JS_PUBLIC_API(double)
     379           0 : JS::YearFromTime(double time)
     380             : {
     381           0 :     return ::YearFromTime(time);
     382             : }
     383             : 
     384             : JS_PUBLIC_API(double)
     385           0 : JS::MonthFromTime(double time)
     386             : {
     387           0 :     return ::MonthFromTime(time);
     388             : }
     389             : 
     390             : JS_PUBLIC_API(double)
     391           0 : JS::DayFromTime(double time)
     392             : {
     393           0 :     return DateFromTime(time);
     394             : }
     395             : 
     396             : JS_PUBLIC_API(double)
     397           0 : JS::DayFromYear(double year)
     398             : {
     399           0 :     return ::DayFromYear(year);
     400             : }
     401             : 
     402             : JS_PUBLIC_API(double)
     403           0 : JS::DayWithinYear(double time, double year)
     404             : {
     405           0 :     return ::DayWithinYear(time, year);
     406             : }
     407             : 
     408             : JS_PUBLIC_API(void)
     409           0 : JS::SetTimeResolutionUsec(uint32_t resolution)
     410             : {
     411           0 :     sResolutionUsec = resolution;
     412           0 : }
     413             : 
     414             : /*
     415             :  * Find a year for which any given date will fall on the same weekday.
     416             :  *
     417             :  * This function should be used with caution when used other than
     418             :  * for determining DST; it hasn't been proven not to produce an
     419             :  * incorrect year for times near year boundaries.
     420             :  */
     421             : static int
     422           0 : EquivalentYearForDST(int year)
     423             : {
     424             :     /*
     425             :      * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
     426             :      *
     427             :      * yearStartingWith[0][i] is an example non-leap year where
     428             :      * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
     429             :      *
     430             :      * yearStartingWith[1][i] is an example leap year where
     431             :      * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
     432             :      */
     433             :     static const int yearStartingWith[2][7] = {
     434             :         {1978, 1973, 1974, 1975, 1981, 1971, 1977},
     435             :         {1984, 1996, 1980, 1992, 1976, 1988, 1972}
     436             :     };
     437             : 
     438           0 :     int day = int(DayFromYear(year) + 4) % 7;
     439           0 :     if (day < 0)
     440           0 :         day += 7;
     441             : 
     442           0 :     return yearStartingWith[IsLeapYear(year)][day];
     443             : }
     444             : 
     445             : /* ES5 15.9.1.8. */
     446             : static double
     447           3 : DaylightSavingTA(double t)
     448             : {
     449           3 :     if (!IsFinite(t))
     450           0 :         return GenericNaN();
     451             : 
     452             :     /*
     453             :      * If earlier than 1970 or after 2038, potentially beyond the ken of
     454             :      * many OSes, map it to an equivalent year before asking.
     455             :      */
     456           3 :     if (t < 0.0 || t > 2145916800000.0) {
     457           0 :         int year = EquivalentYearForDST(int(YearFromTime(t)));
     458           0 :         double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
     459           0 :         t = MakeDate(day, TimeWithinDay(t));
     460             :     }
     461             : 
     462           3 :     int64_t utcMilliseconds = static_cast<int64_t>(t);
     463           3 :     int64_t offsetMilliseconds = DateTimeInfo::getDSTOffsetMilliseconds(utcMilliseconds);
     464           3 :     return static_cast<double>(offsetMilliseconds);
     465             : }
     466             : 
     467             : static double
     468           3 : AdjustTime(double date)
     469             : {
     470           3 :     double localTZA = DateTimeInfo::localTZA();
     471           3 :     double t = DaylightSavingTA(date) + localTZA;
     472           3 :     t = (localTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
     473           3 :     return t;
     474             : }
     475             : 
     476             : /* ES5 15.9.1.9. */
     477             : static double
     478           2 : LocalTime(double t)
     479             : {
     480           2 :     return t + AdjustTime(t);
     481             : }
     482             : 
     483             : static double
     484           1 : UTC(double t)
     485             : {
     486           1 :     return t - AdjustTime(t - DateTimeInfo::localTZA());
     487             : }
     488             : 
     489             : /* ES5 15.9.1.10. */
     490             : static double
     491           0 : HourFromTime(double t)
     492             : {
     493           0 :     double result = fmod(floor(t/msPerHour), HoursPerDay);
     494           0 :     if (result < 0)
     495           0 :         result += HoursPerDay;
     496           0 :     return result;
     497             : }
     498             : 
     499             : static double
     500           0 : MinFromTime(double t)
     501             : {
     502           0 :     double result = fmod(floor(t / msPerMinute), MinutesPerHour);
     503           0 :     if (result < 0)
     504           0 :         result += MinutesPerHour;
     505           0 :     return result;
     506             : }
     507             : 
     508             : static double
     509           0 : SecFromTime(double t)
     510             : {
     511           0 :     double result = fmod(floor(t / msPerSecond), SecondsPerMinute);
     512           0 :     if (result < 0)
     513           0 :         result += SecondsPerMinute;
     514           0 :     return result;
     515             : }
     516             : 
     517             : static double
     518           0 : msFromTime(double t)
     519             : {
     520           0 :     double result = fmod(t, msPerSecond);
     521           0 :     if (result < 0)
     522           0 :         result += msPerSecond;
     523           0 :     return result;
     524             : }
     525             : 
     526             : /* ES5 15.9.1.11. */
     527             : static double
     528           0 : MakeTime(double hour, double min, double sec, double ms)
     529             : {
     530             :     /* Step 1. */
     531           0 :     if (!IsFinite(hour) ||
     532           0 :         !IsFinite(min) ||
     533           0 :         !IsFinite(sec) ||
     534           0 :         !IsFinite(ms))
     535             :     {
     536           0 :         return GenericNaN();
     537             :     }
     538             : 
     539             :     /* Step 2. */
     540           0 :     double h = ToInteger(hour);
     541             : 
     542             :     /* Step 3. */
     543           0 :     double m = ToInteger(min);
     544             : 
     545             :     /* Step 4. */
     546           0 :     double s = ToInteger(sec);
     547             : 
     548             :     /* Step 5. */
     549           0 :     double milli = ToInteger(ms);
     550             : 
     551             :     /* Steps 6-7. */
     552           0 :     return h * msPerHour + m * msPerMinute + s * msPerSecond + milli;
     553             : }
     554             : 
     555             : /**
     556             :  * end of ECMA 'support' functions
     557             :  */
     558             : 
     559             : /* for use by date_parse */
     560             : 
     561             : static const char* const wtb[] = {
     562             :     "am", "pm",
     563             :     "monday", "tuesday", "wednesday", "thursday", "friday",
     564             :     "saturday", "sunday",
     565             :     "january", "february", "march", "april", "may", "june",
     566             :     "july", "august", "september", "october", "november", "december",
     567             :     "gmt", "ut", "utc",
     568             :     "est", "edt",
     569             :     "cst", "cdt",
     570             :     "mst", "mdt",
     571             :     "pst", "pdt"
     572             :     /* time zone table needs to be expanded */
     573             : };
     574             : 
     575             : static const int ttb[] = {
     576             :     -1, -2, 0, 0, 0, 0, 0, 0, 0,       /* AM/PM */
     577             :     2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
     578             :     10000 + 0, 10000 + 0, 10000 + 0,   /* GMT/UT/UTC */
     579             :     10000 + 5 * 60, 10000 + 4 * 60,    /* EST/EDT */
     580             :     10000 + 6 * 60, 10000 + 5 * 60,    /* CST/CDT */
     581             :     10000 + 7 * 60, 10000 + 6 * 60,    /* MST/MDT */
     582             :     10000 + 8 * 60, 10000 + 7 * 60     /* PST/PDT */
     583             : };
     584             : 
     585             : template <typename CharT>
     586             : static bool
     587           0 : RegionMatches(const char* s1, int s1off, const CharT* s2, int s2off, int count)
     588             : {
     589           0 :     while (count > 0 && s1[s1off] && s2[s2off]) {
     590           0 :         if (unicode::ToLowerCase(s1[s1off]) != unicode::ToLowerCase(s2[s2off]))
     591           0 :             break;
     592             : 
     593           0 :         s1off++;
     594           0 :         s2off++;
     595           0 :         count--;
     596             :     }
     597             : 
     598           0 :     return count == 0;
     599             : }
     600             : 
     601             : // ES2017 draft rev (TODO: Add git hash when PR 642 is merged.)
     602             : // 20.3.3.4
     603             : // Date.UTC(year [, month [, date [, hours [, minutes [, seconds [, ms]]]]]])
     604             : static bool
     605           0 : date_UTC(JSContext* cx, unsigned argc, Value* vp)
     606             : {
     607           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     608             : 
     609             :     // Step 1.
     610             :     double y;
     611           0 :     if (!ToNumber(cx, args.get(0), &y))
     612           0 :         return false;
     613             : 
     614             :     // Step 2.
     615             :     double m;
     616           0 :     if (args.length() >= 2) {
     617           0 :         if (!ToNumber(cx, args[1], &m))
     618           0 :             return false;
     619             :     } else {
     620           0 :         m = 0;
     621             :     }
     622             : 
     623             :     // Step 3.
     624             :     double dt;
     625           0 :     if (args.length() >= 3) {
     626           0 :         if (!ToNumber(cx, args[2], &dt))
     627           0 :             return false;
     628             :     } else {
     629           0 :         dt = 1;
     630             :     }
     631             : 
     632             :     // Step 4.
     633             :     double h;
     634           0 :     if (args.length() >= 4) {
     635           0 :         if (!ToNumber(cx, args[3], &h))
     636           0 :             return false;
     637             :     } else {
     638           0 :         h = 0;
     639             :     }
     640             : 
     641             :     // Step 5.
     642             :     double min;
     643           0 :     if (args.length() >= 5) {
     644           0 :         if (!ToNumber(cx, args[4], &min))
     645           0 :             return false;
     646             :     } else {
     647           0 :         min = 0;
     648             :     }
     649             : 
     650             :     // Step 6.
     651             :     double s;
     652           0 :     if (args.length() >= 6) {
     653           0 :         if (!ToNumber(cx, args[5], &s))
     654           0 :             return false;
     655             :     } else {
     656           0 :         s = 0;
     657             :     }
     658             : 
     659             :     // Step 7.
     660             :     double milli;
     661           0 :     if (args.length() >= 7) {
     662           0 :         if (!ToNumber(cx, args[6], &milli))
     663           0 :             return false;
     664             :     } else {
     665           0 :         milli = 0;
     666             :     }
     667             : 
     668             :     // Step 8.
     669           0 :     double yr = y;
     670           0 :     if (!IsNaN(y)) {
     671           0 :         double yint = ToInteger(y);
     672           0 :         if (0 <= yint && yint <= 99)
     673           0 :             yr = 1900 + yint;
     674             :     }
     675             : 
     676             :     // Step 9.
     677           0 :     ClippedTime time = TimeClip(MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)));
     678           0 :     args.rval().set(TimeValue(time));
     679           0 :     return true;
     680             : }
     681             : 
     682             : /*
     683             :  * Read and convert decimal digits from s[*i] into *result
     684             :  * while *i < limit.
     685             :  *
     686             :  * Succeed if any digits are converted. Advance *i only
     687             :  * as digits are consumed.
     688             :  */
     689             : template <typename CharT>
     690             : static bool
     691           0 : ParseDigits(size_t* result, const CharT* s, size_t* i, size_t limit)
     692             : {
     693           0 :     size_t init = *i;
     694           0 :     *result = 0;
     695           0 :     while (*i < limit && ('0' <= s[*i] && s[*i] <= '9')) {
     696           0 :         *result *= 10;
     697           0 :         *result += (s[*i] - '0');
     698           0 :         ++(*i);
     699             :     }
     700           0 :     return *i != init;
     701             : }
     702             : 
     703             : /*
     704             :  * Read and convert decimal digits to the right of a decimal point,
     705             :  * representing a fractional integer, from s[*i] into *result
     706             :  * while *i < limit.
     707             :  *
     708             :  * Succeed if any digits are converted. Advance *i only
     709             :  * as digits are consumed.
     710             :  */
     711             : template <typename CharT>
     712             : static bool
     713           0 : ParseFractional(double* result, const CharT* s, size_t* i, size_t limit)
     714             : {
     715           0 :     double factor = 0.1;
     716           0 :     size_t init = *i;
     717           0 :     *result = 0.0;
     718           0 :     while (*i < limit && ('0' <= s[*i] && s[*i] <= '9')) {
     719           0 :         *result += (s[*i] - '0') * factor;
     720           0 :         factor *= 0.1;
     721           0 :         ++(*i);
     722             :     }
     723           0 :     return *i != init;
     724             : }
     725             : 
     726             : /*
     727             :  * Read and convert exactly n decimal digits from s[*i]
     728             :  * to s[min(*i+n,limit)] into *result.
     729             :  *
     730             :  * Succeed if exactly n digits are converted. Advance *i only
     731             :  * on success.
     732             :  */
     733             : template <typename CharT>
     734             : static bool
     735           0 : ParseDigitsN(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit)
     736             : {
     737           0 :     size_t init = *i;
     738             : 
     739           0 :     if (ParseDigits(result, s, i, Min(limit, init + n)))
     740           0 :         return (*i - init) == n;
     741             : 
     742           0 :     *i = init;
     743           0 :     return false;
     744             : }
     745             : 
     746             : /*
     747             :  * Read and convert n or less decimal digits from s[*i]
     748             :  * to s[min(*i+n,limit)] into *result.
     749             :  *
     750             :  * Succeed only if greater than zero but less than or equal to n digits are
     751             :  * converted. Advance *i only on success.
     752             :  */
     753             : template <typename CharT>
     754             : static bool
     755           0 : ParseDigitsNOrLess(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit)
     756             : {
     757           0 :     size_t init = *i;
     758             : 
     759           0 :     if (ParseDigits(result, s, i, Min(limit, init + n)))
     760           0 :         return ((*i - init) > 0) && ((*i - init) <= n);
     761             : 
     762           0 :     *i = init;
     763           0 :     return false;
     764             : }
     765             : 
     766             : static int
     767           0 : DaysInMonth(int year, int month)
     768             : {
     769           0 :     bool leap = IsLeapYear(year);
     770           0 :     int result = int(DayFromMonth(month, leap) - DayFromMonth(month - 1, leap));
     771           0 :     return result;
     772             : }
     773             : 
     774             : /*
     775             :  * Parse a string in one of the date-time formats given by the W3C
     776             :  * "NOTE-datetime" specification. These formats make up a restricted
     777             :  * profile of the ISO 8601 format. Quoted here:
     778             :  *
     779             :  *   Any combination of the date formats with the time formats is
     780             :  *   allowed, and also either the date or the time can be missing.
     781             :  *
     782             :  *   The specification is silent on the meaning when fields are
     783             :  *   ommitted so the interpretations are a guess, but hopefully a
     784             :  *   reasonable one. We default the month to January, the day to the
     785             :  *   1st, and hours minutes and seconds all to 0. If the date is
     786             :  *   missing entirely then we assume 1970-01-01 so that the time can
     787             :  *   be aded to a date later. If the time is missing then we assume
     788             :  *   00:00 UTC.  If the time is present but the time zone field is
     789             :  *   missing then we use local time.
     790             :  *
     791             :  * For the sake of cross compatibility with other implementations we
     792             :  * make a few exceptions to the standard: months, days, hours, minutes
     793             :  * and seconds may be either one or two digits long, and the 'T' from
     794             :  * the time part may be replaced with a space. Given that, a date time
     795             :  * like "1999-1-1 1:1:1" will parse successfully.
     796             :  *
     797             :  * Date part:
     798             :  *
     799             :  *  Year:
     800             :  *     YYYY (eg 1997)
     801             :  *
     802             :  *  Year and month:
     803             :  *     YYYY-MM (eg 1997-07)
     804             :  *
     805             :  *  Complete date:
     806             :  *     YYYY-MM-DD (eg 1997-07-16)
     807             :  *
     808             :  * Time part:
     809             :  *
     810             :  *  Hours and minutes:
     811             :  *     Thh:mmTZD (eg T19:20+01:00)
     812             :  *
     813             :  *  Hours, minutes and seconds:
     814             :  *     Thh:mm:ssTZD (eg T19:20:30+01:00)
     815             :  *
     816             :  *  Hours, minutes, seconds and a decimal fraction of a second:
     817             :  *     Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
     818             :  *
     819             :  * where:
     820             :  *
     821             :  *   YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
     822             :  *   MM   = one or two-digit month (01=January, etc.)
     823             :  *   DD   = one or two-digit day of month (01 through 31)
     824             :  *   hh   = one or two digits of hour (00 through 23) (am/pm NOT allowed)
     825             :  *   mm   = one or two digits of minute (00 through 59)
     826             :  *   ss   = one or two digits of second (00 through 59)
     827             :  *   s    = one or more digits representing a decimal fraction of a second
     828             :  *   TZD  = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
     829             :  */
     830             : template <typename CharT>
     831             : static bool
     832           0 : ParseISOStyleDate(const CharT* s, size_t length, ClippedTime* result)
     833             : {
     834           0 :     size_t i = 0;
     835           0 :     int tzMul = 1;
     836           0 :     int dateMul = 1;
     837           0 :     size_t year = 1970;
     838           0 :     size_t month = 1;
     839           0 :     size_t day = 1;
     840           0 :     size_t hour = 0;
     841           0 :     size_t min = 0;
     842           0 :     size_t sec = 0;
     843           0 :     double frac = 0;
     844           0 :     bool isLocalTime = false;
     845           0 :     size_t tzHour = 0;
     846           0 :     size_t tzMin = 0;
     847             : 
     848             : #define PEEK(ch) (i < length && s[i] == ch)
     849             : 
     850             : #define NEED(ch)                                                               \
     851             :     if (i >= length || s[i] != ch) { return false; } else { ++i; }
     852             : 
     853             : #define DONE_DATE_UNLESS(ch)                                                   \
     854             :     if (i >= length || s[i] != ch) { goto done_date; } else { ++i; }
     855             : 
     856             : #define DONE_UNLESS(ch)                                                        \
     857             :     if (i >= length || s[i] != ch) { goto done; } else { ++i; }
     858             : 
     859             : #define NEED_NDIGITS(n, field)                                                 \
     860             :     if (!ParseDigitsN(n, &field, s, &i, length)) { return false; }
     861             : 
     862             : #define NEED_NDIGITS_OR_LESS(n, field)                                         \
     863             :     if (!ParseDigitsNOrLess(n, &field, s, &i, length)) { return false; }
     864             : 
     865           0 :     if (PEEK('+') || PEEK('-')) {
     866           0 :         if (PEEK('-'))
     867           0 :             dateMul = -1;
     868           0 :         ++i;
     869           0 :         NEED_NDIGITS(6, year);
     870           0 :     } else if (!PEEK('T')) {
     871           0 :         NEED_NDIGITS(4, year);
     872             :     }
     873           0 :     DONE_DATE_UNLESS('-');
     874           0 :     NEED_NDIGITS_OR_LESS(2, month);
     875           0 :     DONE_DATE_UNLESS('-');
     876           0 :     NEED_NDIGITS_OR_LESS(2, day);
     877             : 
     878             :  done_date:
     879           0 :     if (PEEK('T') || PEEK(' '))
     880           0 :         i++;
     881             :     else
     882             :         goto done;
     883             : 
     884           0 :     NEED_NDIGITS_OR_LESS(2, hour);
     885           0 :     NEED(':');
     886           0 :     NEED_NDIGITS_OR_LESS(2, min);
     887             : 
     888           0 :     if (PEEK(':')) {
     889           0 :         ++i;
     890           0 :         NEED_NDIGITS_OR_LESS(2, sec);
     891           0 :         if (PEEK('.')) {
     892           0 :             ++i;
     893           0 :             if (!ParseFractional(&frac, s, &i, length))
     894           0 :                 return false;
     895             :         }
     896             :     }
     897             : 
     898           0 :     if (PEEK('Z')) {
     899           0 :         ++i;
     900           0 :     } else if (PEEK('+') || PEEK('-')) {
     901           0 :         if (PEEK('-'))
     902           0 :             tzMul = -1;
     903           0 :         ++i;
     904           0 :         NEED_NDIGITS(2, tzHour);
     905             :         /*
     906             :          * Non-standard extension to the ISO date format (permitted by ES5):
     907             :          * allow "-0700" as a time zone offset, not just "-07:00".
     908             :          */
     909           0 :         if (PEEK(':'))
     910           0 :             ++i;
     911           0 :         NEED_NDIGITS(2, tzMin);
     912             :     } else {
     913           0 :         isLocalTime = true;
     914             :     }
     915             : 
     916             :  done:
     917           0 :     if (year > 275943 // ceil(1e8/365) + 1970
     918           0 :         || (month == 0 || month > 12)
     919           0 :         || (day == 0 || day > size_t(DaysInMonth(year,month)))
     920           0 :         || hour > 24
     921           0 :         || ((hour == 24) && (min > 0 || sec > 0 || frac > 0))
     922           0 :         || min > 59
     923           0 :         || sec > 59
     924           0 :         || tzHour > 23
     925           0 :         || tzMin > 59)
     926             :     {
     927           0 :         return false;
     928             :     }
     929             : 
     930           0 :     if (i != length)
     931           0 :         return false;
     932             : 
     933           0 :     month -= 1; /* convert month to 0-based */
     934             : 
     935           0 :     double msec = MakeDate(MakeDay(dateMul * double(year), month, day),
     936           0 :                            MakeTime(hour, min, sec, frac * 1000.0));
     937             : 
     938           0 :     if (isLocalTime)
     939           0 :         msec = UTC(msec);
     940             :     else
     941           0 :         msec -= tzMul * (tzHour * msPerHour + tzMin * msPerMinute);
     942             : 
     943           0 :     *result = TimeClip(msec);
     944           0 :     return NumbersAreIdentical(msec, result->toDouble());
     945             : 
     946             : #undef PEEK
     947             : #undef NEED
     948             : #undef DONE_UNLESS
     949             : #undef NEED_NDIGITS
     950             : }
     951             : 
     952             : template <typename CharT>
     953             : static bool
     954           0 : ParseDate(const CharT* s, size_t length, ClippedTime* result)
     955             : {
     956           0 :     if (ParseISOStyleDate(s, length, result))
     957           0 :         return true;
     958             : 
     959           0 :     if (length == 0)
     960           0 :         return false;
     961             : 
     962           0 :     int year = -1;
     963           0 :     int mon = -1;
     964           0 :     int mday = -1;
     965           0 :     int hour = -1;
     966           0 :     int min = -1;
     967           0 :     int sec = -1;
     968           0 :     int tzOffset = -1;
     969             : 
     970           0 :     int prevc = 0;
     971             : 
     972           0 :     bool seenPlusMinus = false;
     973           0 :     bool seenMonthName = false;
     974             : 
     975           0 :     size_t i = 0;
     976           0 :     while (i < length) {
     977           0 :         int c = s[i];
     978           0 :         i++;
     979           0 :         if (c <= ' ' || c == ',' || c == '-') {
     980           0 :             if (c == '-' && '0' <= s[i] && s[i] <= '9')
     981           0 :                 prevc = c;
     982           0 :             continue;
     983             :         }
     984           0 :         if (c == '(') { /* comments) */
     985           0 :             int depth = 1;
     986           0 :             while (i < length) {
     987           0 :                 c = s[i];
     988           0 :                 i++;
     989           0 :                 if (c == '(') {
     990           0 :                     depth++;
     991           0 :                 } else if (c == ')') {
     992           0 :                     if (--depth <= 0)
     993           0 :                         break;
     994             :                 }
     995             :             }
     996           0 :             continue;
     997             :         }
     998           0 :         if ('0' <= c && c <= '9') {
     999           0 :             int n = c - '0';
    1000           0 :             while (i < length && '0' <= (c = s[i]) && c <= '9') {
    1001           0 :                 n = n * 10 + c - '0';
    1002           0 :                 i++;
    1003             :             }
    1004             : 
    1005             :             /*
    1006             :              * Allow TZA before the year, so 'Wed Nov 05 21:49:11 GMT-0800 1997'
    1007             :              * works.
    1008             :              *
    1009             :              * Uses of seenPlusMinus allow ':' in TZA, so Java no-timezone style
    1010             :              * of GMT+4:30 works.
    1011             :              */
    1012             : 
    1013           0 :             if ((prevc == '+' || prevc == '-')/*  && year>=0 */) {
    1014             :                 /* Make ':' case below change tzOffset. */
    1015           0 :                 seenPlusMinus = true;
    1016             : 
    1017             :                 /* offset */
    1018           0 :                 if (n < 24)
    1019           0 :                     n = n * 60; /* EG. "GMT-3" */
    1020             :                 else
    1021           0 :                     n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
    1022             : 
    1023           0 :                 if (prevc == '+')       /* plus means east of GMT */
    1024           0 :                     n = -n;
    1025             : 
    1026           0 :                 if (tzOffset != 0 && tzOffset != -1)
    1027           0 :                     return false;
    1028             : 
    1029           0 :                 tzOffset = n;
    1030           0 :             } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
    1031           0 :                 if (c <= ' ' || c == ',' || c == '/' || i >= length)
    1032           0 :                     year = n;
    1033             :                 else
    1034           0 :                     return false;
    1035           0 :             } else if (c == ':') {
    1036           0 :                 if (hour < 0)
    1037           0 :                     hour = /*byte*/ n;
    1038           0 :                 else if (min < 0)
    1039           0 :                     min = /*byte*/ n;
    1040             :                 else
    1041           0 :                     return false;
    1042           0 :             } else if (c == '/') {
    1043             :                 /*
    1044             :                  * Until it is determined that mon is the actual month, keep
    1045             :                  * it as 1-based rather than 0-based.
    1046             :                  */
    1047           0 :                 if (mon < 0)
    1048           0 :                     mon = /*byte*/ n;
    1049           0 :                 else if (mday < 0)
    1050           0 :                     mday = /*byte*/ n;
    1051             :                 else
    1052           0 :                     return false;
    1053           0 :             } else if (i < length && c != ',' && c > ' ' && c != '-' && c != '(') {
    1054           0 :                 return false;
    1055           0 :             } else if (seenPlusMinus && n < 60) {  /* handle GMT-3:30 */
    1056           0 :                 if (tzOffset < 0)
    1057           0 :                     tzOffset -= n;
    1058             :                 else
    1059           0 :                     tzOffset += n;
    1060           0 :             } else if (hour >= 0 && min < 0) {
    1061           0 :                 min = /*byte*/ n;
    1062           0 :             } else if (prevc == ':' && min >= 0 && sec < 0) {
    1063           0 :                 sec = /*byte*/ n;
    1064           0 :             } else if (mon < 0) {
    1065           0 :                 mon = /*byte*/n;
    1066           0 :             } else if (mon >= 0 && mday < 0) {
    1067           0 :                 mday = /*byte*/ n;
    1068           0 :             } else if (mon >= 0 && mday >= 0 && year < 0) {
    1069           0 :                 year = n;
    1070             :             } else {
    1071           0 :                 return false;
    1072             :             }
    1073           0 :             prevc = 0;
    1074           0 :         } else if (c == '/' || c == ':' || c == '+' || c == '-') {
    1075           0 :             prevc = c;
    1076             :         } else {
    1077           0 :             size_t st = i - 1;
    1078           0 :             while (i < length) {
    1079           0 :                 c = s[i];
    1080           0 :                 if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
    1081             :                     break;
    1082           0 :                 i++;
    1083             :             }
    1084             : 
    1085           0 :             if (i <= st + 1)
    1086           0 :                 return false;
    1087             : 
    1088             :             int k;
    1089           0 :             for (k = ArrayLength(wtb); --k >= 0;) {
    1090           0 :                 if (RegionMatches(wtb[k], 0, s, st, i - st)) {
    1091           0 :                     int action = ttb[k];
    1092           0 :                     if (action != 0) {
    1093           0 :                         if (action < 0) {
    1094             :                             /*
    1095             :                              * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
    1096             :                              * 12:30, instead of blindly adding 12 if PM.
    1097             :                              */
    1098           0 :                             MOZ_ASSERT(action == -1 || action == -2);
    1099           0 :                             if (hour > 12 || hour < 0)
    1100           0 :                                 return false;
    1101             : 
    1102           0 :                             if (action == -1 && hour == 12) /* am */
    1103           0 :                                 hour = 0;
    1104           0 :                             else if (action == -2 && hour != 12) /* pm */
    1105           0 :                                 hour += 12;
    1106           0 :                         } else if (action <= 13) { /* month! */
    1107             :                             /*
    1108             :                              * Adjust mon to be 1-based until the final values
    1109             :                              * for mon, mday and year are adjusted below.
    1110             :                              */
    1111           0 :                             if (seenMonthName)
    1112           0 :                                 return false;
    1113             : 
    1114           0 :                             seenMonthName = true;
    1115           0 :                             int temp = /*byte*/ (action - 2) + 1;
    1116             : 
    1117           0 :                             if (mon < 0) {
    1118           0 :                                 mon = temp;
    1119           0 :                             } else if (mday < 0) {
    1120           0 :                                 mday = mon;
    1121           0 :                                 mon = temp;
    1122           0 :                             } else if (year < 0) {
    1123           0 :                                 year = mon;
    1124           0 :                                 mon = temp;
    1125             :                             } else {
    1126           0 :                                 return false;
    1127             :                             }
    1128             :                         } else {
    1129           0 :                             tzOffset = action - 10000;
    1130             :                         }
    1131             :                     }
    1132           0 :                     break;
    1133             :                 }
    1134             :             }
    1135             : 
    1136           0 :             if (k < 0)
    1137           0 :                 return false;
    1138             : 
    1139           0 :             prevc = 0;
    1140             :         }
    1141             :     }
    1142             : 
    1143           0 :     if (year < 0 || mon < 0 || mday < 0)
    1144           0 :         return false;
    1145             : 
    1146             :     /*
    1147             :      * Case 1. The input string contains an English month name.
    1148             :      *         The form of the string can be month f l, or f month l, or
    1149             :      *         f l month which each evaluate to the same date.
    1150             :      *         If f and l are both greater than or equal to 100 the date
    1151             :      *         is invalid.
    1152             :      *
    1153             :      *         The year is taken to be either the greater of the values f, l or
    1154             :      *         whichever is set to zero. If the year is greater than or equal to
    1155             :      *         50 and less than 100, it is considered to be the number of years
    1156             :      *         after 1900. If the year is less than 50 it is considered to be the
    1157             :      *         number of years after 2000, otherwise it is considered to be the
    1158             :      *         number of years after 0.
    1159             :      *
    1160             :      * Case 2. The input string is of the form "f/m/l" where f, m and l are
    1161             :      *         integers, e.g. 7/16/45. mon, mday and year values are adjusted
    1162             :      *         to achieve Chrome compatibility.
    1163             :      *
    1164             :      *         a. If 0 < f <= 12 and 0 < l <= 31, f/m/l is interpreted as
    1165             :      *         month/day/year.
    1166             :      *            i.  If year < 50, it is the number of years after 2000
    1167             :      *            ii. If year >= 50, it is the number of years after 1900.
    1168             :      *           iii. If year >= 100, it is the number of years after 0.
    1169             :      *         b. If 31 < f and 0 < m <= 12 and 0 < l <= 31 f/m/l is
    1170             :      *         interpreted as year/month/day
    1171             :      *            i.  If year < 50, it is the number of years after 2000
    1172             :      *            ii. If year >= 50, it is the number of years after 1900.
    1173             :      *           iii. If year >= 100, it is the number of years after 0.
    1174             :      */
    1175           0 :     if (seenMonthName) {
    1176           0 :         if (mday >= 100 && mon >= 100)
    1177           0 :             return false;
    1178             : 
    1179           0 :         if (year > 0 && (mday == 0 || mday > year)) {
    1180           0 :             int temp = year;
    1181           0 :             year = mday;
    1182           0 :             mday = temp;
    1183             :         }
    1184             : 
    1185           0 :         if (mday <= 0 || mday > 31)
    1186           0 :             return false;
    1187             : 
    1188           0 :     } else if (0 < mon && mon <= 12 && 0 < mday && mday <= 31) {
    1189             :         /* (a) month/day/year */
    1190             :     } else {
    1191             :         /* (b) year/month/day */
    1192           0 :         if (mon > 31 && mday <= 12 && year <= 31) {
    1193           0 :             int temp = year;
    1194           0 :             year = mon;
    1195           0 :             mon = mday;
    1196           0 :             mday = temp;
    1197             :         } else {
    1198           0 :             return false;
    1199             :         }
    1200             :     }
    1201             : 
    1202           0 :     if (year < 50)
    1203           0 :         year += 2000;
    1204           0 :     else if (year >= 50 && year < 100)
    1205           0 :         year += 1900;
    1206             : 
    1207           0 :     mon -= 1; /* convert month to 0-based */
    1208           0 :     if (sec < 0)
    1209           0 :         sec = 0;
    1210           0 :     if (min < 0)
    1211           0 :         min = 0;
    1212           0 :     if (hour < 0)
    1213           0 :         hour = 0;
    1214             : 
    1215           0 :     double msec = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0));
    1216             : 
    1217           0 :     if (tzOffset == -1) /* no time zone specified, have to use local */
    1218           0 :         msec = UTC(msec);
    1219             :     else
    1220           0 :         msec += tzOffset * msPerMinute;
    1221             : 
    1222           0 :     *result = TimeClip(msec);
    1223           0 :     return true;
    1224             : }
    1225             : 
    1226             : static bool
    1227           0 : ParseDate(JSLinearString* s, ClippedTime* result)
    1228             : {
    1229           0 :     AutoCheckCannotGC nogc;
    1230           0 :     return s->hasLatin1Chars()
    1231           0 :            ? ParseDate(s->latin1Chars(nogc), s->length(), result)
    1232           0 :            : ParseDate(s->twoByteChars(nogc), s->length(), result);
    1233             : }
    1234             : 
    1235             : static bool
    1236           0 : date_parse(JSContext* cx, unsigned argc, Value* vp)
    1237             : {
    1238           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1239           0 :     if (args.length() == 0) {
    1240           0 :         args.rval().setNaN();
    1241           0 :         return true;
    1242             :     }
    1243             : 
    1244           0 :     JSString* str = ToString<CanGC>(cx, args[0]);
    1245           0 :     if (!str)
    1246           0 :         return false;
    1247             : 
    1248           0 :     JSLinearString* linearStr = str->ensureLinear(cx);
    1249           0 :     if (!linearStr)
    1250           0 :         return false;
    1251             : 
    1252           0 :     ClippedTime result;
    1253           0 :     if (!ParseDate(linearStr, &result)) {
    1254           0 :         args.rval().setNaN();
    1255           0 :         return true;
    1256             :     }
    1257             : 
    1258           0 :     args.rval().set(TimeValue(result));
    1259           0 :     return true;
    1260             : }
    1261             : 
    1262             : static ClippedTime
    1263          65 : NowAsMillis()
    1264             : {
    1265          65 :     double now = PRMJ_Now();
    1266          65 :     if (sResolutionUsec) {
    1267           0 :         now = floor(now / sResolutionUsec) * sResolutionUsec;
    1268             :     }
    1269          65 :     return TimeClip(now / PRMJ_USEC_PER_MSEC);
    1270             : }
    1271             : 
    1272             : bool
    1273          35 : js::date_now(JSContext* cx, unsigned argc, Value* vp)
    1274             : {
    1275          35 :     CallArgs args = CallArgsFromVp(argc, vp);
    1276          35 :     args.rval().set(TimeValue(NowAsMillis()));
    1277          35 :     return true;
    1278             : }
    1279             : 
    1280             : void
    1281          85 : DateObject::setUTCTime(ClippedTime t)
    1282             : {
    1283         595 :     for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++)
    1284         510 :         setReservedSlot(ind, UndefinedValue());
    1285             : 
    1286          85 :     setFixedSlot(UTC_TIME_SLOT, TimeValue(t));
    1287          85 : }
    1288             : 
    1289             : void
    1290           1 : DateObject::setUTCTime(ClippedTime t, MutableHandleValue vp)
    1291             : {
    1292           1 :     setUTCTime(t);
    1293           1 :     vp.set(TimeValue(t));
    1294           1 : }
    1295             : 
    1296             : void
    1297           1 : DateObject::fillLocalTimeSlots()
    1298             : {
    1299             :     /* Check if the cache is already populated. */
    1300           1 :     if (!getReservedSlot(LOCAL_TIME_SLOT).isUndefined() &&
    1301           0 :         getReservedSlot(TZA_SLOT).toDouble() == DateTimeInfo::localTZA())
    1302             :     {
    1303           0 :         return;
    1304             :     }
    1305             : 
    1306             :     /* Remember time zone used to generate the local cache. */
    1307           1 :     setReservedSlot(TZA_SLOT, DoubleValue(DateTimeInfo::localTZA()));
    1308             : 
    1309           1 :     double utcTime = UTCTime().toNumber();
    1310             : 
    1311           1 :     if (!IsFinite(utcTime)) {
    1312           0 :         for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++)
    1313           0 :             setReservedSlot(ind, DoubleValue(utcTime));
    1314           0 :         return;
    1315             :     }
    1316             : 
    1317           1 :     double localTime = LocalTime(utcTime);
    1318             : 
    1319           1 :     setReservedSlot(LOCAL_TIME_SLOT, DoubleValue(localTime));
    1320             : 
    1321           1 :     int year = (int) floor(localTime /(msPerDay * 365.2425)) + 1970;
    1322           1 :     double yearStartTime = TimeFromYear(year);
    1323             : 
    1324             :     /* Adjust the year in case the approximation was wrong, as in YearFromTime. */
    1325             :     int yearDays;
    1326           1 :     if (yearStartTime > localTime) {
    1327           0 :         year--;
    1328           0 :         yearStartTime -= (msPerDay * DaysInYear(year));
    1329           0 :         yearDays = DaysInYear(year);
    1330             :     } else {
    1331           1 :         yearDays = DaysInYear(year);
    1332           1 :         double nextStart = yearStartTime + (msPerDay * yearDays);
    1333           1 :         if (nextStart <= localTime) {
    1334           0 :             year++;
    1335           0 :             yearStartTime = nextStart;
    1336           0 :             yearDays = DaysInYear(year);
    1337             :         }
    1338             :     }
    1339             : 
    1340           1 :     setReservedSlot(LOCAL_YEAR_SLOT, Int32Value(year));
    1341             : 
    1342           1 :     uint64_t yearTime = uint64_t(localTime - yearStartTime);
    1343           1 :     int yearSeconds = uint32_t(yearTime / 1000);
    1344             : 
    1345           1 :     int day = yearSeconds / int(SecondsPerDay);
    1346             : 
    1347           1 :     int step = -1, next = 30;
    1348             :     int month;
    1349             : 
    1350             :     do {
    1351           1 :         if (day <= next) {
    1352           0 :             month = 0;
    1353           0 :             break;
    1354             :         }
    1355           1 :         step = next;
    1356           1 :         next += ((yearDays == 366) ? 29 : 28);
    1357           1 :         if (day <= next) {
    1358           0 :             month = 1;
    1359           0 :             break;
    1360             :         }
    1361           1 :         step = next;
    1362           1 :         if (day <= (next += 31)) {
    1363           0 :             month = 2;
    1364           0 :             break;
    1365             :         }
    1366           1 :         step = next;
    1367           1 :         if (day <= (next += 30)) {
    1368           0 :             month = 3;
    1369           0 :             break;
    1370             :         }
    1371           1 :         step = next;
    1372           1 :         if (day <= (next += 31)) {
    1373           0 :             month = 4;
    1374           0 :             break;
    1375             :         }
    1376           1 :         step = next;
    1377           1 :         if (day <= (next += 30)) {
    1378           0 :             month = 5;
    1379           0 :             break;
    1380             :         }
    1381           1 :         step = next;
    1382           1 :         if (day <= (next += 31)) {
    1383           1 :             month = 6;
    1384           1 :             break;
    1385             :         }
    1386           0 :         step = next;
    1387           0 :         if (day <= (next += 31)) {
    1388           0 :             month = 7;
    1389           0 :             break;
    1390             :         }
    1391           0 :         step = next;
    1392           0 :         if (day <= (next += 30)) {
    1393           0 :             month = 8;
    1394           0 :             break;
    1395             :         }
    1396           0 :         step = next;
    1397           0 :         if (day <= (next += 31)) {
    1398           0 :             month = 9;
    1399           0 :             break;
    1400             :         }
    1401           0 :         step = next;
    1402           0 :         if (day <= (next += 30)) {
    1403           0 :             month = 10;
    1404           0 :             break;
    1405             :         }
    1406           0 :         step = next;
    1407           0 :         month = 11;
    1408             :     } while (0);
    1409             : 
    1410           1 :     setReservedSlot(LOCAL_MONTH_SLOT, Int32Value(month));
    1411           1 :     setReservedSlot(LOCAL_DATE_SLOT, Int32Value(day - step));
    1412             : 
    1413           1 :     int weekday = WeekDay(localTime);
    1414           1 :     setReservedSlot(LOCAL_DAY_SLOT, Int32Value(weekday));
    1415             : 
    1416           1 :     setReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT, Int32Value(yearSeconds));
    1417             : }
    1418             : 
    1419             : inline double
    1420           0 : DateObject::cachedLocalTime()
    1421             : {
    1422           0 :     fillLocalTimeSlots();
    1423           0 :     return getReservedSlot(LOCAL_TIME_SLOT).toDouble();
    1424             : }
    1425             : 
    1426             : MOZ_ALWAYS_INLINE bool
    1427          49 : IsDate(HandleValue v)
    1428             : {
    1429          49 :     return v.isObject() && v.toObject().is<DateObject>();
    1430             : }
    1431             : 
    1432             : /*
    1433             :  * See ECMA 15.9.5.4 thru 15.9.5.23
    1434             :  */
    1435             : /* static */ MOZ_ALWAYS_INLINE bool
    1436          16 : DateObject::getTime_impl(JSContext* cx, const CallArgs& args)
    1437             : {
    1438          16 :     args.rval().set(args.thisv().toObject().as<DateObject>().UTCTime());
    1439          16 :     return true;
    1440             : }
    1441             : 
    1442             : static bool
    1443          16 : date_getTime(JSContext* cx, unsigned argc, Value* vp)
    1444             : {
    1445          16 :     CallArgs args = CallArgsFromVp(argc, vp);
    1446          16 :     return CallNonGenericMethod<IsDate, DateObject::getTime_impl>(cx, args);
    1447             : }
    1448             : 
    1449             : /* static */ MOZ_ALWAYS_INLINE bool
    1450           0 : DateObject::getYear_impl(JSContext* cx, const CallArgs& args)
    1451             : {
    1452           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1453           0 :     dateObj->fillLocalTimeSlots();
    1454             : 
    1455           0 :     Value yearVal = dateObj->getReservedSlot(LOCAL_YEAR_SLOT);
    1456           0 :     if (yearVal.isInt32()) {
    1457             :         /* Follow ECMA-262 to the letter, contrary to IE JScript. */
    1458           0 :         int year = yearVal.toInt32() - 1900;
    1459           0 :         args.rval().setInt32(year);
    1460             :     } else {
    1461           0 :         args.rval().set(yearVal);
    1462             :     }
    1463             : 
    1464           0 :     return true;
    1465             : }
    1466             : 
    1467             : static bool
    1468           0 : date_getYear(JSContext* cx, unsigned argc, Value* vp)
    1469             : {
    1470           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1471           0 :     return CallNonGenericMethod<IsDate, DateObject::getYear_impl>(cx, args);
    1472             : }
    1473             : 
    1474             : /* static */ MOZ_ALWAYS_INLINE bool
    1475           0 : DateObject::getFullYear_impl(JSContext* cx, const CallArgs& args)
    1476             : {
    1477           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1478           0 :     dateObj->fillLocalTimeSlots();
    1479             : 
    1480           0 :     args.rval().set(dateObj->getReservedSlot(LOCAL_YEAR_SLOT));
    1481           0 :     return true;
    1482             : }
    1483             : 
    1484             : static bool
    1485           0 : date_getFullYear(JSContext* cx, unsigned argc, Value* vp)
    1486             : {
    1487           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1488           0 :     return CallNonGenericMethod<IsDate, DateObject::getFullYear_impl>(cx, args);
    1489             : }
    1490             : 
    1491             : /* static */ MOZ_ALWAYS_INLINE bool
    1492           0 : DateObject::getUTCFullYear_impl(JSContext* cx, const CallArgs& args)
    1493             : {
    1494           0 :     double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1495           0 :     if (IsFinite(result))
    1496           0 :         result = YearFromTime(result);
    1497             : 
    1498           0 :     args.rval().setNumber(result);
    1499           0 :     return true;
    1500             : }
    1501             : 
    1502             : static bool
    1503           0 : date_getUTCFullYear(JSContext* cx, unsigned argc, Value* vp)
    1504             : {
    1505           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1506           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCFullYear_impl>(cx, args);
    1507             : }
    1508             : 
    1509             : /* static */ MOZ_ALWAYS_INLINE bool
    1510           0 : DateObject::getMonth_impl(JSContext* cx, const CallArgs& args)
    1511             : {
    1512           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1513           0 :     dateObj->fillLocalTimeSlots();
    1514             : 
    1515           0 :     args.rval().set(dateObj->getReservedSlot(LOCAL_MONTH_SLOT));
    1516           0 :     return true;
    1517             : }
    1518             : 
    1519             : static bool
    1520           0 : date_getMonth(JSContext* cx, unsigned argc, Value* vp)
    1521             : {
    1522           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1523           0 :     return CallNonGenericMethod<IsDate, DateObject::getMonth_impl>(cx, args);
    1524             : }
    1525             : 
    1526             : /* static */ MOZ_ALWAYS_INLINE bool
    1527           0 : DateObject::getUTCMonth_impl(JSContext* cx, const CallArgs& args)
    1528             : {
    1529           0 :     double d = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1530           0 :     args.rval().setNumber(MonthFromTime(d));
    1531           0 :     return true;
    1532             : }
    1533             : 
    1534             : static bool
    1535           0 : date_getUTCMonth(JSContext* cx, unsigned argc, Value* vp)
    1536             : {
    1537           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1538           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCMonth_impl>(cx, args);
    1539             : }
    1540             : 
    1541             : /* static */ MOZ_ALWAYS_INLINE bool
    1542           1 : DateObject::getDate_impl(JSContext* cx, const CallArgs& args)
    1543             : {
    1544           1 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1545           1 :     dateObj->fillLocalTimeSlots();
    1546             : 
    1547           1 :     args.rval().set(dateObj->getReservedSlot(LOCAL_DATE_SLOT));
    1548           1 :     return true;
    1549             : }
    1550             : 
    1551             : static bool
    1552           1 : date_getDate(JSContext* cx, unsigned argc, Value* vp)
    1553             : {
    1554           1 :     CallArgs args = CallArgsFromVp(argc, vp);
    1555           1 :     return CallNonGenericMethod<IsDate, DateObject::getDate_impl>(cx, args);
    1556             : }
    1557             : 
    1558             : /* static */ MOZ_ALWAYS_INLINE bool
    1559           0 : DateObject::getUTCDate_impl(JSContext* cx, const CallArgs& args)
    1560             : {
    1561           0 :     double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1562           0 :     if (IsFinite(result))
    1563           0 :         result = DateFromTime(result);
    1564             : 
    1565           0 :     args.rval().setNumber(result);
    1566           0 :     return true;
    1567             : }
    1568             : 
    1569             : static bool
    1570           0 : date_getUTCDate(JSContext* cx, unsigned argc, Value* vp)
    1571             : {
    1572           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1573           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCDate_impl>(cx, args);
    1574             : }
    1575             : 
    1576             : /* static */ MOZ_ALWAYS_INLINE bool
    1577           0 : DateObject::getDay_impl(JSContext* cx, const CallArgs& args)
    1578             : {
    1579           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1580           0 :     dateObj->fillLocalTimeSlots();
    1581             : 
    1582           0 :     args.rval().set(dateObj->getReservedSlot(LOCAL_DAY_SLOT));
    1583           0 :     return true;
    1584             : }
    1585             : 
    1586             : static bool
    1587           0 : date_getDay(JSContext* cx, unsigned argc, Value* vp)
    1588             : {
    1589           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1590           0 :     return CallNonGenericMethod<IsDate, DateObject::getDay_impl>(cx, args);
    1591             : }
    1592             : 
    1593             : /* static */ MOZ_ALWAYS_INLINE bool
    1594           0 : DateObject::getUTCDay_impl(JSContext* cx, const CallArgs& args)
    1595             : {
    1596           0 :     double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1597           0 :     if (IsFinite(result))
    1598           0 :         result = WeekDay(result);
    1599             : 
    1600           0 :     args.rval().setNumber(result);
    1601           0 :     return true;
    1602             : }
    1603             : 
    1604             : static bool
    1605           0 : date_getUTCDay(JSContext* cx, unsigned argc, Value* vp)
    1606             : {
    1607           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1608           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCDay_impl>(cx, args);
    1609             : }
    1610             : 
    1611             : /* static */ MOZ_ALWAYS_INLINE bool
    1612           0 : DateObject::getHours_impl(JSContext* cx, const CallArgs& args)
    1613             : {
    1614           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1615           0 :     dateObj->fillLocalTimeSlots();
    1616             : 
    1617             :     // Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an
    1618             :     // int32 or NaN after the call to fillLocalTimeSlots.
    1619           0 :     Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT);
    1620           0 :     if (yearSeconds.isDouble()) {
    1621           0 :         MOZ_ASSERT(IsNaN(yearSeconds.toDouble()));
    1622           0 :         args.rval().set(yearSeconds);
    1623             :     } else {
    1624           0 :         args.rval().setInt32((yearSeconds.toInt32() / int(SecondsPerHour)) % int(HoursPerDay));
    1625             :     }
    1626           0 :     return true;
    1627             : }
    1628             : 
    1629             : static bool
    1630           0 : date_getHours(JSContext* cx, unsigned argc, Value* vp)
    1631             : {
    1632           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1633           0 :     return CallNonGenericMethod<IsDate, DateObject::getHours_impl>(cx, args);
    1634             : }
    1635             : 
    1636             : /* static */ MOZ_ALWAYS_INLINE bool
    1637           0 : DateObject::getUTCHours_impl(JSContext* cx, const CallArgs& args)
    1638             : {
    1639           0 :     double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1640           0 :     if (IsFinite(result))
    1641           0 :         result = HourFromTime(result);
    1642             : 
    1643           0 :     args.rval().setNumber(result);
    1644           0 :     return true;
    1645             : }
    1646             : 
    1647             : static bool
    1648           0 : date_getUTCHours(JSContext* cx, unsigned argc, Value* vp)
    1649             : {
    1650           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1651           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCHours_impl>(cx, args);
    1652             : }
    1653             : 
    1654             : /* static */ MOZ_ALWAYS_INLINE bool
    1655           0 : DateObject::getMinutes_impl(JSContext* cx, const CallArgs& args)
    1656             : {
    1657           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1658           0 :     dateObj->fillLocalTimeSlots();
    1659             : 
    1660             :     // Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an
    1661             :     // int32 or NaN after the call to fillLocalTimeSlots.
    1662           0 :     Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT);
    1663           0 :     if (yearSeconds.isDouble()) {
    1664           0 :         MOZ_ASSERT(IsNaN(yearSeconds.toDouble()));
    1665           0 :         args.rval().set(yearSeconds);
    1666             :     } else {
    1667           0 :         args.rval().setInt32((yearSeconds.toInt32() / int(SecondsPerMinute)) % int(MinutesPerHour));
    1668             :     }
    1669           0 :     return true;
    1670             : }
    1671             : 
    1672             : static bool
    1673           0 : date_getMinutes(JSContext* cx, unsigned argc, Value* vp)
    1674             : {
    1675           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1676           0 :     return CallNonGenericMethod<IsDate, DateObject::getMinutes_impl>(cx, args);
    1677             : }
    1678             : 
    1679             : /* static */ MOZ_ALWAYS_INLINE bool
    1680           0 : DateObject::getUTCMinutes_impl(JSContext* cx, const CallArgs& args)
    1681             : {
    1682           0 :     double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1683           0 :     if (IsFinite(result))
    1684           0 :         result = MinFromTime(result);
    1685             : 
    1686           0 :     args.rval().setNumber(result);
    1687           0 :     return true;
    1688             : }
    1689             : 
    1690             : static bool
    1691           0 : date_getUTCMinutes(JSContext* cx, unsigned argc, Value* vp)
    1692             : {
    1693           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1694           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCMinutes_impl>(cx, args);
    1695             : }
    1696             : 
    1697             : /*
    1698             :  * Date.getSeconds is mapped to getUTCSeconds. As long as no supported time
    1699             :  * zone has a fractional-minute component, the differences in their
    1700             :  * specifications aren't observable.
    1701             :  *
    1702             :  * We'll have to split the implementations if a new time zone with a
    1703             :  * fractional-minute component is introduced or once we implement ES6's
    1704             :  * 20.3.1.7 Local Time Zone Adjustment: time zones with adjustments like that
    1705             :  * did historically exist, e.g.
    1706             :  * https://en.wikipedia.org/wiki/UTC%E2%88%9200:25:21
    1707             :  */
    1708             : 
    1709             : /* static */ MOZ_ALWAYS_INLINE bool
    1710           0 : DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args)
    1711             : {
    1712           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1713           0 :     dateObj->fillLocalTimeSlots();
    1714             : 
    1715             :     // Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an
    1716             :     // int32 or NaN after the call to fillLocalTimeSlots.
    1717           0 :     Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT);
    1718           0 :     if (yearSeconds.isDouble()) {
    1719           0 :         MOZ_ASSERT(IsNaN(yearSeconds.toDouble()));
    1720           0 :         args.rval().set(yearSeconds);
    1721             :     } else {
    1722           0 :         args.rval().setInt32(yearSeconds.toInt32() % int(SecondsPerMinute));
    1723             :     }
    1724           0 :     return true;
    1725             : }
    1726             : 
    1727             : static bool
    1728           0 : date_getUTCSeconds(JSContext* cx, unsigned argc, Value* vp)
    1729             : {
    1730           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1731           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCSeconds_impl>(cx, args);
    1732             : }
    1733             : /*
    1734             :  * Date.getMilliseconds is mapped to getUTCMilliseconds for the same reasons
    1735             :  * that getSeconds is mapped to getUTCSeconds (see above).  No known LocalTZA
    1736             :  * has *ever* included a fractional-second component, however, so we can keep
    1737             :  * this simplification even if we stop implementing ES5 local-time computation
    1738             :  * semantics.
    1739             :  */
    1740             : 
    1741             : /* static */ MOZ_ALWAYS_INLINE bool
    1742           0 : DateObject::getUTCMilliseconds_impl(JSContext* cx, const CallArgs& args)
    1743             : {
    1744           0 :     double result = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    1745           0 :     if (IsFinite(result))
    1746           0 :         result = msFromTime(result);
    1747             : 
    1748           0 :     args.rval().setNumber(result);
    1749           0 :     return true;
    1750             : }
    1751             : 
    1752             : static bool
    1753           0 : date_getUTCMilliseconds(JSContext* cx, unsigned argc, Value* vp)
    1754             : {
    1755           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1756           0 :     return CallNonGenericMethod<IsDate, DateObject::getUTCMilliseconds_impl>(cx, args);
    1757             : }
    1758             : 
    1759             : /* static */ MOZ_ALWAYS_INLINE bool
    1760           0 : DateObject::getTimezoneOffset_impl(JSContext* cx, const CallArgs& args)
    1761             : {
    1762           0 :     DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
    1763           0 :     double utctime = dateObj->UTCTime().toNumber();
    1764           0 :     double localtime = dateObj->cachedLocalTime();
    1765             : 
    1766             :     /*
    1767             :      * Return the time zone offset in minutes for the current locale that is
    1768             :      * appropriate for this time. This value would be a constant except for
    1769             :      * daylight savings time.
    1770             :      */
    1771           0 :     double result = (utctime - localtime) / msPerMinute;
    1772           0 :     args.rval().setNumber(result);
    1773           0 :     return true;
    1774             : }
    1775             : 
    1776             : static bool
    1777           0 : date_getTimezoneOffset(JSContext* cx, unsigned argc, Value* vp)
    1778             : {
    1779           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1780           0 :     return CallNonGenericMethod<IsDate, DateObject::getTimezoneOffset_impl>(cx, args);
    1781             : }
    1782             : 
    1783             : MOZ_ALWAYS_INLINE bool
    1784           0 : date_setTime_impl(JSContext* cx, const CallArgs& args)
    1785             : {
    1786           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    1787           0 :     if (args.length() == 0) {
    1788           0 :         dateObj->setUTCTime(ClippedTime::invalid(), args.rval());
    1789           0 :         return true;
    1790             :     }
    1791             : 
    1792             :     double result;
    1793           0 :     if (!ToNumber(cx, args[0], &result))
    1794           0 :         return false;
    1795             : 
    1796           0 :     dateObj->setUTCTime(TimeClip(result), args.rval());
    1797           0 :     return true;
    1798             : }
    1799             : 
    1800             : static bool
    1801           0 : date_setTime(JSContext* cx, unsigned argc, Value* vp)
    1802             : {
    1803           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1804           0 :     return CallNonGenericMethod<IsDate, date_setTime_impl>(cx, args);
    1805             : }
    1806             : 
    1807             : static bool
    1808           0 : GetMsecsOrDefault(JSContext* cx, const CallArgs& args, unsigned i, double t, double* millis)
    1809             : {
    1810           0 :     if (args.length() <= i) {
    1811           0 :         *millis = msFromTime(t);
    1812           0 :         return true;
    1813             :     }
    1814           0 :     return ToNumber(cx, args[i], millis);
    1815             : }
    1816             : 
    1817             : static bool
    1818           0 : GetSecsOrDefault(JSContext* cx, const CallArgs& args, unsigned i, double t, double* sec)
    1819             : {
    1820           0 :     if (args.length() <= i) {
    1821           0 :         *sec = SecFromTime(t);
    1822           0 :         return true;
    1823             :     }
    1824           0 :     return ToNumber(cx, args[i], sec);
    1825             : }
    1826             : 
    1827             : static bool
    1828           0 : GetMinsOrDefault(JSContext* cx, const CallArgs& args, unsigned i, double t, double* mins)
    1829             : {
    1830           0 :     if (args.length() <= i) {
    1831           0 :         *mins = MinFromTime(t);
    1832           0 :         return true;
    1833             :     }
    1834           0 :     return ToNumber(cx, args[i], mins);
    1835             : }
    1836             : 
    1837             : /* ES6 20.3.4.23. */
    1838             : MOZ_ALWAYS_INLINE bool
    1839           0 : date_setMilliseconds_impl(JSContext* cx, const CallArgs& args)
    1840             : {
    1841           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    1842             : 
    1843             :     // Steps 1-2.
    1844           0 :     double t = LocalTime(dateObj->UTCTime().toNumber());
    1845             : 
    1846             :     // Steps 3-4.
    1847             :     double ms;
    1848           0 :     if (!ToNumber(cx, args.get(0), &ms))
    1849           0 :         return false;
    1850             : 
    1851             :     // Step 5.
    1852           0 :     double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms);
    1853             : 
    1854             :     // Step 6.
    1855           0 :     ClippedTime u = TimeClip(UTC(MakeDate(Day(t), time)));
    1856             : 
    1857             :     // Steps 7-8.
    1858           0 :     dateObj->setUTCTime(u, args.rval());
    1859           0 :     return true;
    1860             : }
    1861             : 
    1862             : static bool
    1863           0 : date_setMilliseconds(JSContext* cx, unsigned argc, Value* vp)
    1864             : {
    1865           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1866           0 :     return CallNonGenericMethod<IsDate, date_setMilliseconds_impl>(cx, args);
    1867             : }
    1868             : 
    1869             : /* ES5 15.9.5.29. */
    1870             : MOZ_ALWAYS_INLINE bool
    1871           0 : date_setUTCMilliseconds_impl(JSContext* cx, const CallArgs& args)
    1872             : {
    1873           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    1874             : 
    1875             :     /* Step 1. */
    1876           0 :     double t = dateObj->UTCTime().toNumber();
    1877             : 
    1878             :     /* Step 2. */
    1879             :     double milli;
    1880           0 :     if (!ToNumber(cx, args.get(0), &milli))
    1881           0 :         return false;
    1882           0 :     double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli);
    1883             : 
    1884             :     /* Step 3. */
    1885           0 :     ClippedTime v = TimeClip(MakeDate(Day(t), time));
    1886             : 
    1887             :     /* Steps 4-5. */
    1888           0 :     dateObj->setUTCTime(v, args.rval());
    1889           0 :     return true;
    1890             : }
    1891             : 
    1892             : static bool
    1893           0 : date_setUTCMilliseconds(JSContext* cx, unsigned argc, Value* vp)
    1894             : {
    1895           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1896           0 :     return CallNonGenericMethod<IsDate, date_setUTCMilliseconds_impl>(cx, args);
    1897             : }
    1898             : 
    1899             : /* ES5 15.9.5.30. */
    1900             : MOZ_ALWAYS_INLINE bool
    1901           0 : date_setSeconds_impl(JSContext* cx, const CallArgs& args)
    1902             : {
    1903           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    1904             : 
    1905             :     // Steps 1-2.
    1906           0 :     double t = LocalTime(dateObj->UTCTime().toNumber());
    1907             : 
    1908             :     // Steps 3-4.
    1909             :     double s;
    1910           0 :     if (!ToNumber(cx, args.get(0), &s))
    1911           0 :         return false;
    1912             : 
    1913             :     // Steps 5-6.
    1914             :     double milli;
    1915           0 :     if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
    1916           0 :         return false;
    1917             : 
    1918             :     // Step 7.
    1919           0 :     double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
    1920             : 
    1921             :     // Step 8.
    1922           0 :     ClippedTime u = TimeClip(UTC(date));
    1923             : 
    1924             :     // Step 9.
    1925           0 :     dateObj->setUTCTime(u, args.rval());
    1926           0 :     return true;
    1927             : }
    1928             : 
    1929             : /* ES6 20.3.4.26. */
    1930             : static bool
    1931           0 : date_setSeconds(JSContext* cx, unsigned argc, Value* vp)
    1932             : {
    1933           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1934           0 :     return CallNonGenericMethod<IsDate, date_setSeconds_impl>(cx, args);
    1935             : }
    1936             : 
    1937             : MOZ_ALWAYS_INLINE bool
    1938           0 : date_setUTCSeconds_impl(JSContext* cx, const CallArgs& args)
    1939             : {
    1940           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    1941             : 
    1942             :     /* Step 1. */
    1943           0 :     double t = dateObj->UTCTime().toNumber();
    1944             : 
    1945             :     /* Step 2. */
    1946             :     double s;
    1947           0 :     if (!ToNumber(cx, args.get(0), &s))
    1948           0 :         return false;
    1949             : 
    1950             :     /* Step 3. */
    1951             :     double milli;
    1952           0 :     if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
    1953           0 :         return false;
    1954             : 
    1955             :     /* Step 4. */
    1956           0 :     double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
    1957             : 
    1958             :     /* Step 5. */
    1959           0 :     ClippedTime v = TimeClip(date);
    1960             : 
    1961             :     /* Steps 6-7. */
    1962           0 :     dateObj->setUTCTime(v, args.rval());
    1963           0 :     return true;
    1964             : }
    1965             : 
    1966             : /* ES5 15.9.5.32. */
    1967             : static bool
    1968           0 : date_setUTCSeconds(JSContext* cx, unsigned argc, Value* vp)
    1969             : {
    1970           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1971           0 :     return CallNonGenericMethod<IsDate, date_setUTCSeconds_impl>(cx, args);
    1972             : }
    1973             : 
    1974             : MOZ_ALWAYS_INLINE bool
    1975           0 : date_setMinutes_impl(JSContext* cx, const CallArgs& args)
    1976             : {
    1977           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    1978             : 
    1979             :     // Steps 1-2.
    1980           0 :     double t = LocalTime(dateObj->UTCTime().toNumber());
    1981             : 
    1982             :     // Steps 3-4.
    1983             :     double m;
    1984           0 :     if (!ToNumber(cx, args.get(0), &m))
    1985           0 :         return false;
    1986             : 
    1987             :     // Steps 5-6.
    1988             :     double s;
    1989           0 :     if (!GetSecsOrDefault(cx, args, 1, t, &s))
    1990           0 :         return false;
    1991             : 
    1992             :     // Steps 7-8.
    1993             :     double milli;
    1994           0 :     if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
    1995           0 :         return false;
    1996             : 
    1997             :     // Step 9.
    1998           0 :     double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
    1999             : 
    2000             :     // Step 10.
    2001           0 :     ClippedTime u = TimeClip(UTC(date));
    2002             : 
    2003             :     // Steps 11-12.
    2004           0 :     dateObj->setUTCTime(u, args.rval());
    2005           0 :     return true;
    2006             : }
    2007             : 
    2008             : /* ES6 20.3.4.24. */
    2009             : static bool
    2010           0 : date_setMinutes(JSContext* cx, unsigned argc, Value* vp)
    2011             : {
    2012             :     // Steps 1-2 (the effectful parts).
    2013           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2014           0 :     return CallNonGenericMethod<IsDate, date_setMinutes_impl>(cx, args);
    2015             : }
    2016             : 
    2017             : MOZ_ALWAYS_INLINE bool
    2018           0 : date_setUTCMinutes_impl(JSContext* cx, const CallArgs& args)
    2019             : {
    2020           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2021             : 
    2022             :     /* Step 1. */
    2023           0 :     double t = dateObj->UTCTime().toNumber();
    2024             : 
    2025             :     /* Step 2. */
    2026             :     double m;
    2027           0 :     if (!ToNumber(cx, args.get(0), &m))
    2028           0 :         return false;
    2029             : 
    2030             :     /* Step 3. */
    2031             :     double s;
    2032           0 :     if (!GetSecsOrDefault(cx, args, 1, t, &s))
    2033           0 :         return false;
    2034             : 
    2035             :     /* Step 4. */
    2036             :     double milli;
    2037           0 :     if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
    2038           0 :         return false;
    2039             : 
    2040             :     /* Step 5. */
    2041           0 :     double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
    2042             : 
    2043             :     /* Step 6. */
    2044           0 :     ClippedTime v = TimeClip(date);
    2045             : 
    2046             :     /* Steps 7-8. */
    2047           0 :     dateObj->setUTCTime(v, args.rval());
    2048           0 :     return true;
    2049             : }
    2050             : 
    2051             : /* ES5 15.9.5.34. */
    2052             : static bool
    2053           0 : date_setUTCMinutes(JSContext* cx, unsigned argc, Value* vp)
    2054             : {
    2055           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2056           0 :     return CallNonGenericMethod<IsDate, date_setUTCMinutes_impl>(cx, args);
    2057             : }
    2058             : 
    2059             : MOZ_ALWAYS_INLINE bool
    2060           0 : date_setHours_impl(JSContext* cx, const CallArgs& args)
    2061             : {
    2062           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2063             : 
    2064             :     // Steps 1-2.
    2065           0 :     double t = LocalTime(dateObj->UTCTime().toNumber());
    2066             : 
    2067             :     // Steps 3-4.
    2068             :     double h;
    2069           0 :     if (!ToNumber(cx, args.get(0), &h))
    2070           0 :         return false;
    2071             : 
    2072             :     // Steps 5-6.
    2073             :     double m;
    2074           0 :     if (!GetMinsOrDefault(cx, args, 1, t, &m))
    2075           0 :         return false;
    2076             : 
    2077             :     // Steps 7-8.
    2078             :     double s;
    2079           0 :     if (!GetSecsOrDefault(cx, args, 2, t, &s))
    2080           0 :         return false;
    2081             : 
    2082             :     // Steps 9-10.
    2083             :     double milli;
    2084           0 :     if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
    2085           0 :         return false;
    2086             : 
    2087             :     // Step 11.
    2088           0 :     double date = MakeDate(Day(t), MakeTime(h, m, s, milli));
    2089             : 
    2090             :     // Step 12.
    2091           0 :     ClippedTime u = TimeClip(UTC(date));
    2092             : 
    2093             :     // Steps 13-14.
    2094           0 :     dateObj->setUTCTime(u, args.rval());
    2095           0 :     return true;
    2096             : }
    2097             : 
    2098             : /* ES5 15.9.5.35. */
    2099             : static bool
    2100           0 : date_setHours(JSContext* cx, unsigned argc, Value* vp)
    2101             : {
    2102           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2103           0 :     return CallNonGenericMethod<IsDate, date_setHours_impl>(cx, args);
    2104             : }
    2105             : 
    2106             : MOZ_ALWAYS_INLINE bool
    2107           0 : date_setUTCHours_impl(JSContext* cx, const CallArgs& args)
    2108             : {
    2109           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2110             : 
    2111             :     /* Step 1. */
    2112           0 :     double t = dateObj->UTCTime().toNumber();
    2113             : 
    2114             :     /* Step 2. */
    2115             :     double h;
    2116           0 :     if (!ToNumber(cx, args.get(0), &h))
    2117           0 :         return false;
    2118             : 
    2119             :     /* Step 3. */
    2120             :     double m;
    2121           0 :     if (!GetMinsOrDefault(cx, args, 1, t, &m))
    2122           0 :         return false;
    2123             : 
    2124             :     /* Step 4. */
    2125             :     double s;
    2126           0 :     if (!GetSecsOrDefault(cx, args, 2, t, &s))
    2127           0 :         return false;
    2128             : 
    2129             :     /* Step 5. */
    2130             :     double milli;
    2131           0 :     if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
    2132           0 :         return false;
    2133             : 
    2134             :     /* Step 6. */
    2135           0 :     double newDate = MakeDate(Day(t), MakeTime(h, m, s, milli));
    2136             : 
    2137             :     /* Step 7. */
    2138           0 :     ClippedTime v = TimeClip(newDate);
    2139             : 
    2140             :     /* Steps 8-9. */
    2141           0 :     dateObj->setUTCTime(v, args.rval());
    2142           0 :     return true;
    2143             : }
    2144             : 
    2145             : /* ES5 15.9.5.36. */
    2146             : static bool
    2147           0 : date_setUTCHours(JSContext* cx, unsigned argc, Value* vp)
    2148             : {
    2149           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2150           0 :     return CallNonGenericMethod<IsDate, date_setUTCHours_impl>(cx, args);
    2151             : }
    2152             : 
    2153             : MOZ_ALWAYS_INLINE bool
    2154           1 : date_setDate_impl(JSContext* cx, const CallArgs& args)
    2155             : {
    2156           2 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2157             : 
    2158             :     /* Step 1. */
    2159           1 :     double t = LocalTime(dateObj->UTCTime().toNumber());
    2160             : 
    2161             :     /* Step 2. */
    2162             :     double date;
    2163           1 :     if (!ToNumber(cx, args.get(0), &date))
    2164           0 :         return false;
    2165             : 
    2166             :     /* Step 3. */
    2167           1 :     double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
    2168             : 
    2169             :     /* Step 4. */
    2170           1 :     ClippedTime u = TimeClip(UTC(newDate));
    2171             : 
    2172             :     /* Steps 5-6. */
    2173           1 :     dateObj->setUTCTime(u, args.rval());
    2174           1 :     return true;
    2175             : }
    2176             : 
    2177             : /* ES5 15.9.5.37. */
    2178             : static bool
    2179           1 : date_setDate(JSContext* cx, unsigned argc, Value* vp)
    2180             : {
    2181           1 :     CallArgs args = CallArgsFromVp(argc, vp);
    2182           1 :     return CallNonGenericMethod<IsDate, date_setDate_impl>(cx, args);
    2183             : }
    2184             : 
    2185             : MOZ_ALWAYS_INLINE bool
    2186           0 : date_setUTCDate_impl(JSContext* cx, const CallArgs& args)
    2187             : {
    2188           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2189             : 
    2190             :     /* Step 1. */
    2191           0 :     double t = dateObj->UTCTime().toNumber();
    2192             : 
    2193             :     /* Step 2. */
    2194             :     double date;
    2195           0 :     if (!ToNumber(cx, args.get(0), &date))
    2196           0 :         return false;
    2197             : 
    2198             :     /* Step 3. */
    2199           0 :     double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
    2200             : 
    2201             :     /* Step 4. */
    2202           0 :     ClippedTime v = TimeClip(newDate);
    2203             : 
    2204             :     /* Steps 5-6. */
    2205           0 :     dateObj->setUTCTime(v, args.rval());
    2206           0 :     return true;
    2207             : }
    2208             : 
    2209             : static bool
    2210           0 : date_setUTCDate(JSContext* cx, unsigned argc, Value* vp)
    2211             : {
    2212           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2213           0 :     return CallNonGenericMethod<IsDate, date_setUTCDate_impl>(cx, args);
    2214             : }
    2215             : 
    2216             : static bool
    2217           0 : GetDateOrDefault(JSContext* cx, const CallArgs& args, unsigned i, double t, double* date)
    2218             : {
    2219           0 :     if (args.length() <= i) {
    2220           0 :         *date = DateFromTime(t);
    2221           0 :         return true;
    2222             :     }
    2223           0 :     return ToNumber(cx, args[i], date);
    2224             : }
    2225             : 
    2226             : static bool
    2227           0 : GetMonthOrDefault(JSContext* cx, const CallArgs& args, unsigned i, double t, double* month)
    2228             : {
    2229           0 :     if (args.length() <= i) {
    2230           0 :         *month = MonthFromTime(t);
    2231           0 :         return true;
    2232             :     }
    2233           0 :     return ToNumber(cx, args[i], month);
    2234             : }
    2235             : 
    2236             : /* ES5 15.9.5.38. */
    2237             : MOZ_ALWAYS_INLINE bool
    2238           0 : date_setMonth_impl(JSContext* cx, const CallArgs& args)
    2239             : {
    2240           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2241             : 
    2242             :     /* Step 1. */
    2243           0 :     double t = LocalTime(dateObj->UTCTime().toNumber());
    2244             : 
    2245             :     /* Step 2. */
    2246             :     double m;
    2247           0 :     if (!ToNumber(cx, args.get(0), &m))
    2248           0 :         return false;
    2249             : 
    2250             :     /* Step 3. */
    2251             :     double date;
    2252           0 :     if (!GetDateOrDefault(cx, args, 1, t, &date))
    2253           0 :         return false;
    2254             : 
    2255             :     /* Step 4. */
    2256           0 :     double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t));
    2257             : 
    2258             :     /* Step 5. */
    2259           0 :     ClippedTime u = TimeClip(UTC(newDate));
    2260             : 
    2261             :     /* Steps 6-7. */
    2262           0 :     dateObj->setUTCTime(u, args.rval());
    2263           0 :     return true;
    2264             : }
    2265             : 
    2266             : static bool
    2267           0 : date_setMonth(JSContext* cx, unsigned argc, Value* vp)
    2268             : {
    2269           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2270           0 :     return CallNonGenericMethod<IsDate, date_setMonth_impl>(cx, args);
    2271             : }
    2272             : 
    2273             : /* ES5 15.9.5.39. */
    2274             : MOZ_ALWAYS_INLINE bool
    2275           0 : date_setUTCMonth_impl(JSContext* cx, const CallArgs& args)
    2276             : {
    2277           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2278             : 
    2279             :     /* Step 1. */
    2280           0 :     double t = dateObj->UTCTime().toNumber();
    2281             : 
    2282             :     /* Step 2. */
    2283             :     double m;
    2284           0 :     if (!ToNumber(cx, args.get(0), &m))
    2285           0 :         return false;
    2286             : 
    2287             :     /* Step 3. */
    2288             :     double date;
    2289           0 :     if (!GetDateOrDefault(cx, args, 1, t, &date))
    2290           0 :         return false;
    2291             : 
    2292             :     /* Step 4. */
    2293           0 :     double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t));
    2294             : 
    2295             :     /* Step 5. */
    2296           0 :     ClippedTime v = TimeClip(newDate);
    2297             : 
    2298             :     /* Steps 6-7. */
    2299           0 :     dateObj->setUTCTime(v, args.rval());
    2300           0 :     return true;
    2301             : }
    2302             : 
    2303             : static bool
    2304           0 : date_setUTCMonth(JSContext* cx, unsigned argc, Value* vp)
    2305             : {
    2306           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2307           0 :     return CallNonGenericMethod<IsDate, date_setUTCMonth_impl>(cx, args);
    2308             : }
    2309             : 
    2310             : static double
    2311           0 : ThisLocalTimeOrZero(Handle<DateObject*> dateObj)
    2312             : {
    2313           0 :     double t = dateObj->UTCTime().toNumber();
    2314           0 :     if (IsNaN(t))
    2315           0 :         return +0;
    2316           0 :     return LocalTime(t);
    2317             : }
    2318             : 
    2319             : static double
    2320           0 : ThisUTCTimeOrZero(Handle<DateObject*> dateObj)
    2321             : {
    2322           0 :     double t = dateObj->as<DateObject>().UTCTime().toNumber();
    2323           0 :     return IsNaN(t) ? +0 : t;
    2324             : }
    2325             : 
    2326             : /* ES5 15.9.5.40. */
    2327             : MOZ_ALWAYS_INLINE bool
    2328           0 : date_setFullYear_impl(JSContext* cx, const CallArgs& args)
    2329             : {
    2330           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2331             : 
    2332             :     /* Step 1. */
    2333           0 :     double t = ThisLocalTimeOrZero(dateObj);
    2334             : 
    2335             :     /* Step 2. */
    2336             :     double y;
    2337           0 :     if (!ToNumber(cx, args.get(0), &y))
    2338           0 :         return false;
    2339             : 
    2340             :     /* Step 3. */
    2341             :     double m;
    2342           0 :     if (!GetMonthOrDefault(cx, args, 1, t, &m))
    2343           0 :         return false;
    2344             : 
    2345             :     /* Step 4. */
    2346             :     double date;
    2347           0 :     if (!GetDateOrDefault(cx, args, 2, t, &date))
    2348           0 :         return false;
    2349             : 
    2350             :     /* Step 5. */
    2351           0 :     double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t));
    2352             : 
    2353             :     /* Step 6. */
    2354           0 :     ClippedTime u = TimeClip(UTC(newDate));
    2355             : 
    2356             :     /* Steps 7-8. */
    2357           0 :     dateObj->setUTCTime(u, args.rval());
    2358           0 :     return true;
    2359             : }
    2360             : 
    2361             : static bool
    2362           0 : date_setFullYear(JSContext* cx, unsigned argc, Value* vp)
    2363             : {
    2364           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2365           0 :     return CallNonGenericMethod<IsDate, date_setFullYear_impl>(cx, args);
    2366             : }
    2367             : 
    2368             : /* ES5 15.9.5.41. */
    2369             : MOZ_ALWAYS_INLINE bool
    2370           0 : date_setUTCFullYear_impl(JSContext* cx, const CallArgs& args)
    2371             : {
    2372           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2373             : 
    2374             :     /* Step 1. */
    2375           0 :     double t = ThisUTCTimeOrZero(dateObj);
    2376             : 
    2377             :     /* Step 2. */
    2378             :     double y;
    2379           0 :     if (!ToNumber(cx, args.get(0), &y))
    2380           0 :         return false;
    2381             : 
    2382             :     /* Step 3. */
    2383             :     double m;
    2384           0 :     if (!GetMonthOrDefault(cx, args, 1, t, &m))
    2385           0 :         return false;
    2386             : 
    2387             :     /* Step 4. */
    2388             :     double date;
    2389           0 :     if (!GetDateOrDefault(cx, args, 2, t, &date))
    2390           0 :         return false;
    2391             : 
    2392             :     /* Step 5. */
    2393           0 :     double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t));
    2394             : 
    2395             :     /* Step 6. */
    2396           0 :     ClippedTime v = TimeClip(newDate);
    2397             : 
    2398             :     /* Steps 7-8. */
    2399           0 :     dateObj->setUTCTime(v, args.rval());
    2400           0 :     return true;
    2401             : }
    2402             : 
    2403             : static bool
    2404           0 : date_setUTCFullYear(JSContext* cx, unsigned argc, Value* vp)
    2405             : {
    2406           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2407           0 :     return CallNonGenericMethod<IsDate, date_setUTCFullYear_impl>(cx, args);
    2408             : }
    2409             : 
    2410             : /* ES5 Annex B.2.5. */
    2411             : MOZ_ALWAYS_INLINE bool
    2412           0 : date_setYear_impl(JSContext* cx, const CallArgs& args)
    2413             : {
    2414           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2415             : 
    2416             :     /* Step 1. */
    2417           0 :     double t = ThisLocalTimeOrZero(dateObj);
    2418             : 
    2419             :     /* Step 2. */
    2420             :     double y;
    2421           0 :     if (!ToNumber(cx, args.get(0), &y))
    2422           0 :         return false;
    2423             : 
    2424             :     /* Step 3. */
    2425           0 :     if (IsNaN(y)) {
    2426           0 :         dateObj->setUTCTime(ClippedTime::invalid(), args.rval());
    2427           0 :         return true;
    2428             :     }
    2429             : 
    2430             :     /* Step 4. */
    2431           0 :     double yint = ToInteger(y);
    2432           0 :     if (0 <= yint && yint <= 99)
    2433           0 :         yint += 1900;
    2434             : 
    2435             :     /* Step 5. */
    2436           0 :     double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t));
    2437             : 
    2438             :     /* Step 6. */
    2439           0 :     double u = UTC(MakeDate(day, TimeWithinDay(t)));
    2440             : 
    2441             :     /* Steps 7-8. */
    2442           0 :     dateObj->setUTCTime(TimeClip(u), args.rval());
    2443           0 :     return true;
    2444             : }
    2445             : 
    2446             : static bool
    2447           0 : date_setYear(JSContext* cx, unsigned argc, Value* vp)
    2448             : {
    2449           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2450           0 :     return CallNonGenericMethod<IsDate, date_setYear_impl>(cx, args);
    2451             : }
    2452             : 
    2453             : /* constants for toString, toUTCString */
    2454             : static const char js_NaN_date_str[] = "Invalid Date";
    2455             : static const char * const days[] =
    2456             : {
    2457             :    "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
    2458             : };
    2459             : static const char * const months[] =
    2460             : {
    2461             :    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    2462             : };
    2463             : 
    2464             : /* ES5 B.2.6. */
    2465             : MOZ_ALWAYS_INLINE bool
    2466           0 : date_toGMTString_impl(JSContext* cx, const CallArgs& args)
    2467             : {
    2468           0 :     double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    2469             : 
    2470             :     JSString* str;
    2471           0 :     if (!IsFinite(utctime)) {
    2472           0 :         str = NewStringCopyZ<CanGC>(cx, js_NaN_date_str);
    2473             :     } else {
    2474             :         char buf[100];
    2475           0 :         SprintfLiteral(buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
    2476           0 :                        days[int(WeekDay(utctime))],
    2477           0 :                        int(DateFromTime(utctime)),
    2478           0 :                        months[int(MonthFromTime(utctime))],
    2479           0 :                        int(YearFromTime(utctime)),
    2480           0 :                        int(HourFromTime(utctime)),
    2481           0 :                        int(MinFromTime(utctime)),
    2482           0 :                        int(SecFromTime(utctime)));
    2483             : 
    2484           0 :         str = NewStringCopyZ<CanGC>(cx, buf);
    2485             :     }
    2486             : 
    2487           0 :     if (!str)
    2488           0 :         return false;
    2489           0 :     args.rval().setString(str);
    2490           0 :     return true;
    2491             : }
    2492             : 
    2493             : static bool
    2494           0 : date_toGMTString(JSContext* cx, unsigned argc, Value* vp)
    2495             : {
    2496           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2497           0 :     return CallNonGenericMethod<IsDate, date_toGMTString_impl>(cx, args);
    2498             : }
    2499             : 
    2500             : /* ES6 draft 2015-01-15 20.3.4.36. */
    2501             : MOZ_ALWAYS_INLINE bool
    2502           0 : date_toISOString_impl(JSContext* cx, const CallArgs& args)
    2503             : {
    2504           0 :     double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
    2505           0 :     if (!IsFinite(utctime)) {
    2506           0 :         JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr, JSMSG_INVALID_DATE);
    2507           0 :         return false;
    2508             :     }
    2509             : 
    2510             :     char buf[100];
    2511           0 :     int year = int(YearFromTime(utctime));
    2512           0 :     if (year < 0 || year > 9999) {
    2513           0 :         SprintfLiteral(buf, "%+.6d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
    2514           0 :                        int(YearFromTime(utctime)),
    2515           0 :                        int(MonthFromTime(utctime)) + 1,
    2516           0 :                        int(DateFromTime(utctime)),
    2517           0 :                        int(HourFromTime(utctime)),
    2518           0 :                        int(MinFromTime(utctime)),
    2519           0 :                        int(SecFromTime(utctime)),
    2520           0 :                        int(msFromTime(utctime)));
    2521             :     } else {
    2522           0 :         SprintfLiteral(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
    2523           0 :                        int(YearFromTime(utctime)),
    2524           0 :                        int(MonthFromTime(utctime)) + 1,
    2525           0 :                        int(DateFromTime(utctime)),
    2526           0 :                        int(HourFromTime(utctime)),
    2527           0 :                        int(MinFromTime(utctime)),
    2528           0 :                        int(SecFromTime(utctime)),
    2529           0 :                        int(msFromTime(utctime)));
    2530             :     }
    2531             : 
    2532           0 :     JSString* str = NewStringCopyZ<CanGC>(cx, buf);
    2533           0 :     if (!str)
    2534           0 :         return false;
    2535           0 :     args.rval().setString(str);
    2536           0 :     return true;
    2537             : 
    2538             : }
    2539             : 
    2540             : static bool
    2541           0 : date_toISOString(JSContext* cx, unsigned argc, Value* vp)
    2542             : {
    2543           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2544           0 :     return CallNonGenericMethod<IsDate, date_toISOString_impl>(cx, args);
    2545             : }
    2546             : 
    2547             : /* ES5 15.9.5.44. */
    2548             : static bool
    2549           0 : date_toJSON(JSContext* cx, unsigned argc, Value* vp)
    2550             : {
    2551           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2552             : 
    2553             :     /* Step 1. */
    2554           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
    2555           0 :     if (!obj)
    2556           0 :         return false;
    2557             : 
    2558             :     /* Step 2. */
    2559           0 :     RootedValue tv(cx, ObjectValue(*obj));
    2560           0 :     if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
    2561           0 :         return false;
    2562             : 
    2563             :     /* Step 3. */
    2564           0 :     if (tv.isDouble() && !IsFinite(tv.toDouble())) {
    2565           0 :         args.rval().setNull();
    2566           0 :         return true;
    2567             :     }
    2568             : 
    2569             :     /* Step 4. */
    2570           0 :     RootedValue toISO(cx);
    2571           0 :     if (!GetProperty(cx, obj, obj, cx->names().toISOString, &toISO))
    2572           0 :         return false;
    2573             : 
    2574             :     /* Step 5. */
    2575           0 :     if (!IsCallable(toISO)) {
    2576             :         JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, js::GetErrorMessage, nullptr,
    2577           0 :                                           JSMSG_BAD_TOISOSTRING_PROP);
    2578           0 :         return false;
    2579             :     }
    2580             : 
    2581             :     /* Step 6. */
    2582           0 :     return Call(cx, toISO, obj, args.rval());
    2583             : }
    2584             : 
    2585             : /* Interface to PRMJTime date struct. */
    2586             : static PRMJTime
    2587           0 : ToPRMJTime(double localTime)
    2588             : {
    2589           0 :     double year = YearFromTime(localTime);
    2590             : 
    2591             :     PRMJTime prtm;
    2592           0 :     prtm.tm_usec = int32_t(msFromTime(localTime)) * 1000;
    2593           0 :     prtm.tm_sec = int8_t(SecFromTime(localTime));
    2594           0 :     prtm.tm_min = int8_t(MinFromTime(localTime));
    2595           0 :     prtm.tm_hour = int8_t(HourFromTime(localTime));
    2596           0 :     prtm.tm_mday = int8_t(DateFromTime(localTime));
    2597           0 :     prtm.tm_mon = int8_t(MonthFromTime(localTime));
    2598           0 :     prtm.tm_wday = int8_t(WeekDay(localTime));
    2599           0 :     prtm.tm_year = year;
    2600           0 :     prtm.tm_yday = int16_t(DayWithinYear(localTime, year));
    2601             : 
    2602             :     // XXX: DaylightSavingTA expects utc-time argument.
    2603           0 :     prtm.tm_isdst = (DaylightSavingTA(localTime) != 0);
    2604             : 
    2605           0 :     return prtm;
    2606             : }
    2607             : 
    2608             : enum class FormatSpec {
    2609             :     DateTime,
    2610             :     Date,
    2611             :     Time
    2612             : };
    2613             : 
    2614             : static bool
    2615           0 : FormatDate(JSContext* cx, double utcTime, FormatSpec format, MutableHandleValue rval)
    2616             : {
    2617             :     JSString* str;
    2618           0 :     if (!IsFinite(utcTime)) {
    2619           0 :         str = NewStringCopyZ<CanGC>(cx, js_NaN_date_str);
    2620             :     } else {
    2621           0 :         MOZ_ASSERT(NumbersAreIdentical(TimeClip(utcTime).toDouble(), utcTime));
    2622             : 
    2623           0 :         double localTime = LocalTime(utcTime);
    2624             : 
    2625           0 :         int offset = 0;
    2626             :         char tzbuf[100];
    2627           0 :         bool usetz = false;
    2628           0 :         if (format == FormatSpec::DateTime || format == FormatSpec::Time) {
    2629             :             /*
    2630             :              * Offset from GMT in minutes.  The offset includes daylight
    2631             :              * savings, if it applies.
    2632             :              */
    2633           0 :             int minutes = (int) floor((localTime - utcTime) / msPerMinute);
    2634             : 
    2635             :             /* Map 510 minutes to 0830 hours. */
    2636           0 :             offset = (minutes / 60) * 100 + minutes % 60;
    2637             : 
    2638             :             /*
    2639             :              * Print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997".
    2640             :              *
    2641             :              * The TZA is printed as 'GMT-0800' rather than as 'PST' to avoid
    2642             :              * operating-system dependence on strftime (which PRMJ_FormatTime
    2643             :              * calls, for %Z only.)  win32 prints PST as
    2644             :              * 'Pacific Standard Time.'  This way we always know what we're
    2645             :              * getting, and can parse it if we produce it.  The OS time zone
    2646             :              * string is included as a comment.
    2647             :              */
    2648             : 
    2649             :             /* get a time zone string from the OS to include as a comment. */
    2650           0 :             PRMJTime prtm = ToPRMJTime(utcTime);
    2651           0 :             size_t tzlen = PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &prtm);
    2652           0 :             if (tzlen != 0) {
    2653             :                 /*
    2654             :                  * Decide whether to use the resulting time zone string.
    2655             :                  *
    2656             :                  * Reject it if it contains any non-ASCII, non-alphanumeric
    2657             :                  * characters.  It's then likely in some other character
    2658             :                  * encoding, and we probably won't display it correctly.
    2659             :                  */
    2660           0 :                 usetz = true;
    2661           0 :                 for (size_t i = 0; i < tzlen; i++) {
    2662           0 :                     char16_t c = tzbuf[i];
    2663           0 :                     if (c > 127 || !(isalnum(c) || c == ' ' || c == '(' || c == ')' || c == '.')) {
    2664           0 :                         usetz = false;
    2665           0 :                         break;
    2666             :                     }
    2667             :                 }
    2668             : 
    2669             :                 /* Also reject it if it's not parenthesized or if it's '()'. */
    2670           0 :                 if (tzbuf[0] != '(' || tzbuf[1] == ')')
    2671           0 :                     usetz = false;
    2672             :             }
    2673             :         }
    2674             : 
    2675             :         char buf[100];
    2676           0 :         switch (format) {
    2677             :           case FormatSpec::DateTime:
    2678             :             /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
    2679           0 :             SprintfLiteral(buf, "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
    2680           0 :                            days[int(WeekDay(localTime))],
    2681           0 :                            months[int(MonthFromTime(localTime))],
    2682           0 :                            int(DateFromTime(localTime)),
    2683           0 :                            int(YearFromTime(localTime)),
    2684           0 :                            int(HourFromTime(localTime)),
    2685           0 :                            int(MinFromTime(localTime)),
    2686           0 :                            int(SecFromTime(localTime)),
    2687             :                            offset,
    2688             :                            usetz ? " " : "",
    2689           0 :                            usetz ? tzbuf : "");
    2690           0 :             break;
    2691             :           case FormatSpec::Date:
    2692             :             /* Tue Oct 31 2000 */
    2693           0 :             SprintfLiteral(buf, "%s %s %.2d %.4d",
    2694           0 :                            days[int(WeekDay(localTime))],
    2695           0 :                            months[int(MonthFromTime(localTime))],
    2696           0 :                            int(DateFromTime(localTime)),
    2697           0 :                            int(YearFromTime(localTime)));
    2698           0 :             break;
    2699             :           case FormatSpec::Time:
    2700             :             /* 09:41:40 GMT-0800 (PST) */
    2701           0 :             SprintfLiteral(buf, "%.2d:%.2d:%.2d GMT%+.4d%s%s",
    2702           0 :                            int(HourFromTime(localTime)),
    2703           0 :                            int(MinFromTime(localTime)),
    2704           0 :                            int(SecFromTime(localTime)),
    2705             :                            offset,
    2706             :                            usetz ? " " : "",
    2707           0 :                            usetz ? tzbuf : "");
    2708           0 :             break;
    2709             :         }
    2710             : 
    2711           0 :         str = NewStringCopyZ<CanGC>(cx, buf);
    2712             :     }
    2713             : 
    2714           0 :     if (!str)
    2715           0 :         return false;
    2716           0 :     rval.setString(str);
    2717           0 :     return true;
    2718             : }
    2719             : 
    2720             : static bool
    2721           0 : ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, MutableHandleValue rval)
    2722             : {
    2723           0 :     double utcTime = obj->as<DateObject>().UTCTime().toNumber();
    2724             : 
    2725             :     char buf[100];
    2726           0 :     if (!IsFinite(utcTime)) {
    2727           0 :         strcpy(buf, js_NaN_date_str);
    2728             :     } else {
    2729           0 :         double localTime = LocalTime(utcTime);
    2730           0 :         PRMJTime prtm = ToPRMJTime(localTime);
    2731             : 
    2732             :         /* Let PRMJTime format it. */
    2733           0 :         size_t result_len = PRMJ_FormatTime(buf, sizeof buf, format, &prtm);
    2734             : 
    2735             :         /* If it failed, default to toString. */
    2736           0 :         if (result_len == 0)
    2737           0 :             return FormatDate(cx, utcTime, FormatSpec::DateTime, rval);
    2738             : 
    2739             :         /* Hacked check against undesired 2-digit year 00/00/00 form. */
    2740           0 :         if (strcmp(format, "%x") == 0 && result_len >= 6 &&
    2741             :             /* Format %x means use OS settings, which may have 2-digit yr, so
    2742             :                hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
    2743           0 :             !isdigit(buf[result_len - 3]) &&
    2744           0 :             isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
    2745             :             /* ...but not if starts with 4-digit year, like 2022/3/11. */
    2746           0 :             !(isdigit(buf[0]) && isdigit(buf[1]) &&
    2747           0 :               isdigit(buf[2]) && isdigit(buf[3])))
    2748             :         {
    2749           0 :             int year = int(YearFromTime(localTime));
    2750           0 :             snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), "%d", year);
    2751             :         }
    2752             : 
    2753             :     }
    2754             : 
    2755           0 :     if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUnicode)
    2756           0 :         return cx->runtime()->localeCallbacks->localeToUnicode(cx, buf, rval);
    2757             : 
    2758           0 :     JSString* str = NewStringCopyZ<CanGC>(cx, buf);
    2759           0 :     if (!str)
    2760           0 :         return false;
    2761           0 :     rval.setString(str);
    2762           0 :     return true;
    2763             : }
    2764             : 
    2765             : #if !EXPOSE_INTL_API
    2766             : /* ES5 15.9.5.5. */
    2767             : MOZ_ALWAYS_INLINE bool
    2768             : date_toLocaleString_impl(JSContext* cx, const CallArgs& args)
    2769             : {
    2770             :     /*
    2771             :      * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
    2772             :      * with msvc; '%#c' requests that a full year be used in the result string.
    2773             :      */
    2774             :     static const char format[] =
    2775             : #if defined(_WIN32) && !defined(__MWERKS__)
    2776             :                                    "%#c"
    2777             : #else
    2778             :                                    "%c"
    2779             : #endif
    2780             :                                    ;
    2781             : 
    2782             :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2783             :     return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
    2784             : }
    2785             : 
    2786             : static bool
    2787             : date_toLocaleString(JSContext* cx, unsigned argc, Value* vp)
    2788             : {
    2789             :     CallArgs args = CallArgsFromVp(argc, vp);
    2790             :     return CallNonGenericMethod<IsDate, date_toLocaleString_impl>(cx, args);
    2791             : }
    2792             : 
    2793             : /* ES5 15.9.5.6. */
    2794             : MOZ_ALWAYS_INLINE bool
    2795             : date_toLocaleDateString_impl(JSContext* cx, const CallArgs& args)
    2796             : {
    2797             :     /*
    2798             :      * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
    2799             :      * with msvc; '%#x' requests that a full year be used in the result string.
    2800             :      */
    2801             :     static const char format[] =
    2802             : #if defined(_WIN32) && !defined(__MWERKS__)
    2803             :                                    "%#x"
    2804             : #else
    2805             :                                    "%x"
    2806             : #endif
    2807             :                                    ;
    2808             : 
    2809             :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2810             :     return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
    2811             : }
    2812             : 
    2813             : static bool
    2814             : date_toLocaleDateString(JSContext* cx, unsigned argc, Value* vp)
    2815             : {
    2816             :     CallArgs args = CallArgsFromVp(argc, vp);
    2817             :     return CallNonGenericMethod<IsDate, date_toLocaleDateString_impl>(cx, args);
    2818             : }
    2819             : 
    2820             : /* ES5 15.9.5.7. */
    2821             : MOZ_ALWAYS_INLINE bool
    2822             : date_toLocaleTimeString_impl(JSContext* cx, const CallArgs& args)
    2823             : {
    2824             :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2825             :     return ToLocaleFormatHelper(cx, dateObj, "%X", args.rval());
    2826             : }
    2827             : 
    2828             : static bool
    2829             : date_toLocaleTimeString(JSContext* cx, unsigned argc, Value* vp)
    2830             : {
    2831             :     CallArgs args = CallArgsFromVp(argc, vp);
    2832             :     return CallNonGenericMethod<IsDate, date_toLocaleTimeString_impl>(cx, args);
    2833             : }
    2834             : #endif /* !EXPOSE_INTL_API */
    2835             : 
    2836             : MOZ_ALWAYS_INLINE bool
    2837           0 : date_toLocaleFormat_impl(JSContext* cx, const CallArgs& args)
    2838             : {
    2839           0 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2840             : 
    2841             : #if EXPOSE_INTL_API
    2842           0 :     if (!cx->compartment()->warnedAboutDateToLocaleFormat) {
    2843           0 :         if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
    2844             :                                                JSMSG_DEPRECATED_TOLOCALEFORMAT))
    2845             :         {
    2846           0 :             return false;
    2847             :         }
    2848           0 :         cx->compartment()->warnedAboutDateToLocaleFormat = true;
    2849             :     }
    2850             : #endif
    2851             : 
    2852           0 :     if (args.length() == 0) {
    2853             :         /*
    2854             :          * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
    2855             :          * with msvc; '%#c' requests that a full year be used in the result string.
    2856             :          */
    2857             :         static const char format[] =
    2858             : #if defined(_WIN32) && !defined(__MWERKS__)
    2859             :                                        "%#c"
    2860             : #else
    2861             :                                        "%c"
    2862             : #endif
    2863             :                                        ;
    2864             : 
    2865           0 :         return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
    2866             :     }
    2867             : 
    2868           0 :     RootedString fmt(cx, ToString<CanGC>(cx, args[0]));
    2869           0 :     if (!fmt)
    2870           0 :         return false;
    2871             : 
    2872           0 :     JSAutoByteString fmtbytes(cx, fmt);
    2873           0 :     if (!fmtbytes)
    2874           0 :         return false;
    2875             : 
    2876           0 :     return ToLocaleFormatHelper(cx, dateObj, fmtbytes.ptr(), args.rval());
    2877             : }
    2878             : 
    2879             : static bool
    2880           0 : date_toLocaleFormat(JSContext* cx, unsigned argc, Value* vp)
    2881             : {
    2882           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2883           0 :     return CallNonGenericMethod<IsDate, date_toLocaleFormat_impl>(cx, args);
    2884             : }
    2885             : 
    2886             : /* ES5 15.9.5.4. */
    2887             : MOZ_ALWAYS_INLINE bool
    2888           0 : date_toTimeString_impl(JSContext* cx, const CallArgs& args)
    2889             : {
    2890           0 :     return FormatDate(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
    2891           0 :                       FormatSpec::Time, args.rval());
    2892             : }
    2893             : 
    2894             : static bool
    2895           0 : date_toTimeString(JSContext* cx, unsigned argc, Value* vp)
    2896             : {
    2897           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2898           0 :     return CallNonGenericMethod<IsDate, date_toTimeString_impl>(cx, args);
    2899             : }
    2900             : 
    2901             : /* ES5 15.9.5.3. */
    2902             : MOZ_ALWAYS_INLINE bool
    2903           0 : date_toDateString_impl(JSContext* cx, const CallArgs& args)
    2904             : {
    2905           0 :     return FormatDate(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
    2906           0 :                       FormatSpec::Date, args.rval());
    2907             : }
    2908             : 
    2909             : static bool
    2910           0 : date_toDateString(JSContext* cx, unsigned argc, Value* vp)
    2911             : {
    2912           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2913           0 :     return CallNonGenericMethod<IsDate, date_toDateString_impl>(cx, args);
    2914             : }
    2915             : 
    2916             : #if JS_HAS_TOSOURCE
    2917             : MOZ_ALWAYS_INLINE bool
    2918           0 : date_toSource_impl(JSContext* cx, const CallArgs& args)
    2919             : {
    2920           0 :     StringBuffer sb(cx);
    2921           0 :     if (!sb.append("(new Date(") ||
    2922           0 :         !NumberValueToStringBuffer(cx, args.thisv().toObject().as<DateObject>().UTCTime(), sb) ||
    2923           0 :         !sb.append("))"))
    2924             :     {
    2925           0 :         return false;
    2926             :     }
    2927             : 
    2928           0 :     JSString* str = sb.finishString();
    2929           0 :     if (!str)
    2930           0 :         return false;
    2931           0 :     args.rval().setString(str);
    2932           0 :     return true;
    2933             : }
    2934             : 
    2935             : static bool
    2936           0 : date_toSource(JSContext* cx, unsigned argc, Value* vp)
    2937             : {
    2938           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2939           0 :     return CallNonGenericMethod<IsDate, date_toSource_impl>(cx, args);
    2940             : }
    2941             : #endif
    2942             : 
    2943             : MOZ_ALWAYS_INLINE bool
    2944           0 : IsObject(HandleValue v)
    2945             : {
    2946           0 :     return v.isObject();
    2947             : }
    2948             : 
    2949             : // ES6 20.3.4.41.
    2950             : MOZ_ALWAYS_INLINE bool
    2951           0 : date_toString_impl(JSContext* cx, const CallArgs& args)
    2952             : {
    2953             :     // Step 1.
    2954           0 :     RootedObject obj(cx, &args.thisv().toObject());
    2955             : 
    2956             :     // Step 2.
    2957             :     ESClass cls;
    2958           0 :     if (!GetBuiltinClass(cx, obj, &cls))
    2959           0 :         return false;
    2960             : 
    2961             :     double tv;
    2962           0 :     if (cls != ESClass::Date) {
    2963             :         // Step 2.
    2964           0 :         tv = GenericNaN();
    2965             :     } else {
    2966             :         // Step 3.
    2967           0 :         RootedValue unboxed(cx);
    2968           0 :         if (!Unbox(cx, obj, &unboxed))
    2969           0 :             return false;
    2970             : 
    2971           0 :         tv = unboxed.toNumber();
    2972             :     }
    2973             : 
    2974             :     // Step 4.
    2975           0 :     return FormatDate(cx, tv, FormatSpec::DateTime, args.rval());
    2976             : }
    2977             : 
    2978             : bool
    2979           0 : date_toString(JSContext* cx, unsigned argc, Value* vp)
    2980             : {
    2981             :     // Step 1.
    2982           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2983           0 :     return CallNonGenericMethod<IsObject, date_toString_impl>(cx, args);
    2984             : }
    2985             : 
    2986             : MOZ_ALWAYS_INLINE bool
    2987          31 : date_valueOf_impl(JSContext* cx, const CallArgs& args)
    2988             : {
    2989          62 :     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
    2990          31 :     args.rval().set(dateObj->UTCTime());
    2991          62 :     return true;
    2992             : }
    2993             : 
    2994             : bool
    2995          31 : js::date_valueOf(JSContext* cx, unsigned argc, Value* vp)
    2996             : {
    2997          31 :     CallArgs args = CallArgsFromVp(argc, vp);
    2998          31 :     return CallNonGenericMethod<IsDate, date_valueOf_impl>(cx, args);
    2999             : }
    3000             : 
    3001             : // ES6 20.3.4.45 Date.prototype[@@toPrimitive]
    3002             : static bool
    3003          31 : date_toPrimitive(JSContext* cx, unsigned argc, Value* vp)
    3004             : {
    3005          31 :     CallArgs args = CallArgsFromVp(argc, vp);
    3006             : 
    3007             :     // Steps 1-2.
    3008          31 :     if (!args.thisv().isObject()) {
    3009           0 :         ReportIncompatible(cx, args);
    3010           0 :         return false;
    3011             :     }
    3012             : 
    3013             :     // Steps 3-5.
    3014             :     JSType hint;
    3015          31 :     if (!GetFirstArgumentAsTypeHint(cx, args, &hint))
    3016           0 :         return false;
    3017          31 :     if (hint == JSTYPE_UNDEFINED)
    3018           0 :         hint = JSTYPE_STRING;
    3019             : 
    3020          31 :     args.rval().set(args.thisv());
    3021          62 :     RootedObject obj(cx, &args.thisv().toObject());
    3022          31 :     return OrdinaryToPrimitive(cx, obj, hint, args.rval());
    3023             : }
    3024             : 
    3025             : static const JSFunctionSpec date_static_methods[] = {
    3026             :     JS_FN("UTC",                 date_UTC,                7,0),
    3027             :     JS_FN("parse",               date_parse,              1,0),
    3028             :     JS_FN("now",                 date_now,                0,0),
    3029             :     JS_FS_END
    3030             : };
    3031             : 
    3032             : static const JSFunctionSpec date_methods[] = {
    3033             :     JS_FN("getTime",             date_getTime,            0,0),
    3034             :     JS_FN("getTimezoneOffset",   date_getTimezoneOffset,  0,0),
    3035             :     JS_FN("getYear",             date_getYear,            0,0),
    3036             :     JS_FN("getFullYear",         date_getFullYear,        0,0),
    3037             :     JS_FN("getUTCFullYear",      date_getUTCFullYear,     0,0),
    3038             :     JS_FN("getMonth",            date_getMonth,           0,0),
    3039             :     JS_FN("getUTCMonth",         date_getUTCMonth,        0,0),
    3040             :     JS_FN("getDate",             date_getDate,            0,0),
    3041             :     JS_FN("getUTCDate",          date_getUTCDate,         0,0),
    3042             :     JS_FN("getDay",              date_getDay,             0,0),
    3043             :     JS_FN("getUTCDay",           date_getUTCDay,          0,0),
    3044             :     JS_FN("getHours",            date_getHours,           0,0),
    3045             :     JS_FN("getUTCHours",         date_getUTCHours,        0,0),
    3046             :     JS_FN("getMinutes",          date_getMinutes,         0,0),
    3047             :     JS_FN("getUTCMinutes",       date_getUTCMinutes,      0,0),
    3048             :     JS_FN("getSeconds",          date_getUTCSeconds,      0,0),
    3049             :     JS_FN("getUTCSeconds",       date_getUTCSeconds,      0,0),
    3050             :     JS_FN("getMilliseconds",     date_getUTCMilliseconds, 0,0),
    3051             :     JS_FN("getUTCMilliseconds",  date_getUTCMilliseconds, 0,0),
    3052             :     JS_FN("setTime",             date_setTime,            1,0),
    3053             :     JS_FN("setYear",             date_setYear,            1,0),
    3054             :     JS_FN("setFullYear",         date_setFullYear,        3,0),
    3055             :     JS_FN("setUTCFullYear",      date_setUTCFullYear,     3,0),
    3056             :     JS_FN("setMonth",            date_setMonth,           2,0),
    3057             :     JS_FN("setUTCMonth",         date_setUTCMonth,        2,0),
    3058             :     JS_FN("setDate",             date_setDate,            1,0),
    3059             :     JS_FN("setUTCDate",          date_setUTCDate,         1,0),
    3060             :     JS_FN("setHours",            date_setHours,           4,0),
    3061             :     JS_FN("setUTCHours",         date_setUTCHours,        4,0),
    3062             :     JS_FN("setMinutes",          date_setMinutes,         3,0),
    3063             :     JS_FN("setUTCMinutes",       date_setUTCMinutes,      3,0),
    3064             :     JS_FN("setSeconds",          date_setSeconds,         2,0),
    3065             :     JS_FN("setUTCSeconds",       date_setUTCSeconds,      2,0),
    3066             :     JS_FN("setMilliseconds",     date_setMilliseconds,    1,0),
    3067             :     JS_FN("setUTCMilliseconds",  date_setUTCMilliseconds, 1,0),
    3068             :     JS_FN("toUTCString",         date_toGMTString,        0,0),
    3069             :     JS_FN("toLocaleFormat",      date_toLocaleFormat,     0,0),
    3070             : #if EXPOSE_INTL_API
    3071             :     JS_SELF_HOSTED_FN(js_toLocaleString_str, "Date_toLocaleString", 0,0),
    3072             :     JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0),
    3073             :     JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0),
    3074             : #else
    3075             :     JS_FN(js_toLocaleString_str, date_toLocaleString,     0,0),
    3076             :     JS_FN("toLocaleDateString",  date_toLocaleDateString, 0,0),
    3077             :     JS_FN("toLocaleTimeString",  date_toLocaleTimeString, 0,0),
    3078             : #endif
    3079             :     JS_FN("toDateString",        date_toDateString,       0,0),
    3080             :     JS_FN("toTimeString",        date_toTimeString,       0,0),
    3081             :     JS_FN("toISOString",         date_toISOString,        0,0),
    3082             :     JS_FN(js_toJSON_str,         date_toJSON,             1,0),
    3083             : #if JS_HAS_TOSOURCE
    3084             :     JS_FN(js_toSource_str,       date_toSource,           0,0),
    3085             : #endif
    3086             :     JS_FN(js_toString_str,       date_toString,           0,0),
    3087             :     JS_FN(js_valueOf_str,        date_valueOf,            0,0),
    3088             :     JS_SYM_FN(toPrimitive,       date_toPrimitive,        1,JSPROP_READONLY),
    3089             :     JS_FS_END
    3090             : };
    3091             : 
    3092             : static bool
    3093          46 : NewDateObject(JSContext* cx, const CallArgs& args, ClippedTime t)
    3094             : {
    3095          46 :     MOZ_ASSERT(args.isConstructing());
    3096             : 
    3097          92 :     RootedObject proto(cx);
    3098          46 :     if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
    3099           0 :         return false;
    3100             : 
    3101          46 :     JSObject* obj = NewDateObjectMsec(cx, t, proto);
    3102          46 :     if (!obj)
    3103           0 :         return false;
    3104             : 
    3105          46 :     args.rval().setObject(*obj);
    3106          46 :     return true;
    3107             : }
    3108             : 
    3109             : static bool
    3110           0 : ToDateString(JSContext* cx, const CallArgs& args, ClippedTime t)
    3111             : {
    3112           0 :     return FormatDate(cx, t.toDouble(), FormatSpec::DateTime, args.rval());
    3113             : }
    3114             : 
    3115             : static bool
    3116          30 : DateNoArguments(JSContext* cx, const CallArgs& args)
    3117             : {
    3118          30 :     MOZ_ASSERT(args.length() == 0);
    3119             : 
    3120          30 :     ClippedTime now = NowAsMillis();
    3121             : 
    3122          30 :     if (args.isConstructing())
    3123          30 :         return NewDateObject(cx, args, now);
    3124             : 
    3125           0 :     return ToDateString(cx, args, now);
    3126             : }
    3127             : 
    3128             : static bool
    3129          16 : DateOneArgument(JSContext* cx, const CallArgs& args)
    3130             : {
    3131          16 :     MOZ_ASSERT(args.length() == 1);
    3132             : 
    3133          16 :     if (args.isConstructing()) {
    3134          16 :         if (args[0].isObject()) {
    3135           0 :             RootedObject obj(cx, &args[0].toObject());
    3136             : 
    3137             :             ESClass cls;
    3138           0 :             if (!GetBuiltinClass(cx, obj, &cls))
    3139           0 :                 return false;
    3140             : 
    3141           0 :             if (cls == ESClass::Date) {
    3142           0 :                 RootedValue unboxed(cx);
    3143           0 :                 if (!Unbox(cx, obj, &unboxed))
    3144           0 :                     return false;
    3145             : 
    3146           0 :                 return NewDateObject(cx, args, TimeClip(unboxed.toNumber()));
    3147             :             }
    3148             :         }
    3149             : 
    3150          16 :         if (!ToPrimitive(cx, args[0]))
    3151           0 :             return false;
    3152             : 
    3153          16 :         ClippedTime t;
    3154          16 :         if (args[0].isString()) {
    3155           0 :             JSLinearString* linearStr = args[0].toString()->ensureLinear(cx);
    3156           0 :             if (!linearStr)
    3157           0 :                 return false;
    3158             : 
    3159           0 :             if (!ParseDate(linearStr, &t))
    3160           0 :                 t = ClippedTime::invalid();
    3161             :         } else {
    3162             :             double d;
    3163          16 :             if (!ToNumber(cx, args[0], &d))
    3164           0 :                 return false;
    3165          16 :             t = TimeClip(d);
    3166             :         }
    3167             : 
    3168          16 :         return NewDateObject(cx, args, t);
    3169             :     }
    3170             : 
    3171           0 :     return ToDateString(cx, args, NowAsMillis());
    3172             : }
    3173             : 
    3174             : static bool
    3175           0 : DateMultipleArguments(JSContext* cx, const CallArgs& args)
    3176             : {
    3177           0 :     MOZ_ASSERT(args.length() >= 2);
    3178             : 
    3179             :     // Step 3.
    3180           0 :     if (args.isConstructing()) {
    3181             :         // Steps 3a-b.
    3182             :         double y;
    3183           0 :         if (!ToNumber(cx, args[0], &y))
    3184           0 :             return false;
    3185             : 
    3186             :         // Steps 3c-d.
    3187             :         double m;
    3188           0 :         if (!ToNumber(cx, args[1], &m))
    3189           0 :             return false;
    3190             : 
    3191             :         // Steps 3e-f.
    3192             :         double dt;
    3193           0 :         if (args.length() >= 3) {
    3194           0 :             if (!ToNumber(cx, args[2], &dt))
    3195           0 :                 return false;
    3196             :         } else {
    3197           0 :             dt = 1;
    3198             :         }
    3199             : 
    3200             :         // Steps 3g-h.
    3201             :         double h;
    3202           0 :         if (args.length() >= 4) {
    3203           0 :             if (!ToNumber(cx, args[3], &h))
    3204           0 :                 return false;
    3205             :         } else {
    3206           0 :             h = 0;
    3207             :         }
    3208             : 
    3209             :         // Steps 3i-j.
    3210             :         double min;
    3211           0 :         if (args.length() >= 5) {
    3212           0 :             if (!ToNumber(cx, args[4], &min))
    3213           0 :                 return false;
    3214             :         } else {
    3215           0 :             min = 0;
    3216             :         }
    3217             : 
    3218             :         // Steps 3k-l.
    3219             :         double s;
    3220           0 :         if (args.length() >= 6) {
    3221           0 :             if (!ToNumber(cx, args[5], &s))
    3222           0 :                 return false;
    3223             :         } else {
    3224           0 :             s = 0;
    3225             :         }
    3226             : 
    3227             :         // Steps 3m-n.
    3228             :         double milli;
    3229           0 :         if (args.length() >= 7) {
    3230           0 :             if (!ToNumber(cx, args[6], &milli))
    3231           0 :                 return false;
    3232             :         } else {
    3233           0 :             milli = 0;
    3234             :         }
    3235             : 
    3236             :         // Step 3o.
    3237           0 :         double yr = y;
    3238           0 :         if (!IsNaN(y)) {
    3239           0 :             double yint = ToInteger(y);
    3240           0 :             if (0 <= yint && yint <= 99)
    3241           0 :                 yr = 1900 + yint;
    3242             :         }
    3243             : 
    3244             :         // Step 3p.
    3245           0 :         double finalDate = MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli));
    3246             : 
    3247             :         // Steps 3q-t.
    3248           0 :         return NewDateObject(cx, args, TimeClip(UTC(finalDate)));
    3249             :     }
    3250             : 
    3251           0 :     return ToDateString(cx, args, NowAsMillis());
    3252             : }
    3253             : 
    3254             : bool
    3255          46 : js::DateConstructor(JSContext* cx, unsigned argc, Value* vp)
    3256             : {
    3257          46 :     CallArgs args = CallArgsFromVp(argc, vp);
    3258             : 
    3259          46 :     if (args.length() == 0)
    3260          30 :         return DateNoArguments(cx, args);
    3261             : 
    3262          16 :     if (args.length() == 1)
    3263          16 :         return DateOneArgument(cx, args);
    3264             : 
    3265           0 :     return DateMultipleArguments(cx, args);
    3266             : }
    3267             : 
    3268             : // ES6 final draft 20.3.4.
    3269             : static JSObject*
    3270          25 : CreateDatePrototype(JSContext* cx, JSProtoKey key)
    3271             : {
    3272          25 :     return GlobalObject::createBlankPrototype(cx, cx->global(), &DateObject::protoClass_);
    3273             : }
    3274             : 
    3275             : static bool
    3276          25 : FinishDateClassInit(JSContext* cx, HandleObject ctor, HandleObject proto)
    3277             : {
    3278             :     /*
    3279             :      * Date.prototype.toGMTString has the same initial value as
    3280             :      * Date.prototype.toUTCString.
    3281             :      */
    3282          50 :     RootedValue toUTCStringFun(cx);
    3283          50 :     RootedId toUTCStringId(cx, NameToId(cx->names().toUTCString));
    3284          50 :     RootedId toGMTStringId(cx, NameToId(cx->names().toGMTString));
    3285         150 :     return NativeGetProperty(cx, proto.as<NativeObject>(), toUTCStringId, &toUTCStringFun) &&
    3286         100 :            NativeDefineProperty(cx, proto.as<NativeObject>(), toGMTStringId, toUTCStringFun,
    3287          50 :                                 nullptr, nullptr, 0);
    3288             : }
    3289             : 
    3290             : static const ClassSpec DateObjectClassSpec = {
    3291             :     GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
    3292             :     CreateDatePrototype,
    3293             :     date_static_methods,
    3294             :     nullptr,
    3295             :     date_methods,
    3296             :     nullptr,
    3297             :     FinishDateClassInit
    3298             : };
    3299             : 
    3300             : const Class DateObject::class_ = {
    3301             :     js_Date_str,
    3302             :     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
    3303             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
    3304             :     JS_NULL_CLASS_OPS,
    3305             :     &DateObjectClassSpec
    3306             : };
    3307             : 
    3308             : const Class DateObject::protoClass_ = {
    3309             :     js_Object_str,
    3310             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
    3311             :     JS_NULL_CLASS_OPS,
    3312             :     &DateObjectClassSpec
    3313             : };
    3314             : 
    3315             : JSObject*
    3316          84 : js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
    3317             : {
    3318          84 :     JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
    3319          84 :     if (!obj)
    3320           0 :         return nullptr;
    3321          84 :     obj->as<DateObject>().setUTCTime(t);
    3322          84 :     return obj;
    3323             : }
    3324             : 
    3325             : JS_FRIEND_API(JSObject*)
    3326           0 : js::NewDateObject(JSContext* cx, int year, int mon, int mday,
    3327             :                   int hour, int min, int sec)
    3328             : {
    3329           0 :     MOZ_ASSERT(mon < 12);
    3330           0 :     double msec_time = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0.0));
    3331           0 :     return NewDateObjectMsec(cx, TimeClip(UTC(msec_time)));
    3332             : }
    3333             : 
    3334             : JS_FRIEND_API(bool)
    3335           0 : js::DateIsValid(JSContext* cx, HandleObject obj, bool* isValid)
    3336             : {
    3337             :     ESClass cls;
    3338           0 :     if (!GetBuiltinClass(cx, obj, &cls))
    3339           0 :         return false;
    3340             : 
    3341           0 :     if (cls != ESClass::Date) {
    3342           0 :         *isValid = false;
    3343           0 :         return true;
    3344             :     }
    3345             : 
    3346           0 :     RootedValue unboxed(cx);
    3347           0 :     if (!Unbox(cx, obj, &unboxed))
    3348           0 :         return false;
    3349             : 
    3350           0 :     *isValid = !IsNaN(unboxed.toNumber());
    3351           0 :     return true;
    3352             : }
    3353             : 
    3354             : JS_FRIEND_API(bool)
    3355           0 : js::DateGetMsecSinceEpoch(JSContext* cx, HandleObject obj, double* msecsSinceEpoch)
    3356             : {
    3357             :     ESClass cls;
    3358           0 :     if (!GetBuiltinClass(cx, obj, &cls))
    3359           0 :         return false;
    3360             : 
    3361           0 :     if (cls != ESClass::Date) {
    3362           0 :         *msecsSinceEpoch = 0;
    3363           0 :         return true;
    3364             :     }
    3365             : 
    3366           0 :     RootedValue unboxed(cx);
    3367           0 :     if (!Unbox(cx, obj, &unboxed))
    3368           0 :         return false;
    3369             : 
    3370           0 :     *msecsSinceEpoch = unboxed.toNumber();
    3371           0 :     return true;
    3372             : }

Generated by: LCOV version 1.13