Backed out changeset 7251919f6a23 (bug 1319464) to fix Sm-Tc(nu). r=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 23 Nov 2016 17:48:00 +0100
changeset 324107 00df72027708beea7b601fdc78ca73461bbfe5e3
parent 324106 84db192b60ed0d7414746157c79d17277425c698
child 324108 d29ab4cddb8299285f431ff521c64712f25ad33e
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersbackout
bugs1319464
milestone53.0a1
backs out7251919f6a2318ab715085c4162d927455bae6b7
Backed out changeset 7251919f6a23 (bug 1319464) to fix Sm-Tc(nu). r=backout
js/src/builtin/Intl.cpp
js/src/builtin/Intl.h
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -99,16 +99,22 @@ Char16ToUChar(const char16_t* chars)
 }
 
 inline UChar*
 Char16ToUChar(char16_t* chars)
 {
     MOZ_CRASH("Char16ToUChar: Intl API disabled");
 }
 
+int32_t
+u_strlen(const UChar* s)
+{
+    MOZ_CRASH("u_strlen: Intl API disabled");
+}
+
 struct UEnumeration;
 
 int32_t
 uenum_count(UEnumeration* en, UErrorCode* status)
 {
     MOZ_CRASH("uenum_count: Intl API disabled");
 }
 
