Bug 1300825 - Code clean-ups for date formatting. r=till
authorAndré Bargull <andre.bargull@gmail.com>
Wed, 05 Oct 2016 03:25:03 -0700
changeset 316798 f9fadd6ed3c190b55c4753a24fe1e95a1a3c4ebc
parent 316797 0512a9e149d6f7fd6e72097200475ed5375b3a44
child 316799 67b189765ba96d1bcd41ea2d3be8615b65117cb2
push id32932
push userphilringnalda@gmail.com
push dateFri, 07 Oct 2016 03:24:25 +0000
treeherderautoland@7affb66131bb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1300825
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1300825 - Code clean-ups for date formatting. r=till
js/src/jsdate.cpp
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1040,27 +1040,27 @@ ParseDate(const CharT* s, size_t length,
             } else {
                 return false;
             }
             prevc = 0;
         } else if (c == '/' || c == ':' || c == '+' || c == '-') {
             prevc = c;
         } else {
             size_t st = i - 1;
-            int k;
             while (i < length) {
                 c = s[i];
                 if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
                     break;
                 i++;
             }
 
             if (i <= st + 1)
                 return false;
 
+            int k;
             for (k = ArrayLength(wtb); --k >= 0;) {
                 if (RegionMatches(wtb[k], 0, s, st, i - st)) {
                     int action = ttb[k];
                     if (action != 0) {
                         if (action < 0) {
                             /*
                              * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
                              * 12:30, instead of blindly adding 12 if PM.
@@ -2428,21 +2428,21 @@ static const char * const months[] =
 };
 
 /* ES5 B.2.6. */
 MOZ_ALWAYS_INLINE bool
 date_toGMTString_impl(JSContext* cx, const CallArgs& args)
 {
     double utctime = args.thisv().toObject().as<DateObject>().UTCTime().toNumber();
 
-    char buf[100];
     JSString* str;
     if (!IsFinite(utctime)) {
         str = NewStringCopyZ<CanGC>(cx, js_NaN_date_str);
     } else {
+        char buf[100];
         SprintfLiteral(buf, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
                        days[int(WeekDay(utctime))],
                        int(DateFromTime(utctime)),
                        months[int(MonthFromTime(utctime))],
                        int(YearFromTime(utctime)),
                        int(HourFromTime(utctime)),
                        int(MinFromTime(utctime)),
                        int(SecFromTime(utctime)));
@@ -2544,131 +2544,128 @@ date_toJSON(JSContext* cx, unsigned argc
         return false;
     }
 
     /* Step 6. */
     return Call(cx, toISO, obj, args.rval());
 }
 
 /* Interface to PRMJTime date struct. */
-static void
-ToPRMJTime(double localTime, PRMJTime* prtm)
+static PRMJTime
+ToPRMJTime(double localTime)
 {
     double year = YearFromTime(localTime);
 
-    prtm->tm_usec = int32_t(msFromTime(localTime)) * 1000;
-    prtm->tm_sec = int8_t(SecFromTime(localTime));
-    prtm->tm_min = int8_t(MinFromTime(localTime));
-    prtm->tm_hour = int8_t(HourFromTime(localTime));
-    prtm->tm_mday = int8_t(DateFromTime(localTime));
-    prtm->tm_mon = int8_t(MonthFromTime(localTime));
-    prtm->tm_wday = int8_t(WeekDay(localTime));
-    prtm->tm_year = year;
-    prtm->tm_yday = int16_t(DayWithinYear(localTime, year));
+    PRMJTime prtm;
+    prtm.tm_usec = int32_t(msFromTime(localTime)) * 1000;
+    prtm.tm_sec = int8_t(SecFromTime(localTime));
+    prtm.tm_min = int8_t(MinFromTime(localTime));
+    prtm.tm_hour = int8_t(HourFromTime(localTime));
+    prtm.tm_mday = int8_t(DateFromTime(localTime));
+    prtm.tm_mon = int8_t(MonthFromTime(localTime));
+    prtm.tm_wday = int8_t(WeekDay(localTime));
+    prtm.tm_year = year;
+    prtm.tm_yday = int16_t(DayWithinYear(localTime, year));
 
     // XXX: DaylightSavingTA expects utc-time argument.
-    prtm->tm_isdst = (DaylightSavingTA(localTime) != 0);
+    prtm.tm_isdst = (DaylightSavingTA(localTime) != 0);
+
+    return prtm;
 }
 
-typedef enum formatspec {
-    FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
-} formatspec;
+enum class FormatSpec {
+    DateTime,
+    Date,
+    Time
+};
 
 static bool
-FormatDate(JSContext* cx, double utcTime, formatspec format, MutableHandleValue rval)
+FormatDate(JSContext* cx, double utcTime, FormatSpec format, MutableHandleValue rval)
 {
-    char buf[100];
-    char tzbuf[100];
-    bool usetz;
-    size_t i, tzlen;
-    PRMJTime prtm;
-
     JSString* str;
     if (!IsFinite(utcTime)) {
         str = NewStringCopyZ<CanGC>(cx, js_NaN_date_str);
     } else {
         MOZ_ASSERT(NumbersAreIdentical(TimeClip(utcTime).toDouble(), utcTime));
 
         double localTime = LocalTime(utcTime);
 
         /*
          * Offset from GMT in minutes.  The offset includes daylight
          * savings, if it applies.
          */
-        int minutes = (int) floor(AdjustTime(utcTime) / msPerMinute);
+        int minutes = (int) floor((localTime - utcTime) / msPerMinute);
 
         /* Map 510 minutes to 0830 hours. */
         int offset = (minutes / 60) * 100 + minutes % 60;
 
         /*
          * Print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997".
          *
          * The TZA is printed as 'GMT-0800' rather than as 'PST' to avoid
          * operating-system dependence on strftime (which PRMJ_FormatTime
          * calls, for %Z only.)  win32 prints PST as
          * 'Pacific Standard Time.'  This way we always know what we're
          * getting, and can parse it if we produce it.  The OS time zone
          * string is included as a comment.
          */
 
         /* get a time zone string from the OS to include as a comment. */
-        ToPRMJTime(utcTime, &prtm);
-        if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &prtm) != 0) {
+        PRMJTime prtm = ToPRMJTime(utcTime);
+        char tzbuf[100];
+        bool usetz;
+        size_t tzlen = PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &prtm);
+        if (tzlen != 0) {
             /*
              * Decide whether to use the resulting time zone string.
              *
              * Reject it if it contains any non-ASCII, non-alphanumeric
              * characters.  It's then likely in some other character
              * encoding, and we probably won't display it correctly.
              */
             usetz = true;
-            tzlen = strlen(tzbuf);
-            if (tzlen > 100) {
-                usetz = false;
-            } else {
-                for (i = 0; i < tzlen; i++) {
-                    char16_t c = tzbuf[i];
-                    if (c > 127 ||
-                        !(isalpha(c) || isdigit(c) ||
-                          c == ' ' || c == '(' || c == ')' || c == '.')) {
-                        usetz = false;
-                    }
+            for (size_t i = 0; i < tzlen; i++) {
+                char16_t c = tzbuf[i];
+                if (c > 127 || !(isalnum(c) || c == ' ' || c == '(' || c == ')' || c == '.')) {
+                    usetz = false;
+                    break;
                 }
             }
 
             /* Also reject it if it's not parenthesized or if it's '()'. */
             if (tzbuf[0] != '(' || tzbuf[1] == ')')
                 usetz = false;
         } else
             usetz = false;
 
+        char buf[100];
         switch (format) {
-          case FORMATSPEC_FULL:
+          case FormatSpec::DateTime:
             /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
             SprintfLiteral(buf, "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
                            days[int(WeekDay(localTime))],
                            months[int(MonthFromTime(localTime))],
                            int(DateFromTime(localTime)),
                            int(YearFromTime(localTime)),
                            int(HourFromTime(localTime)),
                            int(MinFromTime(localTime)),
                            int(SecFromTime(localTime)),
                            offset,
                            usetz ? " " : "",
                            usetz ? tzbuf : "");
             break;
-          case FORMATSPEC_DATE:
+          case FormatSpec::Date:
             /* Tue Oct 31 2000 */
             SprintfLiteral(buf, "%s %s %.2d %.4d",
                            days[int(WeekDay(localTime))],
                            months[int(MonthFromTime(localTime))],
                            int(DateFromTime(localTime)),
                            int(YearFromTime(localTime)));
             break;
-          case FORMATSPEC_TIME:
+          case FormatSpec::Time:
             /* 09:41:40 GMT-0800 (PST) */
             SprintfLiteral(buf, "%.2d:%.2d:%.2d GMT%+.4d%s%s",
                            int(HourFromTime(localTime)),
                            int(MinFromTime(localTime)),
                            int(SecFromTime(localTime)),
                            offset,
                            usetz ? " " : "",
                            usetz ? tzbuf : "");
@@ -2688,77 +2685,71 @@ static bool
 ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, MutableHandleValue rval)
 {
     double utcTime = obj->as<DateObject>().UTCTime().toNumber();
 
     char buf[100];
     if (!IsFinite(utcTime)) {
         strcpy(buf, js_NaN_date_str);
     } else {
-        int result_len;
         double localTime = LocalTime(utcTime);
-        PRMJTime prtm;
-        ToPRMJTime(localTime, &prtm);
+        PRMJTime prtm = ToPRMJTime(localTime);
 
         /* Let PRMJTime format it. */
-        result_len = PRMJ_FormatTime(buf, sizeof buf, format, &prtm);
+        size_t result_len = PRMJ_FormatTime(buf, sizeof buf, format, &prtm);
 
         /* If it failed, default to toString. */
         if (result_len == 0)
-            return FormatDate(cx, utcTime, FORMATSPEC_FULL, rval);
+            return FormatDate(cx, utcTime, FormatSpec::DateTime, rval);
 
         /* Hacked check against undesired 2-digit year 00/00/00 form. */
         if (strcmp(format, "%x") == 0 && result_len >= 6 &&
             /* Format %x means use OS settings, which may have 2-digit yr, so
                hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
             !isdigit(buf[result_len - 3]) &&
             isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
             /* ...but not if starts with 4-digit year, like 2022/3/11. */
             !(isdigit(buf[0]) && isdigit(buf[1]) &&
-              isdigit(buf[2]) && isdigit(buf[3]))) {
-            double localtime = obj->as<DateObject>().cachedLocalTime();
-            int year = IsNaN(localtime) ? 0 : (int) YearFromTime(localtime);
+              isdigit(buf[2]) && isdigit(buf[3])))
+        {
+            int year = int(YearFromTime(localTime));
             snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), "%d", year);
         }
 
     }
 
     if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUnicode)
         return cx->runtime()->localeCallbacks->localeToUnicode(cx, buf, rval);
 
     JSString* str = NewStringCopyZ<CanGC>(cx, buf);
     if (!str)
         return false;
     rval.setString(str);
     return true;
 }
 
 #if !EXPOSE_INTL_API
-static bool
-ToLocaleStringHelper(JSContext* cx, Handle<DateObject*> dateObj, MutableHandleValue rval)
+/* ES5 15.9.5.5. */
+MOZ_ALWAYS_INLINE bool
+date_toLocaleString_impl(JSContext* cx, const CallArgs& args)
 {
     /*
      * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
      * with msvc; '%#c' requests that a full year be used in the result string.
      */
-    return ToLocaleFormatHelper(cx, dateObj,
+    static const char format[] =
 #if defined(_WIN32) && !defined(__MWERKS__)
-                          "%#c"
+                                   "%#c"
 #else
-                          "%c"
+                                   "%c"
 #endif
-                         , rval);
-}
-
-/* ES5 15.9.5.5. */
-MOZ_ALWAYS_INLINE bool
-date_toLocaleString_impl(JSContext* cx, const CallArgs& args)
-{
+                                   ;
+
     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
-    return ToLocaleStringHelper(cx, dateObj, args.rval());
+    return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
 }
 
 static bool
 date_toLocaleString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsDate, date_toLocaleString_impl>(cx, args);
 }
@@ -2811,23 +2802,25 @@ date_toLocaleFormat_impl(JSContext* cx, 
 {
     Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
 
     if (args.length() == 0) {
         /*
          * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
          * with msvc; '%#c' requests that a full year be used in the result string.
          */
-        return ToLocaleFormatHelper(cx, dateObj,
+        static const char format[] =
 #if defined(_WIN32) && !defined(__MWERKS__)
-                              "%#c"
+                                       "%#c"
 #else
-                              "%c"
+                                       "%c"
 #endif
-                             , args.rval());
+                                       ;
+
+        return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
     }
 
     RootedString fmt(cx, ToString<CanGC>(cx, args[0]));
     if (!fmt)
         return false;
 
     JSAutoByteString fmtbytes(cx, fmt);
     if (!fmtbytes)
@@ -2843,32 +2836,32 @@ date_toLocaleFormat(JSContext* cx, unsig
     return CallNonGenericMethod<IsDate, date_toLocaleFormat_impl>(cx, args);
 }
 
 /* ES5 15.9.5.4. */
 MOZ_ALWAYS_INLINE bool
 date_toTimeString_impl(JSContext* cx, const CallArgs& args)
 {
     return FormatDate(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
-                      FORMATSPEC_TIME, args.rval());
+                      FormatSpec::Time, args.rval());
 }
 
 static bool
 date_toTimeString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsDate, date_toTimeString_impl>(cx, args);
 }
 
 /* ES5 15.9.5.3. */
 MOZ_ALWAYS_INLINE bool
 date_toDateString_impl(JSContext* cx, const CallArgs& args)
 {
     return FormatDate(cx, args.thisv().toObject().as<DateObject>().UTCTime().toNumber(),
-                      FORMATSPEC_DATE, args.rval());
+                      FormatSpec::Date, args.rval());
 }
 
 static bool
 date_toDateString(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsDate, date_toDateString_impl>(cx, args);
 }
@@ -2927,17 +2920,17 @@ date_toString_impl(JSContext* cx, const 
         RootedValue unboxed(cx);
         if (!Unbox(cx, obj, &unboxed))
             return false;
 
         tv = unboxed.toNumber();
     }
 
     // Step 4.
-    return FormatDate(cx, tv, FORMATSPEC_FULL, args.rval());
+    return FormatDate(cx, tv, FormatSpec::DateTime, args.rval());
 }
 
 bool
 date_toString(JSContext* cx, unsigned argc, Value* vp)
 {
     // Step 1.
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsObject, date_toString_impl>(cx, args);
@@ -3065,17 +3058,17 @@ NewDateObject(JSContext* cx, const CallA
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
 ToDateString(JSContext* cx, const CallArgs& args, ClippedTime t)
 {
-    return FormatDate(cx, t.toDouble(), FORMATSPEC_FULL, args.rval());
+    return FormatDate(cx, t.toDouble(), FormatSpec::DateTime, args.rval());
 }
 
 static bool
 DateNoArguments(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(args.length() == 0);
 
     ClippedTime now = NowAsMillis();