@@ -1513,20 +1519,22 @@ NewUNumberFormat(JSContext* cx, HandleOb
         return nullptr;
 
     if (equal(style, "currency")) {
         if (!GetProperty(cx, internals, internals, cx->names().currency, &value))
             return nullptr;
         currency = value.toString();
         MOZ_ASSERT(currency->length() == 3,
                    "IsWellFormedCurrencyCode permits only length-3 strings");
-        if (!stableChars.initTwoByte(cx, currency))
+        if (!currency->ensureFlat(cx) || !stableChars.initTwoByte(cx, currency))
             return nullptr;
         // uCurrency remains owned by stableChars.
         uCurrency = Char16ToUChar(stableChars.twoByteRange().begin().get());
+        if (!uCurrency)
+            return nullptr;
 
         if (!GetProperty(cx, internals, internals, cx->names().currencyDisplay, &value))
             return nullptr;
         JSAutoByteString currencyDisplay(cx, value.toString());
         if (!currencyDisplay)
             return nullptr;
         if (equal(currencyDisplay, "code")) {
             uStyle = UNUM_CURRENCY_ISO;
@@ -1621,31 +1629,29 @@ intl_FormatNumber(JSContext* cx, UNumber
     // FormatNumber doesn't consider -0.0 to be negative.
     if (IsNegativeZero(x))
         x = 0.0;
 
     Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
     if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
         return false;
     UErrorCode status = U_ZERO_ERROR;
-    int32_t size = unum_formatDouble(nf, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE,
-                                     nullptr, &status);
+    int size = unum_formatDouble(nf, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE,
+                                 nullptr, &status);
     if (status == U_BUFFER_OVERFLOW_ERROR) {
-        MOZ_ASSERT(size >= 0);
         if (!chars.resize(size))
             return false;
         status = U_ZERO_ERROR;
         unum_formatDouble(nf, x, Char16ToUChar(chars.begin()), size, nullptr, &status);
     }
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
-    MOZ_ASSERT(size >= 0);
     JSString* str = NewStringCopyN<CanGC>(cx, chars.begin(), size);
     if (!str)
         return false;
 
     result.setString(str);
     return true;
 }
 
@@ -2037,17 +2043,17 @@ static js::HashNumber
 HashStringIgnoreCaseASCII(const Char* s, size_t length)
 {
     uint32_t hash = 0;
     for (size_t i = 0; i < length; i++)
         hash = mozilla::AddToHash(hash, ToUpperASCII(s[i]));
     return hash;
 }
 
-js::SharedIntlData::TimeZoneHasher::Lookup::Lookup(JSLinearString* timeZone)
+js::SharedIntlData::TimeZoneHasher::Lookup::Lookup(JSFlatString* timeZone)
   : isLatin1(timeZone->hasLatin1Chars()), length(timeZone->length())
 {
     if (isLatin1) {
         latin1Chars = timeZone->latin1Chars(nogc);
         hash = HashStringIgnoreCaseASCII(latin1Chars, length);
     } else {
         twoByteChars = timeZone->twoByteChars(nogc);
         hash = HashStringIgnoreCaseASCII(twoByteChars, length);
@@ -2203,39 +2209,39 @@ js::SharedIntlData::ensureTimeZones(JSCo
 
 bool
 js::SharedIntlData::validateTimeZoneName(JSContext* cx, HandleString timeZone,
                                          MutableHandleString result)
 {
     if (!ensureTimeZones(cx))
         return false;
 
-    RootedLinearString timeZoneLinear(cx, timeZone->ensureLinear(cx));
-    if (!timeZoneLinear)
+    Rooted<JSFlatString*> timeZoneFlat(cx, timeZone->ensureFlat(cx));
+    if (!timeZoneFlat)
         return false;
 
-    TimeZoneHasher::Lookup lookup(timeZoneLinear);
+    TimeZoneHasher::Lookup lookup(timeZoneFlat);
     if (TimeZoneSet::Ptr p = availableTimeZones.lookup(lookup))
         result.set(*p);
 
     return true;
 }
 
 bool
 js::SharedIntlData::tryCanonicalizeTimeZoneConsistentWithIANA(JSContext* cx, HandleString timeZone,
                                                               MutableHandleString result)
 {
     if (!ensureTimeZones(cx))
         return false;
 
-    RootedLinearString timeZoneLinear(cx, timeZone->ensureLinear(cx));
-    if (!timeZoneLinear)
+    Rooted<JSFlatString*> timeZoneFlat(cx, timeZone->ensureFlat(cx));
+    if (!timeZoneFlat)
         return false;
 
-    TimeZoneHasher::Lookup lookup(timeZoneLinear);
+    TimeZoneHasher::Lookup lookup(timeZoneFlat);
     MOZ_ASSERT(availableTimeZones.has(lookup), "Invalid time zone name");
 
     if (TimeZoneMap::Ptr p = ianaLinksCanonicalizedDifferentlyByICU.lookup(lookup)) {
         // The effectively supported time zones aren't known at compile time,
         // when
         // 1. SpiderMonkey was compiled with "--with-system-icu".
         // 2. ICU's dynamic time zone data loading feature was used.
         //    (ICU supports loading time zone files at runtime through the
@@ -2429,52 +2435,54 @@ js::intl_patternForSkeleton(JSContext* c
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(args[0].isString());
     MOZ_ASSERT(args[1].isString());
 
     JSAutoByteString locale(cx, args[0].toString());
     if (!locale)
         return false;
 
-    AutoStableStringChars skeleton(cx);
-    if (!skeleton.initTwoByte(cx, args[1].toString()))
+    JSFlatString* skeletonFlat = args[1].toString()->ensureFlat(cx);
+    if (!skeletonFlat)
         return false;
 
-    mozilla::Range<const char16_t> skeletonChars = skeleton.twoByteRange();
+    AutoStableStringChars stableChars(cx);
+    if (!stableChars.initTwoByte(cx, skeletonFlat))
+        return false;
+
+    mozilla::Range<const char16_t> skeletonChars = stableChars.twoByteRange();
+    uint32_t skeletonLen = u_strlen(Char16ToUChar(skeletonChars.begin().get()));
 
     UErrorCode status = U_ZERO_ERROR;
     UDateTimePatternGenerator* gen = udatpg_open(icuLocale(locale.ptr()), &status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
     ScopedICUObject<UDateTimePatternGenerator, udatpg_close> toClose(gen);
 
-    Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
-    if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
+    int32_t size = udatpg_getBestPattern(gen, Char16ToUChar(skeletonChars.begin().get()),
+                                         skeletonLen, nullptr, 0, &status);
+    if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
-
-    int32_t size = udatpg_getBestPattern(gen, Char16ToUChar(skeletonChars.begin().get()),
-                                         skeletonChars.length(), Char16ToUChar(chars.begin()),
-                                         INITIAL_CHAR_BUFFER_SIZE, &status);
-    if (status == U_BUFFER_OVERFLOW_ERROR) {
-        MOZ_ASSERT(size >= 0);
-        if (!chars.resize(size))
-            return false;
-        status = U_ZERO_ERROR;
-        udatpg_getBestPattern(gen, Char16ToUChar(skeletonChars.begin().get()),
-                              skeletonChars.length(), Char16ToUChar(chars.begin()), size, &status);
     }
+    ScopedJSFreePtr<UChar> pattern(cx->pod_malloc<UChar>(size + 1));
+    if (!pattern)
+        return false;
+    pattern[size] = '\0';
+    status = U_ZERO_ERROR;
+    udatpg_getBestPattern(gen, Char16ToUChar(skeletonChars.begin().get()),
+                          skeletonLen, pattern, size, &status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
-    MOZ_ASSERT(size >= 0);
-    JSString* str = NewStringCopyN<CanGC>(cx, chars.begin(), size);
+    RootedString str(cx, JS_NewUCStringCopyZ(cx, reinterpret_cast<char16_t*>(pattern.get())));
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
 /**
  * Returns a new UDateFormat with the locale and date-time formatting options
@@ -2497,36 +2505,39 @@ NewUDateFormat(JSContext* cx, HandleObje
 
     // We don't need to look at calendar and numberingSystem - they can only be
     // set via the Unicode locale extension and are therefore already set on
     // locale.
 
     if (!GetProperty(cx, internals, internals, cx->names().timeZone, &value))
         return nullptr;
 
-    AutoStableStringChars timeZone(cx);
-    if (!timeZone.initTwoByte(cx, value.toString()))
+    AutoStableStringChars timeZoneChars(cx);
+    Rooted<JSFlatString*> timeZoneFlat(cx, value.toString()->ensureFlat(cx));
+    if (!timeZoneFlat || !timeZoneChars.initTwoByte(cx, timeZoneFlat))
         return nullptr;
 
-    mozilla::Range<const char16_t> timeZoneChars = timeZone.twoByteRange();
+    const UChar* uTimeZone = Char16ToUChar(timeZoneChars.twoByteRange().begin().get());
+    uint32_t uTimeZoneLength = u_strlen(uTimeZone);
 
     if (!GetProperty(cx, internals, internals, cx->names().pattern, &value))
         return nullptr;
 
-    AutoStableStringChars pattern(cx);
-    if (!pattern.initTwoByte(cx, value.toString()))
+    AutoStableStringChars patternChars(cx);
+    Rooted<JSFlatString*> patternFlat(cx, value.toString()->ensureFlat(cx));
+    if (!patternFlat || !patternChars.initTwoByte(cx, patternFlat))
         return nullptr;
 
-    mozilla::Range<const char16_t> patternChars = pattern.twoByteRange();
+    const UChar* uPattern = Char16ToUChar(patternChars.twoByteRange().begin().get());
+    uint32_t uPatternLength = u_strlen(uPattern);
 
     UErrorCode status = U_ZERO_ERROR;
     UDateFormat* df =
-        udat_open(UDAT_PATTERN, UDAT_PATTERN, icuLocale(locale.ptr()),
-                  Char16ToUChar(timeZoneChars.begin().get()), timeZoneChars.length(),
-                  Char16ToUChar(patternChars.begin().get()), patternChars.length(), &status);
+        udat_open(UDAT_PATTERN, UDAT_PATTERN, icuLocale(locale.ptr()), uTimeZone, uTimeZoneLength,
+                  uPattern, uPatternLength, &status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return nullptr;
     }
 
     // ECMAScript requires the Gregorian calendar to be used from the beginning
     // of ECMAScript time.
     UCalendar* cal = const_cast<UCalendar*>(udat_getCalendar(df));
@@ -2544,31 +2555,29 @@ intl_FormatDateTime(JSContext* cx, UDate
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATE_NOT_FINITE);
         return false;
     }
 
     Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
     if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
         return false;
     UErrorCode status = U_ZERO_ERROR;
-    int32_t size = udat_format(df, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE,
-                               nullptr, &status);
+    int size = udat_format(df, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE,
+                           nullptr, &status);
     if (status == U_BUFFER_OVERFLOW_ERROR) {
-        MOZ_ASSERT(size >= 0);
         if (!chars.resize(size))
             return false;
         status = U_ZERO_ERROR;
         udat_format(df, x, Char16ToUChar(chars.begin()), size, nullptr, &status);
     }
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
-    MOZ_ASSERT(size >= 0);
     JSString* str = NewStringCopyN<CanGC>(cx, chars.begin(), size);
     if (!str)
         return false;
 
     result.setString(str);
 
     return true;
 }
@@ -2676,36 +2685,33 @@ intl_FormatToPartsDateTime(JSContext* cx
     UErrorCode status = U_ZERO_ERROR;
     UFieldPositionIterator* fpositer = ufieldpositer_open(&status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
     auto closeFieldPosIter = MakeScopeExit([&]() { ufieldpositer_close(fpositer); });
 
-    int32_t resultSize =
+    int resultSize =
         udat_formatForFields(df, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE,
                              fpositer, &status);
     if (status == U_BUFFER_OVERFLOW_ERROR) {
-        MOZ_ASSERT(resultSize >= 0);
         if (!chars.resize(resultSize))
             return false;
         status = U_ZERO_ERROR;
         udat_formatForFields(df, x, Char16ToUChar(chars.begin()), resultSize, fpositer, &status);
     }
     if (U_FAILURE(status)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
     RootedArrayObject partsArray(cx, NewDenseEmptyArray(cx));
     if (!partsArray)
         return false;
-
-    MOZ_ASSERT(resultSize >= 0);
     if (resultSize == 0) {
         // An empty string contains no parts, so avoid extra work below.
         result.setObject(*partsArray);
         return true;
     }
 
     RootedString overallResult(cx, NewStringCopyN<CanGC>(cx, chars.begin(), resultSize));
     if (!overallResult)
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -77,17 +77,17 @@ class SharedIntlData
                 const JS::Latin1Char* latin1Chars;
                 const char16_t* twoByteChars;
             };
             bool isLatin1;
             size_t length;
             JS::AutoCheckCannotGC nogc;
             HashNumber hash;
 
-            explicit Lookup(JSLinearString* timeZone);
+            explicit Lookup(JSFlatString* timeZone);
         };
 
         static js::HashNumber hash(const Lookup& lookup) { return lookup.hash; }
         static bool match(TimeZoneName key, const Lookup& lookup);
     };
 
     using TimeZoneSet = js::GCHashSet<TimeZoneName,
                                       TimeZoneHasher,