From c4aadf04aa9c089c6251478f23e941bfa03b3cad Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Fri, 30 Mar 2018 18:58:51 +0200 Subject: Bug 1287677 - Add mozIntl.getDisplayNames API --- js/src/builtin/Intl.cpp | 381 +++++++++++++++++++++++++++++++++++ js/src/builtin/Intl.h | 54 +++++ js/src/js.msg | 2 + js/src/shell/js.cpp | 1 + js/src/tests/Intl/getDisplayNames.js | 238 ++++++++++++++++++++++ js/src/vm/SelfHosting.cpp | 1 + 6 files changed, 677 insertions(+) create mode 100644 js/src/tests/Intl/getDisplayNames.js (limited to 'js') diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 3a20c487b..cd808cb10 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -102,6 +102,18 @@ Char16ToUChar(char16_t* chars) MOZ_CRASH("Char16ToUChar: Intl API disabled"); } +inline char16_t* +UCharToChar16(UChar* chars) +{ + MOZ_CRASH("UCharToChar16: Intl API disabled"); +} + +inline const char16_t* +UCharToChar16(const UChar* chars) +{ + MOZ_CRASH("UCharToChar16: Intl API disabled"); +} + static int32_t u_strlen(const UChar* s) { @@ -356,6 +368,27 @@ enum UCalendarDateFields { UCAL_DAY_OF_MONTH = UCAL_DATE }; +enum UCalendarMonths { + UCAL_JANUARY, + UCAL_FEBRUARY, + UCAL_MARCH, + UCAL_APRIL, + UCAL_MAY, + UCAL_JUNE, + UCAL_JULY, + UCAL_AUGUST, + UCAL_SEPTEMBER, + UCAL_OCTOBER, + UCAL_NOVEMBER, + UCAL_DECEMBER, + UCAL_UNDECIMBER +}; + +enum UCalendarAMPMs { + UCAL_AM, + UCAL_PM +}; + static UCalendar* ucal_open(const UChar* zoneID, int32_t len, const char* locale, UCalendarType type, UErrorCode* status) @@ -420,6 +453,13 @@ ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* statu MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled"); } +enum UDateTimePatternField { + UDATPG_YEAR_FIELD, + UDATPG_MONTH_FIELD, + UDATPG_WEEK_OF_YEAR_FIELD, + UDATPG_DAY_FIELD, +}; + typedef void* UDateTimePatternGenerator; static UDateTimePatternGenerator* @@ -436,6 +476,14 @@ udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton, MOZ_CRASH("udatpg_getBestPattern: Intl API disabled"); } +static const UChar * +udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg, + UDateTimePatternField field, + int32_t *pLength) +{ + MOZ_CRASH("udatpg_getAppendItemName: Intl API disabled"); +} + static void udatpg_close(UDateTimePatternGenerator* dtpg) { @@ -488,10 +536,46 @@ enum UDateFormatField { }; enum UDateFormatStyle { + UDAT_FULL, + UDAT_LONG, + UDAT_MEDIUM, + UDAT_SHORT, + UDAT_DEFAULT = UDAT_MEDIUM, UDAT_PATTERN = -2, UDAT_IGNORE = UDAT_PATTERN }; +enum UDateFormatSymbolType { + UDAT_ERAS, + UDAT_MONTHS, + UDAT_SHORT_MONTHS, + UDAT_WEEKDAYS, + UDAT_SHORT_WEEKDAYS, + UDAT_AM_PMS, + UDAT_LOCALIZED_CHARS, + UDAT_ERA_NAMES, + UDAT_NARROW_MONTHS, + UDAT_NARROW_WEEKDAYS, + UDAT_STANDALONE_MONTHS, + UDAT_STANDALONE_SHORT_MONTHS, + UDAT_STANDALONE_NARROW_MONTHS, + UDAT_STANDALONE_WEEKDAYS, + UDAT_STANDALONE_SHORT_WEEKDAYS, + UDAT_STANDALONE_NARROW_WEEKDAYS, + UDAT_QUARTERS, + UDAT_SHORT_QUARTERS, + UDAT_STANDALONE_QUARTERS, + UDAT_STANDALONE_SHORT_QUARTERS, + UDAT_SHORTER_WEEKDAYS, + UDAT_STANDALONE_SHORTER_WEEKDAYS, + UDAT_CYCLIC_YEARS_WIDE, + UDAT_CYCLIC_YEARS_ABBREVIATED, + UDAT_CYCLIC_YEARS_NARROW, + UDAT_ZODIAC_NAMES_WIDE, + UDAT_ZODIAC_NAMES_ABBREVIATED, + UDAT_ZODIAC_NAMES_NARROW +}; + static int32_t udat_countAvailable() { @@ -563,6 +647,13 @@ udat_close(UDateFormat* format) MOZ_CRASH("udat_close: Intl API disabled"); } +static int32_t +udat_getSymbols(const UDateFormat *fmt, UDateFormatSymbolType type, int32_t symbolIndex, + UChar *result, int32_t resultLength, UErrorCode *status) +{ + MOZ_CRASH("udat_getSymbols: Intl API disabled"); +} + #endif @@ -2921,6 +3012,296 @@ js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp) return true; } +template +inline bool +MatchPart(const char** pattern, const char (&part)[N]) +{ + if (strncmp(*pattern, part, N - 1)) + return false; + + *pattern += N - 1; + return true; +} + +bool +js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 3); + // 1. Assert: locale is a string. + MOZ_ASSERT(args[0].isString()); + // 2. Assert: style is a string. + MOZ_ASSERT(args[1].isString()); + // 3. Assert: keys is an Array. + MOZ_ASSERT(args[2].isObject()); + + JSAutoByteString locale(cx, args[0].toString()); + if (!locale) + return false; + + JSAutoByteString style(cx, args[1].toString()); + if (!style) + return false; + + RootedArrayObject keys(cx, &args[2].toObject().as()); + if (!keys) + return false; + + // 4. Let result be ArrayCreate(0). + RootedArrayObject result(cx, NewDenseUnallocatedArray(cx, keys->length())); + if (!result) + return false; + + UErrorCode status = U_ZERO_ERROR; + + UDateFormat* fmt = + udat_open(UDAT_DEFAULT, UDAT_DEFAULT, icuLocale(locale.ptr()), + nullptr, 0, nullptr, 0, &status); + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + ScopedICUObject datToClose(fmt); + + // UDateTimePatternGenerator will be needed for translations of date and + // time fields like "month", "week", "day" etc. + UDateTimePatternGenerator* dtpg = udatpg_open(icuLocale(locale.ptr()), &status); + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + ScopedICUObject datPgToClose(dtpg); + + RootedValue keyValue(cx); + RootedString keyValStr(cx); + RootedValue wordVal(cx); + Vector chars(cx); + if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE)) + return false; + + // 5. For each element of keys, + for (uint32_t i = 0; i < keys->length(); i++) { + /** + * We iterate over keys array looking for paths that we have code + * branches for. + * + * For any unknown path branch, the wordVal will keep NullValue and + * we'll throw at the end. + */ + + if (!GetElement(cx, keys, keys, i, &keyValue)) + return false; + + JSAutoByteString pattern; + keyValStr = keyValue.toString(); + if (!pattern.encodeUtf8(cx, keyValStr)) + return false; + + wordVal.setNull(); + + // 5.a. Perform an implementation dependent algorithm to map a key to a + // corresponding display name. + const char* pat = pattern.ptr(); + + if (!MatchPart(&pat, "dates")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (MatchPart(&pat, "fields")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + UDateTimePatternField fieldType; + + if (MatchPart(&pat, "year")) { + fieldType = UDATPG_YEAR_FIELD; + } else if (MatchPart(&pat, "month")) { + fieldType = UDATPG_MONTH_FIELD; + } else if (MatchPart(&pat, "week")) { + fieldType = UDATPG_WEEK_OF_YEAR_FIELD; + } else if (MatchPart(&pat, "day")) { + fieldType = UDATPG_DAY_FIELD; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + // This part must be the final part with no trailing data. + if (*pat != '\0') { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + int32_t resultSize; + + const UChar* value = udatpg_getAppendItemName(dtpg, fieldType, &resultSize); + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + + JSString* word = NewStringCopyN(cx, UCharToChar16(value), resultSize); + if (!word) + return false; + + wordVal.setString(word); + } else if (MatchPart(&pat, "gregorian")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + UDateFormatSymbolType symbolType; + int32_t index; + + if (MatchPart(&pat, "months")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (equal(style, "narrow")) { + symbolType = UDAT_STANDALONE_NARROW_MONTHS; + } else if (equal(style, "short")) { + symbolType = UDAT_STANDALONE_SHORT_MONTHS; + } else { + MOZ_ASSERT(equal(style, "long")); + symbolType = UDAT_STANDALONE_MONTHS; + } + + if (MatchPart(&pat, "january")) { + index = UCAL_JANUARY; + } else if (MatchPart(&pat, "february")) { + index = UCAL_FEBRUARY; + } else if (MatchPart(&pat, "march")) { + index = UCAL_MARCH; + } else if (MatchPart(&pat, "april")) { + index = UCAL_APRIL; + } else if (MatchPart(&pat, "may")) { + index = UCAL_MAY; + } else if (MatchPart(&pat, "june")) { + index = UCAL_JUNE; + } else if (MatchPart(&pat, "july")) { + index = UCAL_JULY; + } else if (MatchPart(&pat, "august")) { + index = UCAL_AUGUST; + } else if (MatchPart(&pat, "september")) { + index = UCAL_SEPTEMBER; + } else if (MatchPart(&pat, "october")) { + index = UCAL_OCTOBER; + } else if (MatchPart(&pat, "november")) { + index = UCAL_NOVEMBER; + } else if (MatchPart(&pat, "december")) { + index = UCAL_DECEMBER; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + } else if (MatchPart(&pat, "weekdays")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (equal(style, "narrow")) { + symbolType = UDAT_STANDALONE_NARROW_WEEKDAYS; + } else if (equal(style, "short")) { + symbolType = UDAT_STANDALONE_SHORT_WEEKDAYS; + } else { + MOZ_ASSERT(equal(style, "long")); + symbolType = UDAT_STANDALONE_WEEKDAYS; + } + + if (MatchPart(&pat, "monday")) { + index = UCAL_MONDAY; + } else if (MatchPart(&pat, "tuesday")) { + index = UCAL_TUESDAY; + } else if (MatchPart(&pat, "wednesday")) { + index = UCAL_WEDNESDAY; + } else if (MatchPart(&pat, "thursday")) { + index = UCAL_THURSDAY; + } else if (MatchPart(&pat, "friday")) { + index = UCAL_FRIDAY; + } else if (MatchPart(&pat, "saturday")) { + index = UCAL_SATURDAY; + } else if (MatchPart(&pat, "sunday")) { + index = UCAL_SUNDAY; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + } else if (MatchPart(&pat, "dayperiods")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + symbolType = UDAT_AM_PMS; + + if (MatchPart(&pat, "am")) { + index = UCAL_AM; + } else if (MatchPart(&pat, "pm")) { + index = UCAL_PM; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + // This part must be the final part with no trailing data. + if (*pat != '\0') { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + int32_t resultSize = + udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()), + INITIAL_CHAR_BUFFER_SIZE, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + if (!chars.resize(resultSize)) + return false; + status = U_ZERO_ERROR; + udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()), + resultSize, &status); + } + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + + JSString* word = NewStringCopyN(cx, chars.begin(), resultSize); + if (!word) + return false; + + wordVal.setString(word); + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + MOZ_ASSERT(wordVal.isString()); + + // 5.b. Append the result string to result. + if (!DefineElement(cx, result, i, wordVal)) + return false; + } + + // 6. Return result. + args.rval().setObject(*result); + return true; +} + /******************** Intl ********************/ const Class js::IntlClass = { diff --git a/js/src/builtin/Intl.h b/js/src/builtin/Intl.h index 54764605b..b2197060d 100644 --- a/js/src/builtin/Intl.h +++ b/js/src/builtin/Intl.h @@ -387,6 +387,48 @@ intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp); extern MOZ_MUST_USE bool intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp); +/** + * Returns an Array with CLDR-based fields display names. + * The function takes three arguments: + * + * locale + * BCP47 compliant locale string + * style + * A string with values: long or short or narrow + * keys + * An array or path-like strings that identify keys to be returned + * At the moment the following types of keys are supported: + * + * 'dates/fields/{year|month|week|day}' + * 'dates/gregorian/months/{january|...|december}' + * 'dates/gregorian/weekdays/{sunday|...|saturday}' + * 'dates/gregorian/dayperiods/{am|pm}' + * + * Example: + * + * let info = intl_ComputeDisplayNames( + * 'en-US', + * 'long', + * [ + * 'dates/fields/year', + * 'dates/gregorian/months/january', + * 'dates/gregorian/weekdays/monday', + * 'dates/gregorian/dayperiods/am', + * ] + * ); + * + * Returned value: + * + * [ + * 'year', + * 'January', + * 'Monday', + * 'AM' + * ] + */ +extern MOZ_MUST_USE bool +intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp); + #if ENABLE_INTL_API /** * Cast char16_t* strings to UChar* strings used by ICU. @@ -402,6 +444,18 @@ Char16ToUChar(char16_t* chars) { return reinterpret_cast(chars); } + +inline char16_t* +UCharToChar16(UChar* chars) +{ + return reinterpret_cast(chars); +} + +inline const char16_t* +UCharToChar16(const UChar* chars) +{ + return reinterpret_cast(chars); +} #endif // ENABLE_INTL_API } // namespace js diff --git a/js/src/js.msg b/js/src/js.msg index 8d492f523..a276dab94 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -474,6 +474,8 @@ MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} MSG_DEF(JSMSG_INTL_OBJECT_REINITED, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor") MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}") MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}") +MSG_DEF(JSMSG_INVALID_KEYS_TYPE, 0, JSEXN_TYPEERR, "calendar info keys must be an object or undefined") +MSG_DEF(JSMSG_INVALID_KEY, 1, JSEXN_RANGEERR, "invalid key: {0}") MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG, 1, JSEXN_RANGEERR, "invalid language tag: {0}") MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument") MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}") diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index cc68c90d5..8d69ca942 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -906,6 +906,7 @@ AddIntlExtras(JSContext* cx, unsigned argc, Value* vp) static const JSFunctionSpec funcs[] = { JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0), + JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0), JS_FS_END }; diff --git a/js/src/tests/Intl/getDisplayNames.js b/js/src/tests/Intl/getDisplayNames.js new file mode 100644 index 000000000..ad2dbc940 --- /dev/null +++ b/js/src/tests/Intl/getDisplayNames.js @@ -0,0 +1,238 @@ +// |reftest| skip-if(!this.hasOwnProperty('Intl')||!this.hasOwnProperty('addIntlExtras')) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCalendarInfo function with a diverse set of arguments. + +/* + * Test if getDisplayNames return value matches expected values. + */ +function checkDisplayNames(names, expected) +{ + assertEq(Object.getPrototypeOf(names), Object.prototype); + + assertEq(names.locale, expected.locale); + assertEq(names.style, expected.style); + + const nameValues = names.values; + const expectedValues = expected.values; + + const nameValuesKeys = Object.getOwnPropertyNames(nameValues).sort(); + const expectedValuesKeys = Object.getOwnPropertyNames(expectedValues).sort(); + + assertEqArray(nameValuesKeys, expectedValuesKeys); + + for (let key of expectedValuesKeys) + assertEq(nameValues[key], expectedValues[key]); +} + +addIntlExtras(Intl); + +let gDN = Intl.getDisplayNames; + +assertEq(gDN.length, 2); + +checkDisplayNames(gDN('en-US', { +}), { + locale: 'en-US', + style: 'long', + values: {} +}); + +checkDisplayNames(gDN('en-US', { + keys: [ + 'dates/gregorian/weekdays/wednesday' + ], + style: 'narrow' +}), { + locale: 'en-US', + style: 'narrow', + values: { + 'dates/gregorian/weekdays/wednesday': 'W' + } +}); + +checkDisplayNames(gDN('en-US', { + keys: [ + 'dates/fields/year', + 'dates/fields/month', + 'dates/fields/week', + 'dates/fields/day', + 'dates/gregorian/months/january', + 'dates/gregorian/months/february', + 'dates/gregorian/months/march', + 'dates/gregorian/weekdays/tuesday' + ] +}), { + locale: 'en-US', + style: 'long', + values: { + 'dates/fields/year': 'year', + 'dates/fields/month': 'month', + 'dates/fields/week': 'week', + 'dates/fields/day': 'day', + 'dates/gregorian/months/january': 'January', + 'dates/gregorian/months/february': 'February', + 'dates/gregorian/months/march': 'March', + 'dates/gregorian/weekdays/tuesday': 'Tuesday', + } +}); + +checkDisplayNames(gDN('fr', { + keys: [ + 'dates/fields/year', + 'dates/fields/day', + 'dates/gregorian/months/october', + 'dates/gregorian/weekdays/saturday', + 'dates/gregorian/dayperiods/pm' + ] +}), { + locale: 'fr', + style: 'long', + values: { + 'dates/fields/year': 'année', + 'dates/fields/day': 'jour', + 'dates/gregorian/months/october': 'octobre', + 'dates/gregorian/weekdays/saturday': 'samedi', + 'dates/gregorian/dayperiods/pm': 'PM' + } +}); + +checkDisplayNames(gDN('it', { + style: 'short', + keys: [ + 'dates/gregorian/weekdays/thursday', + 'dates/gregorian/months/august', + 'dates/gregorian/dayperiods/am', + 'dates/fields/month', + ] +}), { + locale: 'it', + style: 'short', + values: { + 'dates/gregorian/weekdays/thursday': 'gio', + 'dates/gregorian/months/august': 'ago', + 'dates/gregorian/dayperiods/am': 'AM', + 'dates/fields/month': 'mese' + } +}); + +checkDisplayNames(gDN('ar', { + style: 'long', + keys: [ + 'dates/gregorian/weekdays/thursday', + 'dates/gregorian/months/august', + 'dates/gregorian/dayperiods/am', + 'dates/fields/month', + ] +}), { + locale: 'ar', + style: 'long', + values: { + 'dates/gregorian/weekdays/thursday': 'الخميس', + 'dates/gregorian/months/august': 'أغسطس', + 'dates/gregorian/dayperiods/am': 'ص', + 'dates/fields/month': 'الشهر' + } +}); + +/* Invalid input */ + +assertThrowsInstanceOf(() => { + gDN('en-US', { + style: '', + keys: [ + 'dates/gregorian/weekdays/thursday', + ] + }); +}, RangeError); + +assertThrowsInstanceOf(() => { + gDN('en-US', { + style: 'bogus', + keys: [ + 'dates/gregorian/weekdays/thursday', + ] + }); +}, RangeError); + +assertThrowsInstanceOf(() => { + gDN('foo-X', { + keys: [ + 'dates/gregorian/weekdays/thursday', + ] + }); +}, RangeError); + +const typeErrorKeys = [ + null, + 'string', + Symbol.iterator, + 15, + 1, + 3.7, + NaN, + Infinity +]; + +for (let keys of typeErrorKeys) { + assertThrowsInstanceOf(() => { + gDN('en-US', { + keys + }); + }, TypeError); +} + +const rangeErrorKeys = [ + [''], + ['foo'], + ['dates/foo'], + ['/dates/foo'], + ['dates/foo/foo'], + ['dates/fields'], + ['dates/fields/'], + ['dates/fields/foo'], + ['dates/fields/foo/month'], + ['/dates/foo/faa/bar/baz'], + ['dates///bar/baz'], + ['dates/gregorian'], + ['dates/gregorian/'], + ['dates/gregorian/foo'], + ['dates/gregorian/months'], + ['dates/gregorian/months/foo'], + ['dates/gregorian/weekdays'], + ['dates/gregorian/weekdays/foo'], + ['dates/gregorian/dayperiods'], + ['dates/gregorian/dayperiods/foo'], + ['dates/gregorian/months/الشهر'], + [3], + [null], + ['d', 'a', 't', 'e', 's'], + ['datesEXTRA'], + ['dates/fieldsEXTRA'], + ['dates/gregorianEXTRA'], + ['dates/gregorian/monthsEXTRA'], + ['dates/gregorian/weekdaysEXTRA'], + ['dates/fields/dayperiods/amEXTRA'], + ['dates/gregori\u1161n/months/january'], + ["dates/fields/year/"], + ["dates/fields/month/"], + ["dates/fields/week/"], + ["dates/fields/day/"], + ["dates/gregorian/months/january/"], + ["dates/gregorian/weekdays/saturday/"], + ["dates/gregorian/dayperiods/am/"], + ["dates/fields/months/january/"], +]; + +for (let keys of rangeErrorKeys) { + assertThrowsInstanceOf(() => { + gDN('en-US', { + keys + }); + }, RangeError); +} + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index bf49f2268..9a8ec7679 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2477,6 +2477,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0), JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0), JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0), + JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0), JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0), JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0), JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0), -- cgit v1.2.3 From a77308735f50fb1735bca82ffd0ffaf12a5c9f62 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Fri, 30 Mar 2018 19:11:11 +0200 Subject: Bug 1310078 - Implement valueAsNumber and valueAsDate for --- js/public/Date.h | 8 ++++++++ js/src/jsdate.cpp | 12 ++++++++++++ 2 files changed, 20 insertions(+) (limited to 'js') diff --git a/js/public/Date.h b/js/public/Date.h index cba0ea875..cab36a3de 100644 --- a/js/public/Date.h +++ b/js/public/Date.h @@ -134,6 +134,14 @@ NewDateObject(JSContext* cx, ClippedTime time); JS_PUBLIC_API(double) MakeDate(double year, unsigned month, unsigned day); +// Year is a year, month is 0-11, day is 1-based, and time is in milliseconds. +// The return value is a number of milliseconds since the epoch. +// +// Consistent with the MakeDate algorithm defined in ECMAScript, this value is +// *not* clipped! Use JS::TimeClip if you need a clipped date. +JS_PUBLIC_API(double) +MakeDate(double year, unsigned month, unsigned day, double time); + // Takes an integer number of milliseconds since the epoch and returns the // year. Can return NaN, and will do so if NaN is passed in. JS_PUBLIC_API(double) diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index ccaeda2a3..00a8abf84 100755 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -354,9 +354,21 @@ MakeDate(double day, double time) JS_PUBLIC_API(double) JS::MakeDate(double year, unsigned month, unsigned day) { + MOZ_ASSERT(month <= 11); + MOZ_ASSERT(day >= 1 && day <= 31); + return ::MakeDate(MakeDay(year, month, day), 0); } +JS_PUBLIC_API(double) +JS::MakeDate(double year, unsigned month, unsigned day, double time) +{ + MOZ_ASSERT(month <= 11); + MOZ_ASSERT(day >= 1 && day <= 31); + + return ::MakeDate(MakeDay(year, month, day), time); +} + JS_PUBLIC_API(double) JS::YearFromTime(double time) { -- cgit v1.2.3 From 287ca21a651803ce87347ba584ce93908cd8a9e6 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Sat, 14 Apr 2018 22:20:43 +0200 Subject: moebius#242: XPCOM: exportFunction() - fix wrong .length attribute https://github.com/MoonchildProductions/moebius/pull/243 --- js/xpconnect/src/ExportHelpers.cpp | 11 ++++++++++- js/xpconnect/tests/unit/test_exportFunction.js | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'js') diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index 3dbf83e3b..e574e708c 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -329,11 +329,20 @@ NewFunctionForwarder(JSContext* cx, HandleId idArg, HandleObject callable, if (id == JSID_VOIDHANDLE) id = GetJSIDByIndex(cx, XPCJSContext::IDX_EMPTYSTRING); + // If our callable is a (possibly wrapped) function, we can give + // the exported thing the right number of args. + unsigned nargs = 0; + RootedObject unwrapped(cx, js::UncheckedUnwrap(callable)); + if (unwrapped) { + if (JSFunction* fun = JS_GetObjectFunction(unwrapped)) + nargs = JS_GetFunctionArity(fun); + } + // We have no way of knowing whether the underlying function wants to be a // constructor or not, so we just mark all forwarders as constructors, and // let the underlying function throw for construct calls if it wants. JSFunction* fun = js::NewFunctionByIdWithReserved(cx, FunctionForwarder, - 0, JSFUN_CONSTRUCTOR, id); + nargs, JSFUN_CONSTRUCTOR, id); if (!fun) return false; diff --git a/js/xpconnect/tests/unit/test_exportFunction.js b/js/xpconnect/tests/unit/test_exportFunction.js index 830816342..9e1bf2082 100644 --- a/js/xpconnect/tests/unit/test_exportFunction.js +++ b/js/xpconnect/tests/unit/test_exportFunction.js @@ -10,12 +10,14 @@ function run_test() { epsb.do_check_true = do_check_true; epsb.do_check_eq = do_check_eq; subsb.do_check_true = do_check_true; + subsb.do_check_eq = do_check_eq; // Exporting should work if prinicipal of the source sandbox // subsumes the principal of the target sandbox. Cu.evalInSandbox("(" + function() { var wasCalled = false; this.funToExport = function(expectedThis, a, obj, native, mixed, callback) { + do_check_eq(arguments.callee.length, 6); do_check_eq(a, 42); do_check_eq(obj, subsb.tobecloned); do_check_eq(obj.cloned, "cloned"); @@ -53,6 +55,7 @@ function run_test() { invokedCallback = false; callback = function() { invokedCallback = true; }; imported(this, 42, tobecloned, native, mixed, callback); + do_check_eq(imported.length, 6); do_check_true(invokedCallback); }.toSource() + ")()", subsb); -- cgit v1.2.3 From 3cf71e45130b161ff5e3412898babfe13dec4bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Wed, 4 Apr 2018 15:31:16 +0200 Subject: Bug 1449574 - Update tzdata in ICU data files to 2018d. r=Waldo, a=RyanVM --- js/src/builtin/IntlTimeZoneData.h | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'js') diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index f92c583df..3d5c1b0d5 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js index 890b1c1d5..7b3a46a60 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js index 19fd871eb..ed63df921 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js index 34425acec..215808765 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js index 8b2dedec2..48242dfbd 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, -- cgit v1.2.3 From 9472136272f01b858412f2d9d7854d2daa82496f Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 10 Apr 2018 15:00:49 +0200 Subject: Bug 1444668 - Avoid allocating large AssemblerBuffers. r=luke, r=bbouvier, a=RyanVM --- js/src/jit/MacroAssembler.cpp | 6 ++++ js/src/jit/ProcessExecutableMemory.cpp | 8 ------ js/src/jit/ProcessExecutableMemory.h | 8 ++++++ js/src/jit/shared/IonAssemblerBuffer.h | 4 +++ js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h | 32 +++++++++++++++++++++- 5 files changed, 49 insertions(+), 9 deletions(-) (limited to 'js') diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index f633b9b7b..9dbbe7624 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2214,6 +2214,12 @@ MacroAssembler::finish() } MacroAssemblerSpecific::finish(); + + MOZ_RELEASE_ASSERT(size() <= MaxCodeBytesPerProcess, + "AssemblerBuffer should ensure we don't exceed MaxCodeBytesPerProcess"); + + if (bytesNeeded() > MaxCodeBytesPerProcess) + setOOM(); } void diff --git a/js/src/jit/ProcessExecutableMemory.cpp b/js/src/jit/ProcessExecutableMemory.cpp index 71c2ab0dc..301541541 100644 --- a/js/src/jit/ProcessExecutableMemory.cpp +++ b/js/src/jit/ProcessExecutableMemory.cpp @@ -385,14 +385,6 @@ class PageBitSet #endif }; -// Limit on the number of bytes of executable memory to prevent JIT spraying -// attacks. -#if JS_BITS_PER_WORD == 32 -static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; -#else -static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; -#endif - // Per-process executable memory allocator. It reserves a block of memory of // MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that. // diff --git a/js/src/jit/ProcessExecutableMemory.h b/js/src/jit/ProcessExecutableMemory.h index 078ce7cb7..a0e2fab98 100644 --- a/js/src/jit/ProcessExecutableMemory.h +++ b/js/src/jit/ProcessExecutableMemory.h @@ -17,6 +17,14 @@ namespace jit { // alignment though. static const size_t ExecutableCodePageSize = 64 * 1024; +// Limit on the number of bytes of executable memory to prevent JIT spraying +// attacks. +#if JS_BITS_PER_WORD == 32 +static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; +#else +static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; +#endif + enum class ProtectionSetting { Protected, // Not readable, writable, or executable. Writable, diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index cc20e26d2..3a6552696 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -181,6 +181,10 @@ class AssemblerBuffer protected: virtual Slice* newSlice(LifoAlloc& a) { + if (size() > MaxCodeBytesPerProcess - sizeof(Slice)) { + fail_oom(); + return nullptr; + } Slice* tmp = static_cast(a.alloc(sizeof(Slice))); if (!tmp) { fail_oom(); diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index 8cb557784..fe678fc7d 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -68,6 +68,33 @@ namespace js { namespace jit { + // AllocPolicy for AssemblerBuffer. OOMs when trying to allocate more than + // MaxCodeBytesPerProcess bytes. Use private inheritance to make sure we + // explicitly have to expose SystemAllocPolicy methods. + class AssemblerBufferAllocPolicy : private SystemAllocPolicy + { + public: + using SystemAllocPolicy::checkSimulatedOOM; + using SystemAllocPolicy::reportAllocOverflow; + using SystemAllocPolicy::free_; + + template T* pod_realloc(T* p, size_t oldSize, size_t newSize) { + static_assert(sizeof(T) == 1, + "AssemblerBufferAllocPolicy should only be used with byte vectors"); + MOZ_ASSERT(oldSize <= MaxCodeBytesPerProcess); + if (MOZ_UNLIKELY(newSize > MaxCodeBytesPerProcess)) + return nullptr; + return SystemAllocPolicy::pod_realloc(p, oldSize, newSize); + } + template T* pod_malloc(size_t numElems) { + static_assert(sizeof(T) == 1, + "AssemblerBufferAllocPolicy should only be used with byte vectors"); + if (MOZ_UNLIKELY(numElems > MaxCodeBytesPerProcess)) + return nullptr; + return SystemAllocPolicy::pod_malloc(numElems); + } + }; + class AssemblerBuffer { template @@ -93,6 +120,9 @@ namespace jit { void ensureSpace(size_t space) { + // This should only be called with small |space| values to ensure + // we don't overflow below. + MOZ_ASSERT(space <= 16); if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space))) oomDetected(); } @@ -168,7 +198,7 @@ namespace jit { m_buffer.clear(); } - PageProtectingVector m_buffer; + PageProtectingVector m_buffer; bool m_oom; }; -- cgit v1.2.3 From f7edee79a1ccbb94d0ef61ad392d764a600fd5a8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 24 Apr 2018 20:27:06 +0200 Subject: Remove build support for HP-UX Note: 3rd party lib support (NSS, etc.) has not been touched. --- js/src/Makefile.in | 7 ------- js/src/jstypes.h | 4 ---- js/src/moz.build | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'js') diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 3be6a6781..b007954b1 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -147,13 +147,6 @@ ifeq ($(OS_ARCH),AIX) CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 endif -ifeq ($(OS_ARCH),HP-UX) -# Suppress warnings from aCC -# 3055: anonymous unions declaring types -# 4189: offsetof() on non-POD types -CFLAGS += +W3055,4189 -CXXFLAGS += +W3055,4189 -endif endif ifeq ($(OS_ARCH),SunOS) ifeq ($(TARGET_CPU),sparc) diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 6593d2067..75774e5b8 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -160,10 +160,6 @@ # if defined(__64BIT__) # define JS_64BIT # endif -#elif defined(__HP_cc) || defined(__HP_aCC) /* HP-UX cc/aCC */ -# if defined(__LP64__) -# define JS_64BIT -# endif #else # error "Implement me" #endif diff --git a/js/src/moz.build b/js/src/moz.build index a18170a75..2d4e83db3 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -708,7 +708,7 @@ if CONFIG['_MSC_VER']: CXXFLAGS += ['-wd4577'] CXXFLAGS += ['-wd4312'] -if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'): +if CONFIG['OS_ARCH'] not in ('WINNT'): OS_LIBS += [ 'm', ] -- cgit v1.2.3 From 9349f7f29e108da8ddb8684dd9e70201895db1b4 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 25 Apr 2018 08:26:25 +0200 Subject: Revert "Add pluralrules to JS Intl" This reverts commit 7686bceecff17f91758c8c6547a78e71ff3a8c38. --- js/src/builtin/Intl.js | 626 +++++---------------- .../resolvedOptions-overridden-species.js | 27 - .../Intl/getCanonicalLocales-overridden-species.js | 23 - 3 files changed, 134 insertions(+), 542 deletions(-) delete mode 100644 js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js delete mode 100644 js/src/tests/Intl/getCanonicalLocales-overridden-species.js (limited to 'js') diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js index 37c87365b..493062c1c 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -9,8 +9,7 @@ JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false, JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false, JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false, - JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false, - JSMSG_INVALID_KEY: false, + JSMSG_DATE_NOT_FINITE: false, intl_Collator_availableLocales: false, intl_availableCollations: false, intl_CompareStrings: false, @@ -21,9 +20,6 @@ intl_availableCalendars: false, intl_patternForSkeleton: false, intl_FormatDateTime: false, - intl_SelectPluralRule: false, - intl_GetPluralCategories: false, - intl_GetCalendarInfo: false, */ /* @@ -436,7 +432,7 @@ function CanonicalizeLanguageTag(locale) { subtags[i] = subtag; i++; } - var normal = ArrayJoinRange(subtags, "-", 0, i); + var normal = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, 0, i), "-"); // Extension sequences are sorted by their singleton characters. // "u-ca-chinese-t-zh-latn" -> "t-zh-latn-u-ca-chinese" @@ -446,7 +442,7 @@ function CanonicalizeLanguageTag(locale) { i++; while (i < subtags.length && subtags[i].length > 1) i++; - var extension = ArrayJoinRange(subtags, "-", extensionStart, i); + var extension = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, extensionStart, i), "-"); callFunction(std_Array_push, extensions, extension); } callFunction(std_Array_sort, extensions); @@ -454,7 +450,7 @@ function CanonicalizeLanguageTag(locale) { // Private use sequences are left as is. "x-private" var privateUse = ""; if (i < subtags.length) - privateUse = ArrayJoinRange(subtags, "-", i); + privateUse = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, i), "-"); // Put everything back together. var canonical = normal; @@ -471,24 +467,6 @@ function CanonicalizeLanguageTag(locale) { return canonical; } -/** - * Joins the array elements in the given range with the supplied separator. - */ -function ArrayJoinRange(array, separator, from, to = array.length) { - assert(typeof separator === "string", "|separator| is a string value"); - assert(typeof from === "number", "|from| is a number value"); - assert(typeof to === "number", "|to| is a number value"); - assert(0 <= from && from <= to && to <= array.length, "|from| and |to| form a valid range"); - - if (from === to) - return ""; - - var result = array[from]; - for (var i = from + 1; i < to; i++) { - result += separator + array[i]; - } - return result; -} function localeContainsNoUnicodeExtensions(locale) { // No "-u-", no possible Unicode extension. @@ -860,7 +838,6 @@ function BestAvailableLocaleIgnoringDefault(availableLocales, locale) { return BestAvailableLocaleHelper(availableLocales, locale, false); } -var noRelevantExtensionKeys = []; /** * Compares a BCP 47 language priority list against the set of locales in @@ -1188,10 +1165,9 @@ function GetOption(options, property, type, values, fallback) { * Spec: ECMAScript Internationalization API Specification, 9.2.10. */ function GetNumberOption(options, property, minimum, maximum, fallback) { - assert(typeof minimum === "number" && (minimum | 0) === minimum, "GetNumberOption"); - assert(typeof maximum === "number" && (maximum | 0) === maximum, "GetNumberOption"); - assert(typeof fallback === "number" && (fallback | 0) === fallback, "GetNumberOption"); - assert(minimum <= fallback && fallback <= maximum, "GetNumberOption"); + assert(typeof minimum === "number", "GetNumberOption"); + assert(typeof maximum === "number", "GetNumberOption"); + assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption"); // Step 1. var value = options[property]; @@ -1201,10 +1177,7 @@ function GetNumberOption(options, property, minimum, maximum, fallback) { value = ToNumber(value); if (Number_isNaN(value) || value < minimum || value > maximum) ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value); - - // Apply bitwise-or to convert -0 to +0 per ES2017, 5.2 and to ensure - // the result is an int32 value. - return std_Math_floor(value) | 0; + return std_Math_floor(value); } // Step 3. @@ -1278,9 +1251,7 @@ function initializeIntlObject(obj) { function setLazyData(internals, type, lazyData) { assert(internals.type === "partial", "can't set lazy data for anything but a newborn"); - assert(type === "Collator" || type === "DateTimeFormat" || - type == "NumberFormat" || type === "PluralRules", - "bad type"); + assert(type === "Collator" || type === "DateTimeFormat" || type == "NumberFormat", "bad type"); assert(IsObject(lazyData), "non-object lazy data"); // Set in reverse order so that the .type change is a barrier. @@ -1330,9 +1301,7 @@ function isInitializedIntlObject(obj) { if (IsObject(internals)) { assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type"); var type = internals.type; - assert(type === "partial" || type === "Collator" || - type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules", - "unexpected type"); + assert(type === "partial" || type === "Collator" || type === "DateTimeFormat" || type === "NumberFormat", "unexpected type"); assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData"); assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps"); } else { @@ -1389,8 +1358,6 @@ function getInternals(obj) internalProps = resolveCollatorInternals(lazyData) else if (type === "DateTimeFormat") internalProps = resolveDateTimeFormatInternals(lazyData) - else if (type === "PluralRules") - internalProps = resolvePluralRulesInternals(lazyData) else internalProps = resolveNumberFormatInternals(lazyData); setInternalProperties(internals, internalProps); @@ -1722,7 +1689,6 @@ function Intl_Collator_compare_get() { // Step 2. return internals.boundCompare; } -_SetCanonicalName(Intl_Collator_compare_get, "get compare"); /** @@ -1791,37 +1757,45 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { // Step 6. var opt = lazyNumberFormatData.opt; + // Compute effective locale. + // Step 9. var NumberFormat = numberFormatInternalProperties; - // Step 9. + // Step 10. var localeData = NumberFormat.localeData; - // Step 10. + // Step 11. var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat), lazyNumberFormatData.requestedLocales, lazyNumberFormatData.opt, NumberFormat.relevantExtensionKeys, localeData); - // Steps 11-12. (Step 13 is not relevant to our implementation.) + // Steps 12-13. (Step 14 is not relevant to our implementation.) internalProps.locale = r.locale; internalProps.numberingSystem = r.nu; // Compute formatting options. - // Step 15. - var style = lazyNumberFormatData.style; - internalProps.style = style; + // Step 16. + var s = lazyNumberFormatData.style; + internalProps.style = s; - // Steps 19, 21. - if (style === "currency") { + // Steps 20, 22. + if (s === "currency") { internalProps.currency = lazyNumberFormatData.currency; internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay; } + // Step 24. internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits; + + // Steps 27. internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits; + + // Step 30. internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits; + // Step 33. if ("minimumSignificantDigits" in lazyNumberFormatData) { // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the // actual presence (versus undefined-ness) of these properties. @@ -1830,10 +1804,10 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits; } - // Step 27. + // Step 35. internalProps.useGrouping = lazyNumberFormatData.useGrouping; - // Step 34. + // Step 42. internalProps.boundFormat = undefined; // The caller is responsible for associating |internalProps| with the right @@ -1861,44 +1835,6 @@ function getNumberFormatInternals(obj, methodName) { return internalProps; } -/** - * Applies digit options used for number formatting onto the intl object. - * - * Spec: ECMAScript Internationalization API Specification, 11.1.1. - */ -function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) { - // We skip Step 1 because we set the properties on a lazyData object. - - // Step 2-3. - assert(IsObject(options), "SetNumberFormatDigitOptions"); - assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions"); - - // Steps 4-6. - const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); - const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); - const mxfdActualDefault = std_Math_max(mnfd, mxfdDefault); - const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdActualDefault); - - // Steps 7-8. - let mnsd = options.minimumSignificantDigits; - let mxsd = options.maximumSignificantDigits; - - // Steps 9-11. - lazyData.minimumIntegerDigits = mnid; - lazyData.minimumFractionDigits = mnfd; - lazyData.maximumFractionDigits = mxfd; - - // Step 12. - if (mnsd !== undefined || mxsd !== undefined) { - mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); - mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); - lazyData.minimumSignificantDigits = mnsd; - lazyData.maximumSignificantDigits = mxsd; - } -} - /** * Initializes an object as a NumberFormat. @@ -1948,7 +1884,7 @@ function InitializeNumberFormat(numberFormat, locales, options) { // } // // Note that lazy data is only installed as a final step of initialization, - // so every NumberFormat lazy data object has *all* these properties, never a + // so every Collator lazy data object has *all* these properties, never a // subset of them. var lazyNumberFormatData = std_Object_create(null); @@ -1978,46 +1914,67 @@ function InitializeNumberFormat(numberFormat, locales, options) { opt.localeMatcher = matcher; // Compute formatting options. - // Step 14. - var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); - lazyNumberFormatData.style = style; + // Step 15. + var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); + lazyNumberFormatData.style = s; - // Steps 16-19. + // Steps 17-20. var c = GetOption(options, "currency", "string", undefined, undefined); if (c !== undefined && !IsWellFormedCurrencyCode(c)) ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c); var cDigits; - if (style === "currency") { + if (s === "currency") { if (c === undefined) ThrowTypeError(JSMSG_UNDEFINED_CURRENCY); - // Steps 19.a-c. + // Steps 20.a-c. c = toASCIIUpperCase(c); lazyNumberFormatData.currency = c; cDigits = CurrencyDigits(c); } - // Step 20. + // Step 21. var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol"); - if (style === "currency") + if (s === "currency") lazyNumberFormatData.currencyDisplay = cd; - // Steps 22-25. - var mnfdDefault, mxfdDefault; - if (style === "currency") { - mnfdDefault = cDigits; - mxfdDefault = cDigits; - } else { - mnfdDefault = 0; - mxfdDefault = style === "percent" ? 0 : 3; + // Step 23. + var mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); + lazyNumberFormatData.minimumIntegerDigits = mnid; + + // Steps 25-26. + var mnfdDefault = (s === "currency") ? cDigits : 0; + var mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); + lazyNumberFormatData.minimumFractionDigits = mnfd; + + // Steps 28-29. + var mxfdDefault; + if (s === "currency") + mxfdDefault = std_Math_max(mnfd, cDigits); + else if (s === "percent") + mxfdDefault = std_Math_max(mnfd, 0); + else + mxfdDefault = std_Math_max(mnfd, 3); + var mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault); + lazyNumberFormatData.maximumFractionDigits = mxfd; + + // Steps 31-32. + var mnsd = options.minimumSignificantDigits; + var mxsd = options.maximumSignificantDigits; + + // Step 33. + if (mnsd !== undefined || mxsd !== undefined) { + mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); + mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); + lazyNumberFormatData.minimumSignificantDigits = mnsd; + lazyNumberFormatData.maximumSignificantDigits = mxsd; } - SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault); - // Steps 26. + // Step 34. var g = GetOption(options, "useGrouping", "boolean", undefined, true); lazyNumberFormatData.useGrouping = g; - // Steps 35-36. + // Step 43. // // We've done everything that must be done now: mark the lazy data as fully // computed and install it. @@ -2025,6 +1982,43 @@ function InitializeNumberFormat(numberFormat, locales, options) { } +/** + * Mapping from currency codes to the number of decimal digits used for them. + * Default is 2 digits. + * + * Spec: ISO 4217 Currency and Funds Code List. + * http://www.currency-iso.org/en/home/tables/table-a1.html + */ +var currencyDigits = { + BHD: 3, + BIF: 0, + BYR: 0, + CLF: 4, + CLP: 0, + DJF: 0, + GNF: 0, + IQD: 3, + ISK: 0, + JOD: 3, + JPY: 0, + KMF: 0, + KRW: 0, + KWD: 3, + LYD: 3, + OMR: 3, + PYG: 0, + RWF: 0, + TND: 3, + UGX: 0, + UYI: 0, + VND: 0, + VUV: 0, + XAF: 0, + XOF: 0, + XPF: 0 +}; + + /** * Returns the number of decimal digits to be used for the given currency. * @@ -2106,7 +2100,7 @@ function numberFormatFormatToBind(value) { // Step 1.a.ii-iii. var x = ToNumber(value); - return intl_FormatNumber(this, x, /* formatToParts = */ false); + return intl_FormatNumber(this, x); } @@ -2133,22 +2127,6 @@ function Intl_NumberFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_NumberFormat_format_get, "get format"); - - -function Intl_NumberFormat_formatToParts(value) { - // Step 1. - var nf = this; - - // Steps 2-3. - getNumberFormatInternals(nf, "formatToParts"); - - // Step 4. - var x = ToNumber(value); - - // Step 5. - return intl_FormatNumber(nf, x, /* formatToParts = */ true); -} /** @@ -2290,6 +2268,26 @@ function getDateTimeFormatInternals(obj, methodName) { return internalProps; } +/** + * Components of date and time formats and their values. + * + * Spec: ECMAScript Internationalization API Specification, 12.1.1. + */ +var dateTimeComponentValues = { + weekday: ["narrow", "short", "long"], + era: ["narrow", "short", "long"], + year: ["2-digit", "numeric"], + month: ["2-digit", "numeric", "narrow", "short", "long"], + day: ["2-digit", "numeric"], + hour: ["2-digit", "numeric"], + minute: ["2-digit", "numeric"], + second: ["2-digit", "numeric"], + timeZoneName: ["short", "long"] +}; + + +var dateTimeComponents = std_Object_getOwnPropertyNames(dateTimeComponentValues); + /** * Initializes an object as a DateTimeFormat. @@ -2379,19 +2377,12 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) { lazyDateTimeFormatData.formatOpt = formatOpt; // Step 19. - // 12.1, Table 4: Components of date and time formats. - formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"], - undefined); - formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined); - formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined); - formatOpt.month = GetOption(options, "month", "string", - ["2-digit", "numeric", "narrow", "short", "long"], undefined); - formatOpt.day = GetOption(options, "day", "string", ["2-digit", "numeric"], undefined); - formatOpt.hour = GetOption(options, "hour", "string", ["2-digit", "numeric"], undefined); - formatOpt.minute = GetOption(options, "minute", "string", ["2-digit", "numeric"], undefined); - formatOpt.second = GetOption(options, "second", "string", ["2-digit", "numeric"], undefined); - formatOpt.timeZoneName = GetOption(options, "timeZoneName", "string", ["short", "long"], - undefined); + var i, prop; + for (i = 0; i < dateTimeComponents.length; i++) { + prop = dateTimeComponents[i]; + var value = GetOption(options, prop, "string", dateTimeComponentValues[prop], undefined); + formatOpt[prop] = value; + } // Steps 20-21 provided by ICU - see comment after this function. @@ -2659,6 +2650,7 @@ function ToDateTimeOptions(options, required, defaults) { return options; } + /** * Compares the date and time components requested by options with the available * date and time formats in formats, and selects the best match according @@ -2844,7 +2836,6 @@ function Intl_DateTimeFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format"); function Intl_DateTimeFormat_formatToParts() { @@ -2980,232 +2971,6 @@ function resolveICUPattern(pattern, result) { } } -/********** Intl.PluralRules **********/ - -/** - * PluralRules internal properties. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.3. - */ -var pluralRulesInternalProperties = { - _availableLocales: null, - availableLocales: function() - { - var locales = this._availableLocales; - if (locales) - return locales; - - locales = intl_PluralRules_availableLocales(); - addSpecialMissingLanguageTags(locales); - return (this._availableLocales = locales); - } -}; - -/** - * Compute an internal properties object from |lazyPluralRulesData|. - */ -function resolvePluralRulesInternals(lazyPluralRulesData) { - assert(IsObject(lazyPluralRulesData), "lazy data not an object?"); - - var internalProps = std_Object_create(null); - - var requestedLocales = lazyPluralRulesData.requestedLocales; - - var PluralRules = pluralRulesInternalProperties; - - // Step 13. - const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules), - lazyPluralRulesData.requestedLocales, - lazyPluralRulesData.opt, - noRelevantExtensionKeys, undefined); - - // Step 14. - internalProps.locale = r.locale; - internalProps.type = lazyPluralRulesData.type; - - internalProps.pluralCategories = intl_GetPluralCategories( - internalProps.locale, - internalProps.type); - - internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits; - internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits; - internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits; - - if ("minimumSignificantDigits" in lazyPluralRulesData) { - assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch"); - internalProps.minimumSignificantDigits = lazyPluralRulesData.minimumSignificantDigits; - internalProps.maximumSignificantDigits = lazyPluralRulesData.maximumSignificantDigits; - } - - return internalProps; -} - -/** - * Returns an object containing the PluralRules internal properties of |obj|, - * or throws a TypeError if |obj| isn't PluralRules-initialized. - */ -function getPluralRulesInternals(obj, methodName) { - var internals = getIntlObjectInternals(obj, "PluralRules", methodName); - assert(internals.type === "PluralRules", "bad type escaped getIntlObjectInternals"); - - var internalProps = maybeInternalProperties(internals); - if (internalProps) - return internalProps; - - internalProps = resolvePluralRulesInternals(internals.lazyData); - setInternalProperties(internals, internalProps); - return internalProps; -} - -/** - * Initializes an object as a PluralRules. - * - * This method is complicated a moderate bit by its implementing initialization - * as a *lazy* concept. Everything that must happen now, does -- but we defer - * all the work we can until the object is actually used as a PluralRules. - * This later work occurs in |resolvePluralRulesInternals|; steps not noted - * here occur there. - * - * Spec: ECMAScript 402 API, PluralRules, 1.1.1. - */ -function InitializePluralRules(pluralRules, locales, options) { - assert(IsObject(pluralRules), "InitializePluralRules"); - - // Step 1. - if (isInitializedIntlObject(pluralRules)) - ThrowTypeError(JSMSG_INTL_OBJECT_REINITED); - - let internals = initializeIntlObject(pluralRules); - - // Lazy PluralRules data has the following structure: - // - // { - // requestedLocales: List of locales, - // type: "cardinal" / "ordinal", - // - // opt: // opt object computer in InitializePluralRules - // { - // localeMatcher: "lookup" / "best fit", - // } - // - // minimumIntegerDigits: integer ∈ [1, 21], - // minimumFractionDigits: integer ∈ [0, 20], - // maximumFractionDigits: integer ∈ [0, 20], - // - // // optional - // minimumSignificantDigits: integer ∈ [1, 21], - // maximumSignificantDigits: integer ∈ [1, 21], - // } - // - // Note that lazy data is only installed as a final step of initialization, - // so every PluralRules lazy data object has *all* these properties, never a - // subset of them. - const lazyPluralRulesData = std_Object_create(null); - - // Step 3. - let requestedLocales = CanonicalizeLocaleList(locales); - lazyPluralRulesData.requestedLocales = requestedLocales; - - // Steps 4-5. - if (options === undefined) - options = {}; - else - options = ToObject(options); - - // Step 6. - const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal"); - lazyPluralRulesData.type = type; - - // Step 8. - let opt = new Record(); - lazyPluralRulesData.opt = opt; - - // Steps 9-10. - let matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit"); - opt.localeMatcher = matcher; - - // Steps 11-12. - SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3); - - setLazyData(internals, "PluralRules", lazyPluralRulesData) -} - -/** - * Returns the subset of the given locale list for which this locale list has a - * matching (possibly fallback) locale. Locales appear in the same order in the - * returned list as in the input list. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.2. - */ -function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) { - var options = arguments.length > 1 ? arguments[1] : undefined; - - // Step 1. - var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales, - pluralRulesInternalProperties); - // Step 2. - let requestedLocales = CanonicalizeLocaleList(locales); - - // Step 3. - return SupportedLocales(availableLocales, requestedLocales, options); -} - -/** - * Returns a String value representing the plural category matching - * the number passed as value according to the - * effective locale and the formatting options of this PluralRules. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.3. - */ -function Intl_PluralRules_select(value) { - // Step 1. - let pluralRules = this; - // Step 2. - let internals = getPluralRulesInternals(pluralRules, "select"); - - // Steps 3-4. - let n = ToNumber(value); - - // Step 5. - return intl_SelectPluralRule(pluralRules, n); -} - -/** - * Returns the resolved options for a PluralRules object. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.4. - */ -function Intl_PluralRules_resolvedOptions() { - var internals = getPluralRulesInternals(this, "resolvedOptions"); - - var internalsPluralCategories = internals.pluralCategories; - var pluralCategories = []; - for (var i = 0; i < internalsPluralCategories.length; i++) - _DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]); - - var result = { - locale: internals.locale, - type: internals.type, - pluralCategories, - minimumIntegerDigits: internals.minimumIntegerDigits, - minimumFractionDigits: internals.minimumFractionDigits, - maximumFractionDigits: internals.maximumFractionDigits, - }; - - var optionalProperties = [ - "minimumSignificantDigits", - "maximumSignificantDigits" - ]; - - for (var i = 0; i < optionalProperties.length; i++) { - var p = optionalProperties[i]; - if (callFunction(std_Object_hasOwnProperty, internals, p)) - _DefineDataProperty(result, p, internals[p]); - } - return result; -} - - function Intl_getCanonicalLocales(locales) { let codes = CanonicalizeLocaleList(locales); let result = []; @@ -3241,126 +3006,3 @@ function Intl_getCalendarInfo(locales) { return result; } - -/** - * This function is a custom method designed after Intl API, but currently - * not part of the spec or spec proposal. - * We want to use it internally to retrieve translated values from CLDR in - * order to ensure they're aligned with what Intl API returns. - * - * This API may one day be a foundation for an ECMA402 API spec proposal. - * - * The function takes two arguments - locales which is a list of locale strings - * and options which is an object with two optional properties: - * - * keys: - * an Array of string values that are paths to individual terms - * - * style: - * a String with a value "long", "short" or "narrow" - * - * It returns an object with properties: - * - * locale: - * a negotiated locale string - * - * style: - * negotiated style - * - * values: - * A key-value pair list of requested keys and corresponding - * translated values - * - */ -function Intl_getDisplayNames(locales, options) { - // 1. Let requestLocales be ? CanonicalizeLocaleList(locales). - const requestedLocales = CanonicalizeLocaleList(locales); - - // 2. If options is undefined, then - if (options === undefined) - // a. Let options be ObjectCreate(%ObjectPrototype%). - options = {}; - // 3. Else, - else - // a. Let options be ? ToObject(options). - options = ToObject(options); - - const DateTimeFormat = dateTimeFormatInternalProperties; - - // 4. Let localeData be %DateTimeFormat%.[[localeData]]. - const localeData = DateTimeFormat.localeData; - - // 5. Let opt be a new Record. - const localeOpt = new Record(); - // 6. Set localeOpt.[[localeMatcher]] to "best fit". - localeOpt.localeMatcher = "best fit"; - - // 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt, - // %DateTimeFormat%.[[relevantExtensionKeys]], localeData). - const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat), - requestedLocales, - localeOpt, - DateTimeFormat.relevantExtensionKeys, - localeData); - - // 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long"). - const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long"); - // 9. Let keys be ? Get(options, "keys"). - let keys = options.keys; - - // 10. If keys is undefined, - if (keys === undefined) { - // a. Let keys be ArrayCreate(0). - keys = []; - } else if (!IsObject(keys)) { - // 11. Else, - // a. If Type(keys) is not Object, throw a TypeError exception. - ThrowTypeError(JSMSG_INVALID_KEYS_TYPE); - } - - // 12. Let processedKeys be ArrayCreate(0). - // (This really should be a List, but we use an Array here in order that - // |intl_ComputeDisplayNames| may infallibly access the list's length via - // |ArrayObject::length|.) - let processedKeys = []; - // 13. Let len be ? ToLength(? Get(keys, "length")). - let len = ToLength(keys.length); - // 14. Let i be 0. - // 15. Repeat, while i < len - for (let i = 0; i < len; i++) { - // a. Let processedKey be ? ToString(? Get(keys, i)). - // b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey). - callFunction(std_Array_push, processedKeys, ToString(keys[i])); - } - - // 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys). - const names = intl_ComputeDisplayNames(r.locale, style, processedKeys); - - // 17. Let values be ObjectCreate(%ObjectPrototype%). - const values = {}; - - // 18. Set i to 0. - // 19. Repeat, while i < len - for (let i = 0; i < len; i++) { - // a. Let key be ? Get(processedKeys, i). - const key = processedKeys[i]; - // b. Let name be ? Get(names, i). - const name = names[i]; - // c. Assert: Type(name) is string. - assert(typeof name === "string", "unexpected non-string value"); - // d. Assert: the length of name is greater than zero. - assert(name.length > 0, "empty string value"); - // e. Perform ? DefinePropertyOrThrow(values, key, name). - _DefineDataProperty(values, key, name); - } - - // 20. Let options be ObjectCreate(%ObjectPrototype%). - // 21. Perform ! DefinePropertyOrThrow(result, "locale", r.[[locale]]). - // 22. Perform ! DefinePropertyOrThrow(result, "style", style). - // 23. Perform ! DefinePropertyOrThrow(result, "values", values). - const result = { locale: r.locale, style, values }; - - // 24. Return result. - return result; -} - diff --git a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js b/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js deleted file mode 100644 index f5f5b62a8..000000000 --- a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js +++ /dev/null @@ -1,27 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras")) - -// Tests the PluralRules.resolvedOptions function for overriden Array[Symbol.species]. - -addIntlExtras(Intl); - -var pl = new Intl.PluralRules("de"); - -Object.defineProperty(Array, Symbol.species, { - value: function() { - return new Proxy(["?"], { - get(t, pk, r) { - return Reflect.get(t, pk, r); - }, - defineProperty(t, pk) { - return true; - } - }); - } -}); - -var pluralCategories = pl.resolvedOptions().pluralCategories; - -assertEqArray(pluralCategories, ["one", "other"]); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-overridden-species.js b/js/src/tests/Intl/getCanonicalLocales-overridden-species.js deleted file mode 100644 index 858735b58..000000000 --- a/js/src/tests/Intl/getCanonicalLocales-overridden-species.js +++ /dev/null @@ -1,23 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("Intl")) - -// Tests the getCanonicalLocales function for overriden Array[Symbol.species]. - -Object.defineProperty(Array, Symbol.species, { - value: function() { - return new Proxy(["?"], { - get(t, pk, r) { - return Reflect.get(t, pk, r); - }, - defineProperty(t, pk) { - return true; - } - }); - } -}); - -var arr = Intl.getCanonicalLocales("de-x-private"); - -assertEqArray(arr, ["de-x-private"]); - -if (typeof reportCompare === "function") - reportCompare(0, 0); -- cgit v1.2.3 From b069dabc91b7e0f5f8d161cdbe598276a21d6d68 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 25 Apr 2018 11:16:14 +0200 Subject: Avoid calling slice in self-hosted code. DiD This time without unrelated/incomplete pluralforms junk. --- js/src/builtin/Intl.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'js') diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js index 493062c1c..509168d7a 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -432,7 +432,7 @@ function CanonicalizeLanguageTag(locale) { subtags[i] = subtag; i++; } - var normal = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, 0, i), "-"); + var normal = ArrayJoinRange(subtags, "-", 0, i); // Extension sequences are sorted by their singleton characters. // "u-ca-chinese-t-zh-latn" -> "t-zh-latn-u-ca-chinese" @@ -442,7 +442,7 @@ function CanonicalizeLanguageTag(locale) { i++; while (i < subtags.length && subtags[i].length > 1) i++; - var extension = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, extensionStart, i), "-"); + var extension = ArrayJoinRange(subtags, "-", extensionStart, i); callFunction(std_Array_push, extensions, extension); } callFunction(std_Array_sort, extensions); @@ -450,7 +450,7 @@ function CanonicalizeLanguageTag(locale) { // Private use sequences are left as is. "x-private" var privateUse = ""; if (i < subtags.length) - privateUse = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, i), "-"); + privateUse = ArrayJoinRange(subtags, "-", i); // Put everything back together. var canonical = normal; @@ -467,6 +467,24 @@ function CanonicalizeLanguageTag(locale) { return canonical; } +/** + * Joins the array elements in the given range with the supplied separator. + */ +function ArrayJoinRange(array, separator, from, to = array.length) { + assert(typeof separator === "string", "|separator| is a string value"); + assert(typeof from === "number", "|from| is a number value"); + assert(typeof to === "number", "|to| is a number value"); + assert(0 <= from && from <= to && to <= array.length, "|from| and |to| form a valid range"); + + if (from === to) + return ""; + + var result = array[from]; + for (var i = from + 1; i < to; i++) { + result += separator + array[i]; + } + return result; +} function localeContainsNoUnicodeExtensions(locale) { // No "-u-", no possible Unicode extension. -- cgit v1.2.3 From 077c63084488ac38c1c44e8cdaa9c33086f0a649 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 27 Apr 2018 13:56:47 +0200 Subject: Remove support for making jemalloc4 the default memory allocator. --- js/xpconnect/src/XPCJSContext.cpp | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'js') diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index f5f6a11bb..8862bca32 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -59,10 +59,6 @@ #include "nsIXULRuntime.h" #include "nsJSPrincipals.h" -#if defined(MOZ_JEMALLOC4) -#include "mozmemory.h" -#endif - #ifdef XP_WIN #include #endif @@ -147,18 +143,6 @@ public: mActive = false; } } else { -#if defined(MOZ_JEMALLOC4) - if (mPurge) { - /* Jemalloc purges dirty pages regularly during free() when the - * ratio of dirty pages compared to active pages is higher than - * 1 << lg_dirty_mult. A high ratio can have an impact on - * performance, so we use the default ratio of 8, but force a - * regular purge of all remaining dirty pages, after cycle - * collection. */ - Telemetry::AutoTimer timer; - jemalloc_free_dirty_pages(); - } -#endif mActive = false; } return NS_OK; -- cgit v1.2.3 From 43034a36e132ac4394e26cbfb4d855bd6f5114b3 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 27 Apr 2018 19:16:45 +0200 Subject: Remove jemalloc 4 from our tree. --- js/src/aclocal.m4 | 1 - js/src/make-source-package.sh | 1 - js/src/old-configure.in | 2 -- 3 files changed, 4 deletions(-) (limited to 'js') diff --git a/js/src/aclocal.m4 b/js/src/aclocal.m4 index 627837a41..abbbd4873 100644 --- a/js/src/aclocal.m4 +++ b/js/src/aclocal.m4 @@ -25,7 +25,6 @@ builtin(include, ../../build/autoconf/zlib.m4)dnl builtin(include, ../../build/autoconf/icu.m4)dnl builtin(include, ../../build/autoconf/clang-plugin.m4)dnl builtin(include, ../../build/autoconf/alloc.m4)dnl -builtin(include, ../../build/autoconf/jemalloc.m4)dnl builtin(include, ../../build/autoconf/sanitize.m4)dnl builtin(include, ../../build/autoconf/ios.m4)dnl diff --git a/js/src/make-source-package.sh b/js/src/make-source-package.sh index 6e44dd977..e6d3f6df5 100755 --- a/js/src/make-source-package.sh +++ b/js/src/make-source-package.sh @@ -151,7 +151,6 @@ case $cmd in ${TOPSRCDIR}/memory/moz.build \ ${TOPSRCDIR}/memory/build \ ${TOPSRCDIR}/memory/fallible \ - ${TOPSRCDIR}/memory/jemalloc \ ${TOPSRCDIR}/memory/mozalloc \ ${TOPSRCDIR}/memory/mozjemalloc \ ${tgtpath}/memory diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 1736cc5d4..7432ab9e2 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -2244,8 +2244,6 @@ AC_SUBST(JS_LIBRARY_NAME) AC_SUBST(JS_CONFIG_MOZ_JS_LIBS) AC_SUBST(JS_CONFIG_LIBS) -MOZ_SUBCONFIGURE_JEMALLOC() - # Avoid using obsolete NSPR features AC_DEFINE(NO_NSPR_10_SUPPORT) -- cgit v1.2.3 From 8d6b34f8630d6802e3570e8c6adcd2ad6fe4ddbe Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 28 Apr 2018 15:45:56 +0200 Subject: Use SRWlocks for js mutexes on Windows. --- js/src/threading/windows/ConditionVariable.cpp | 8 ++--- js/src/threading/windows/MutexImpl.cpp | 47 ++------------------------ js/src/threading/windows/MutexPlatformData.h | 2 +- 3 files changed, 8 insertions(+), 49 deletions(-) (limited to 'js') diff --git a/js/src/threading/windows/ConditionVariable.cpp b/js/src/threading/windows/ConditionVariable.cpp index 3c75a0f27..92e0249b7 100644 --- a/js/src/threading/windows/ConditionVariable.cpp +++ b/js/src/threading/windows/ConditionVariable.cpp @@ -54,8 +54,8 @@ js::ConditionVariable::notify_all() void js::ConditionVariable::wait(UniqueLock& lock) { - CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection; - bool r = SleepConditionVariableCS(&platformData()->cv_, cs, INFINITE); + SRWLOCK* srwlock = &lock.lock.platformData()->lock; + bool r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, INFINITE, 0); MOZ_RELEASE_ASSERT(r); } @@ -70,7 +70,7 @@ js::CVStatus js::ConditionVariable::wait_for(UniqueLock& lock, const mozilla::TimeDuration& rel_time) { - CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection; + SRWLOCK* srwlock = &lock.lock.platformData()->lock; // Note that DWORD is unsigned, so we have to be careful to clamp at 0. // If rel_time is Forever, then ToMilliseconds is +inf, which evaluates as @@ -82,7 +82,7 @@ js::ConditionVariable::wait_for(UniqueLock& lock, ? INFINITE : static_cast(msecd); - BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec); + BOOL r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, msec, 0); if (r) return CVStatus::NoTimeout; MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT); diff --git a/js/src/threading/windows/MutexImpl.cpp b/js/src/threading/windows/MutexImpl.cpp index 385d1c8de..e838459b5 100644 --- a/js/src/threading/windows/MutexImpl.cpp +++ b/js/src/threading/windows/MutexImpl.cpp @@ -13,35 +13,6 @@ #include "threading/Mutex.h" #include "threading/windows/MutexPlatformData.h" -namespace { - -// We build with a toolkit that supports WinXP, so we have to probe -// for modern features at runtime. This is necessary because Vista and -// later automatically allocate and subsequently leak a debug info -// object for each critical section that we allocate unless we tell it -// not to. In order to tell it not to, we need the extra flags field -// provided by the Ex version of InitializeCriticalSection. -struct MutexNativeImports -{ - using InitializeCriticalSectionExT = BOOL (WINAPI*)(CRITICAL_SECTION*, DWORD, DWORD); - InitializeCriticalSectionExT InitializeCriticalSectionEx; - - MutexNativeImports() { - HMODULE kernel32_dll = GetModuleHandle("kernel32.dll"); - MOZ_RELEASE_ASSERT(kernel32_dll != NULL); - InitializeCriticalSectionEx = reinterpret_cast( - GetProcAddress(kernel32_dll, "InitializeCriticalSectionEx")); - } - - bool hasInitializeCriticalSectionEx() const { - return InitializeCriticalSectionEx; - } -}; - -static MutexNativeImports NativeImports; - -} // (anonymous namespace) - js::detail::MutexImpl::MutexImpl() { AutoEnterOOMUnsafeRegion oom; @@ -49,18 +20,7 @@ js::detail::MutexImpl::MutexImpl() if (!platformData_) oom.crash("js::Mutex::Mutex"); - // This number was adopted from NSPR. - const static DWORD LockSpinCount = 1500; - BOOL r; - if (NativeImports.hasInitializeCriticalSectionEx()) { - r = NativeImports.InitializeCriticalSectionEx(&platformData()->criticalSection, - LockSpinCount, - CRITICAL_SECTION_NO_DEBUG_INFO); - } else { - r = InitializeCriticalSectionAndSpinCount(&platformData()->criticalSection, - LockSpinCount); - } - MOZ_RELEASE_ASSERT(r); + InitializeSRWLock(&platformData()->lock); } js::detail::MutexImpl::~MutexImpl() @@ -68,18 +28,17 @@ js::detail::MutexImpl::~MutexImpl() if (!platformData_) return; - DeleteCriticalSection(&platformData()->criticalSection); js_delete(platformData()); } void js::detail::MutexImpl::lock() { - EnterCriticalSection(&platformData()->criticalSection); + AcquireSRWLockExclusive(&platformData()->lock); } void js::detail::MutexImpl::unlock() { - LeaveCriticalSection(&platformData()->criticalSection); + ReleaseSRWLockExclusive(&platformData()->lock); } diff --git a/js/src/threading/windows/MutexPlatformData.h b/js/src/threading/windows/MutexPlatformData.h index fbe7fc80d..1d741c5d0 100644 --- a/js/src/threading/windows/MutexPlatformData.h +++ b/js/src/threading/windows/MutexPlatformData.h @@ -13,7 +13,7 @@ struct js::detail::MutexImpl::PlatformData { - CRITICAL_SECTION criticalSection; + SRWLOCK lock; }; #endif // platform_win_MutexPlatformData_h -- cgit v1.2.3 From 927868e8b93f508fe89ee82f618f4a1761366f70 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 29 Apr 2018 13:27:12 +0200 Subject: Move --enable-tests out of Python configure and flip the default. --- js/src/old-configure.in | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'js') diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 7432ab9e2..162a071d7 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -1533,6 +1533,14 @@ MOZ_ARG_ENABLE_STRING(ui-locale, MOZ_UI_LOCALE=$enableval ) AC_SUBST(MOZ_UI_LOCALE) +dnl ======================================================== +dnl Build the tests? +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(tests, +[ --enable-tests Build test libraries & programs], + ENABLE_TESTS=1, + ENABLE_TESTS= ) + dnl ======================================================== dnl = dnl = Module specific options @@ -2091,6 +2099,8 @@ AC_SUBST(MOZ_DEBUG_LDFLAGS) AC_SUBST(WARNINGS_AS_ERRORS) AC_SUBST(LIBICONV) +AC_SUBST(ENABLE_TESTS) + AC_SUBST(ENABLE_STRIP) AC_SUBST(PKG_SKIP_STRIP) AC_SUBST(INCREMENTAL_LINKER) -- cgit v1.2.3 From 66aa6b595c47231958a855e4b166f5d55df1184d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 29 Apr 2018 13:39:11 +0200 Subject: Bug 1411415. --- js/public/Value.h | 55 ++++++++++++++++++++++++++++++++--- js/src/jit/BaselineFrameInfo.h | 4 +-- js/src/jit/RegisterSets.h | 8 ++--- js/src/jit/RematerializedFrame.cpp | 14 +++++++-- js/src/wasm/AsmJS.cpp | 10 +++---- js/xpconnect/src/XPCWrappedNative.cpp | 7 +++-- 6 files changed, 78 insertions(+), 20 deletions(-) (limited to 'js') diff --git a/js/public/Value.h b/js/public/Value.h index a40e65c83..01666ed4e 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -140,12 +140,16 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32) + #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING #elif defined(JS_PUNBOX64) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) + #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL #define JSVAL_TAG_MASK 0xFFFF800000000000LL #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) @@ -817,7 +821,7 @@ class MOZ_NON_PARAM alignas(8) Value double asDouble; void* asPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -843,7 +847,7 @@ class MOZ_NON_PARAM alignas(8) Value size_t asWord; uintptr_t asUIntPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -871,7 +875,7 @@ class MOZ_NON_PARAM alignas(8) Value double asDouble; void* asPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -895,7 +899,7 @@ class MOZ_NON_PARAM alignas(8) Value size_t asWord; uintptr_t asUIntPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -948,8 +952,51 @@ class MOZ_NON_PARAM alignas(8) Value } } JS_HAZ_GC_POINTER; +/** + * This is a null-constructible structure that can convert to and from + * a Value, allowing UninitializedValue to be stored in unions. + */ +struct MOZ_NON_PARAM alignas(8) UninitializedValue +{ + private: + uint64_t bits; + + public: + UninitializedValue() = default; + UninitializedValue(const UninitializedValue&) = default; + MOZ_IMPLICIT UninitializedValue(const Value& val) : bits(val.asRawBits()) {} + + inline uint64_t asRawBits() const { + return bits; + } + + inline Value& asValueRef() { + return *reinterpret_cast(this); + } + inline const Value& asValueRef() const { + return *reinterpret_cast(this); + } + + inline operator Value&() { + return asValueRef(); + } + inline operator Value const&() const { + return asValueRef(); + } + inline operator Value() const { + return asValueRef(); + } + + inline void operator=(Value const& other) { + asValueRef() = other; + } +}; + static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere"); +static_assert(sizeof(UninitializedValue) == sizeof(Value), "Value and UninitializedValue must be the same size"); +static_assert(alignof(UninitializedValue) == alignof(Value), "Value and UninitializedValue must have same alignment"); + inline bool IsOptimizedPlaceholderMagicValue(const Value& v) { diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h index 13bf0358d..1691270ac 100644 --- a/js/src/jit/BaselineFrameInfo.h +++ b/js/src/jit/BaselineFrameInfo.h @@ -67,7 +67,7 @@ class StackValue union { struct { - Value v; + JS::UninitializedValue v; } constant; struct { mozilla::AlignedStorage2 reg; @@ -112,7 +112,7 @@ class StackValue } Value constant() const { MOZ_ASSERT(kind_ == Constant); - return data.constant.v; + return data.constant.v.asValueRef(); } ValueOperand reg() const { MOZ_ASSERT(kind_ == Register); diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h index 0a4045dd7..08ae53f16 100644 --- a/js/src/jit/RegisterSets.h +++ b/js/src/jit/RegisterSets.h @@ -226,13 +226,13 @@ class ConstantOrRegister // Space to hold either a Value or a TypedOrValueRegister. union U { - Value constant; + JS::UninitializedValue constant; TypedOrValueRegister reg; } data; - const Value& dataValue() const { + Value dataValue() const { MOZ_ASSERT(constant()); - return data.constant; + return data.constant.asValueRef(); } void setDataValue(const Value& value) { MOZ_ASSERT(constant()); @@ -268,7 +268,7 @@ class ConstantOrRegister return constant_; } - const Value& value() const { + Value value() const { return dataValue(); } diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp index cb324220c..32fad1267 100644 --- a/js/src/jit/RematerializedFrame.cpp +++ b/js/src/jit/RematerializedFrame.cpp @@ -61,9 +61,17 @@ RematerializedFrame::New(JSContext* cx, uint8_t* top, InlineFrameIterator& iter, { unsigned numFormals = iter.isFunctionFrame() ? iter.calleeTemplate()->nargs() : 0; unsigned argSlots = Max(numFormals, iter.numActualArgs()); - size_t numBytes = sizeof(RematerializedFrame) + - (argSlots + iter.script()->nfixed()) * sizeof(Value) - - sizeof(Value); // 1 Value included in sizeof(RematerializedFrame) + unsigned extraSlots = argSlots + iter.script()->nfixed(); + + // One Value slot is included in sizeof(RematerializedFrame), so we can + // reduce the extra slot count by one. However, if there are zero slot + // allocations total, then reducing the slots by one will lead to + // the memory allocation being smaller than sizeof(RematerializedFrame). + if (extraSlots > 0) + extraSlots -= 1; + + size_t numBytes = sizeof(RematerializedFrame) + (extraSlots * sizeof(Value)); + MOZ_ASSERT(numBytes >= sizeof(RematerializedFrame)); void* buf = cx->pod_calloc(numBytes); if (!buf) diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index b4f41c3d5..7fade24fb 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -857,7 +857,7 @@ class NumLit private: Which which_; union { - Value scalar_; + JS::UninitializedValue scalar_; SimdConstant simd_; } u; @@ -880,7 +880,7 @@ class NumLit int32_t toInt32() const { MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned); - return u.scalar_.toInt32(); + return u.scalar_.asValueRef().toInt32(); } uint32_t toUint32() const { @@ -889,17 +889,17 @@ class NumLit RawF64 toDouble() const { MOZ_ASSERT(which_ == Double); - return RawF64(u.scalar_.toDouble()); + return RawF64(u.scalar_.asValueRef().toDouble()); } RawF32 toFloat() const { MOZ_ASSERT(which_ == Float); - return RawF32(float(u.scalar_.toDouble())); + return RawF32(float(u.scalar_.asValueRef().toDouble())); } Value scalarValue() const { MOZ_ASSERT(which_ != OutOfRangeInt); - return u.scalar_; + return u.scalar_.asValueRef(); } bool isSimd() const diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index acf92f3c3..a12e36baa 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1785,9 +1785,12 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i) // indirectly, regardless of in/out-ness. if (type_tag == nsXPTType::T_JSVAL) { // Root the value. - dp->val.j.setUndefined(); - if (!js::AddRawValueRoot(mCallContext, &dp->val.j, "XPCWrappedNative::CallMethod param")) + dp->val.j.asValueRef().setUndefined(); + if (!js::AddRawValueRoot(mCallContext, &dp->val.j.asValueRef(), + "XPCWrappedNative::CallMethod param")) + { return false; + } } // Flag cleanup for anything that isn't self-contained. -- cgit v1.2.3 From d308db119d48ce858b194a720f7946349b5f9b47 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 9 Apr 2018 12:02:43 -0700 Subject: Bug 1452619 - Implement mozilla::IsAsciiAlpha. r=froydnj, a=lizzard --- js/src/jsstr.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'js') diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 3b92aa21b..7e9621d4a 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -9,6 +9,7 @@ #include "mozilla/HashFunctions.h" #include "mozilla/PodOperations.h" +#include "mozilla/TextUtils.h" #include @@ -95,7 +96,7 @@ struct JSSubString { #define JS7_UNOCT(c) (JS7_UNDEC(c)) #define JS7_ISHEX(c) ((c) < 128 && isxdigit(c)) #define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a') -#define JS7_ISLET(c) ((c) < 128 && isalpha(c)) +#define JS7_ISLET(c) (mozilla::IsAsciiAlpha(c)) extern size_t js_strlen(const char16_t* s); -- cgit v1.2.3 From fc1eb3a144cca21fe4749f08bae58904ad5c4b84 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 30 Apr 2018 09:00:49 +0200 Subject: [regression] [follow up] Error: No such property on self-hosted object: "Intl_getDisplayNames" Issue #162 and #264 --- js/src/builtin/Intl.js | 126 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) (limited to 'js') diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js index 509168d7a..6391c3e70 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -9,7 +9,8 @@ JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false, JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false, JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false, - JSMSG_DATE_NOT_FINITE: false, + JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false, + JSMSG_INVALID_KEY: false, intl_Collator_availableLocales: false, intl_availableCollations: false, intl_CompareStrings: false, @@ -3024,3 +3025,126 @@ function Intl_getCalendarInfo(locales) { return result; } + +/** + * This function is a custom method designed after Intl API, but currently + * not part of the spec or spec proposal. + * We want to use it internally to retrieve translated values from CLDR in + * order to ensure they're aligned with what Intl API returns. + * + * This API may one day be a foundation for an ECMA402 API spec proposal. + * + * The function takes two arguments - locales which is a list of locale strings + * and options which is an object with two optional properties: + * + * keys: + * an Array of string values that are paths to individual terms + * + * style: + * a String with a value "long", "short" or "narrow" + * + * It returns an object with properties: + * + * locale: + * a negotiated locale string + * + * style: + * negotiated style + * + * values: + * A key-value pair list of requested keys and corresponding + * translated values + * + */ +function Intl_getDisplayNames(locales, options) { + // 1. Let requestLocales be ? CanonicalizeLocaleList(locales). + const requestedLocales = CanonicalizeLocaleList(locales); + + // 2. If options is undefined, then + if (options === undefined) + // a. Let options be ObjectCreate(%ObjectPrototype%). + options = {}; + // 3. Else, + else + // a. Let options be ? ToObject(options). + options = ToObject(options); + + const DateTimeFormat = dateTimeFormatInternalProperties; + + // 4. Let localeData be %DateTimeFormat%.[[localeData]]. + const localeData = DateTimeFormat.localeData; + + // 5. Let opt be a new Record. + const localeOpt = new Record(); + // 6. Set localeOpt.[[localeMatcher]] to "best fit". + localeOpt.localeMatcher = "best fit"; + + // 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt, + // %DateTimeFormat%.[[relevantExtensionKeys]], localeData). + const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat), + requestedLocales, + localeOpt, + DateTimeFormat.relevantExtensionKeys, + localeData); + + // 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long"). + const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long"); + // 9. Let keys be ? Get(options, "keys"). + let keys = options.keys; + + // 10. If keys is undefined, + if (keys === undefined) { + // a. Let keys be ArrayCreate(0). + keys = []; + } else if (!IsObject(keys)) { + // 11. Else, + // a. If Type(keys) is not Object, throw a TypeError exception. + ThrowTypeError(JSMSG_INVALID_KEYS_TYPE); + } + + // 12. Let processedKeys be ArrayCreate(0). + // (This really should be a List, but we use an Array here in order that + // |intl_ComputeDisplayNames| may infallibly access the list's length via + // |ArrayObject::length|.) + let processedKeys = []; + // 13. Let len be ? ToLength(? Get(keys, "length")). + let len = ToLength(keys.length); + // 14. Let i be 0. + // 15. Repeat, while i < len + for (let i = 0; i < len; i++) { + // a. Let processedKey be ? ToString(? Get(keys, i)). + // b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey). + callFunction(std_Array_push, processedKeys, ToString(keys[i])); + } + + // 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys). + const names = intl_ComputeDisplayNames(r.locale, style, processedKeys); + + // 17. Let values be ObjectCreate(%ObjectPrototype%). + const values = {}; + + // 18. Set i to 0. + // 19. Repeat, while i < len + for (let i = 0; i < len; i++) { + // a. Let key be ? Get(processedKeys, i). + const key = processedKeys[i]; + // b. Let name be ? Get(names, i). + const name = names[i]; + // c. Assert: Type(name) is string. + assert(typeof name === "string", "unexpected non-string value"); + // d. Assert: the length of name is greater than zero. + assert(name.length > 0, "empty string value"); + // e. Perform ? DefinePropertyOrThrow(values, key, name). + _DefineDataProperty(values, key, name); + } + + // 20. Let options be ObjectCreate(%ObjectPrototype%). + // 21. Perform ! DefinePropertyOrThrow(result, "locale", r.[[locale]]). + // 22. Perform ! DefinePropertyOrThrow(result, "style", style). + // 23. Perform ! DefinePropertyOrThrow(result, "values", values). + const result = { locale: r.locale, style, values }; + + // 24. Return result. + return result; + +} -- cgit v1.2.3 From 4613b91ecac2745252c40be64e73de5ff920b02b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 3 May 2018 01:24:31 +0200 Subject: Remove sandbox ductwork conditional code. --- js/xpconnect/shell/moz.build | 16 ---------------- js/xpconnect/shell/xpcshell.cpp | 7 ------- js/xpconnect/src/XPCShellImpl.cpp | 13 ------------- 3 files changed, 36 deletions(-) (limited to 'js') diff --git a/js/xpconnect/shell/moz.build b/js/xpconnect/shell/moz.build index ecc796f7f..d4f5d55af 100644 --- a/js/xpconnect/shell/moz.build +++ b/js/xpconnect/shell/moz.build @@ -35,22 +35,6 @@ if CONFIG['_MSC_VER']: if CONFIG['OS_ARCH'] == 'WINNT': RCINCLUDE = 'xpcshell.rc' - if CONFIG['MOZ_SANDBOX']: - # For sandbox includes and the include dependencies those have - LOCAL_INCLUDES += [ - '/security/sandbox/chromium', - '/security/sandbox/chromium-shim', - ] - - USE_LIBS += [ - 'sandbox_s', - ] - - DELAYLOAD_DLLS += [ - 'winmm.dll', - 'user32.dll', - ] - DELAYLOAD_DLLS += [ 'xul.dll', ] diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp index ba979bc69..4521dc52f 100644 --- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -22,9 +22,6 @@ #define XRE_DONT_PROTECT_DLL_LOAD #define XRE_WANT_ENVIRON #include "nsWindowsWMain.cpp" -#ifdef MOZ_SANDBOX -#include "mozilla/sandboxing/SandboxInitialization.h" -#endif #endif #ifdef MOZ_WIDGET_GTK @@ -54,10 +51,6 @@ main(int argc, char** argv, char** envp) #endif XREShellData shellData; -#if defined(XP_WIN) && defined(MOZ_SANDBOX) - shellData.sandboxBrokerServices = - mozilla::sandboxing::GetInitializedBrokerServices(); -#endif int result = XRE_XPCShellMain(argc, argv, envp, &shellData); diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 45d00d390..f6c74f9b2 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -44,9 +44,6 @@ #ifdef XP_WIN #include "mozilla/widget/AudioSession.h" #include -#if defined(MOZ_SANDBOX) -#include "SandboxBroker.h" -#endif #endif // all this crap is needed to do the interactive shell stuff @@ -1484,16 +1481,6 @@ XRE_XPCShellMain(int argc, char** argv, char** envp, // Plugin may require audio session if installed plugin can initialize // asynchronized. AutoAudioSession audioSession; - -#if defined(MOZ_SANDBOX) - // Required for sandboxed child processes. - if (aShellData->sandboxBrokerServices) { - SandboxBroker::Initialize(aShellData->sandboxBrokerServices); - } else { - NS_WARNING("Failed to initialize broker services, sandboxed " - "processes will fail to start."); - } -#endif #endif { -- cgit v1.2.3 From 755e3a48bf58ca128107cf656a5900806a09d5eb Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 3 May 2018 06:28:20 +0200 Subject: Remove unused XREShellData --- js/xpconnect/shell/xpcshell.cpp | 4 +--- js/xpconnect/src/XPCShellImpl.cpp | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'js') diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp index 4521dc52f..4eef3f6bf 100644 --- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -50,9 +50,7 @@ main(int argc, char** argv, char** envp) DllBlocklist_Initialize(); #endif - XREShellData shellData; - - int result = XRE_XPCShellMain(argc, argv, envp, &shellData); + int result = XRE_XPCShellMain(argc, argv, envp); #ifdef XP_MACOSX FinishAutoreleasePool(); diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index f6c74f9b2..a6432856d 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1232,11 +1232,8 @@ GetCurrentWorkingDirectory(nsAString& workingDirectory) static JSSecurityCallbacks shellSecurityCallbacks; int -XRE_XPCShellMain(int argc, char** argv, char** envp, - const XREShellData* aShellData) +XRE_XPCShellMain(int argc, char** argv, char** envp) { - MOZ_ASSERT(aShellData); - JSContext* cx; int result = 0; nsresult rv; -- cgit v1.2.3 From a2652e5bc46b411f894d0a343f6ea6a83f07e3e2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 4 May 2018 12:08:48 +0200 Subject: Issue #325 Part 5: Remove non-Intl legacy code paths from js. --- js/src/builtin/Intl.cpp | 602 +------------------------------------------ js/src/builtin/Intl.h | 4 - js/src/gdb/moz.build | 2 +- js/src/jsapi-tests/moz.build | 2 +- js/src/jsstr.cpp | 2 - js/src/moz.build | 23 +- js/src/shell/js.cpp | 4 - js/src/shell/moz.build | 2 +- js/src/vm/DateTime.cpp | 6 +- js/src/vm/Initialization.cpp | 2 - 10 files changed, 17 insertions(+), 632 deletions(-) (limited to 'js') diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index cd808cb10..71f7b58d4 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -23,7 +23,6 @@ #include "jsobj.h" #include "builtin/IntlTimeZoneData.h" -#if ENABLE_INTL_API #include "unicode/ucal.h" #include "unicode/ucol.h" #include "unicode/udat.h" @@ -32,7 +31,6 @@ #include "unicode/unum.h" #include "unicode/unumsys.h" #include "unicode/ustring.h" -#endif #include "vm/DateTime.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" @@ -60,603 +58,6 @@ using mozilla::PodCopy; * http://userguide.icu-project.org/design#TOC-Error-Handling */ - -/******************** ICU stubs ********************/ - -#if !ENABLE_INTL_API - -/* - * When the Internationalization API isn't enabled, we also shouldn't link - * against ICU. However, we still want to compile this code in order to prevent - * bit rot. The following stub implementations for ICU functions make this - * possible. The functions using them should never be called, so they assert - * and return error codes. Signatures adapted from ICU header files locid.h, - * numsys.h, ucal.h, ucol.h, udat.h, udatpg.h, uenum.h, unum.h; see the ICU - * directory for license. - */ - -typedef bool UBool; -typedef char16_t UChar; -typedef double UDate; - -enum UErrorCode { - U_ZERO_ERROR, - U_BUFFER_OVERFLOW_ERROR, -}; - -static inline UBool -U_FAILURE(UErrorCode code) -{ - MOZ_CRASH("U_FAILURE: Intl API disabled"); -} - -inline const UChar* -Char16ToUChar(const char16_t* chars) -{ - MOZ_CRASH("Char16ToUChar: Intl API disabled"); -} - -inline UChar* -Char16ToUChar(char16_t* chars) -{ - MOZ_CRASH("Char16ToUChar: Intl API disabled"); -} - -inline char16_t* -UCharToChar16(UChar* chars) -{ - MOZ_CRASH("UCharToChar16: Intl API disabled"); -} - -inline const char16_t* -UCharToChar16(const UChar* chars) -{ - MOZ_CRASH("UCharToChar16: Intl API disabled"); -} - -static int32_t -u_strlen(const UChar* s) -{ - MOZ_CRASH("u_strlen: Intl API disabled"); -} - -struct UEnumeration; - -static int32_t -uenum_count(UEnumeration* en, UErrorCode* status) -{ - MOZ_CRASH("uenum_count: Intl API disabled"); -} - -static const char* -uenum_next(UEnumeration* en, int32_t* resultLength, UErrorCode* status) -{ - MOZ_CRASH("uenum_next: Intl API disabled"); -} - -static void -uenum_close(UEnumeration* en) -{ - MOZ_CRASH("uenum_close: Intl API disabled"); -} - -struct UCollator; - -enum UColAttribute { - UCOL_ALTERNATE_HANDLING, - UCOL_CASE_FIRST, - UCOL_CASE_LEVEL, - UCOL_NORMALIZATION_MODE, - UCOL_STRENGTH, - UCOL_NUMERIC_COLLATION, -}; - -enum UColAttributeValue { - UCOL_DEFAULT = -1, - UCOL_PRIMARY = 0, - UCOL_SECONDARY = 1, - UCOL_TERTIARY = 2, - UCOL_OFF = 16, - UCOL_ON = 17, - UCOL_SHIFTED = 20, - UCOL_LOWER_FIRST = 24, - UCOL_UPPER_FIRST = 25, -}; - -enum UCollationResult { - UCOL_EQUAL = 0, - UCOL_GREATER = 1, - UCOL_LESS = -1 -}; - -static int32_t -ucol_countAvailable() -{ - MOZ_CRASH("ucol_countAvailable: Intl API disabled"); -} - -static const char* -ucol_getAvailable(int32_t localeIndex) -{ - MOZ_CRASH("ucol_getAvailable: Intl API disabled"); -} - -static UCollator* -ucol_open(const char* loc, UErrorCode* status) -{ - MOZ_CRASH("ucol_open: Intl API disabled"); -} - -static void -ucol_setAttribute(UCollator* coll, UColAttribute attr, UColAttributeValue value, UErrorCode* status) -{ - MOZ_CRASH("ucol_setAttribute: Intl API disabled"); -} - -static UCollationResult -ucol_strcoll(const UCollator* coll, const UChar* source, int32_t sourceLength, - const UChar* target, int32_t targetLength) -{ - MOZ_CRASH("ucol_strcoll: Intl API disabled"); -} - -static void -ucol_close(UCollator* coll) -{ - MOZ_CRASH("ucol_close: Intl API disabled"); -} - -static UEnumeration* -ucol_getKeywordValuesForLocale(const char* key, const char* locale, UBool commonlyUsed, - UErrorCode* status) -{ - MOZ_CRASH("ucol_getKeywordValuesForLocale: Intl API disabled"); -} - -struct UParseError; -struct UFieldPosition; -struct UFieldPositionIterator; -typedef void* UNumberFormat; - -enum UNumberFormatStyle { - UNUM_DECIMAL = 1, - UNUM_CURRENCY, - UNUM_PERCENT, - UNUM_CURRENCY_ISO, - UNUM_CURRENCY_PLURAL, -}; - -enum UNumberFormatRoundingMode { - UNUM_ROUND_HALFUP, -}; - -enum UNumberFormatAttribute { - UNUM_GROUPING_USED, - UNUM_MIN_INTEGER_DIGITS, - UNUM_MAX_FRACTION_DIGITS, - UNUM_MIN_FRACTION_DIGITS, - UNUM_ROUNDING_MODE, - UNUM_SIGNIFICANT_DIGITS_USED, - UNUM_MIN_SIGNIFICANT_DIGITS, - UNUM_MAX_SIGNIFICANT_DIGITS, -}; - -enum UNumberFormatTextAttribute { - UNUM_CURRENCY_CODE, -}; - -static int32_t -unum_countAvailable() -{ - MOZ_CRASH("unum_countAvailable: Intl API disabled"); -} - -static const char* -unum_getAvailable(int32_t localeIndex) -{ - MOZ_CRASH("unum_getAvailable: Intl API disabled"); -} - -static UNumberFormat* -unum_open(UNumberFormatStyle style, const UChar* pattern, int32_t patternLength, - const char* locale, UParseError* parseErr, UErrorCode* status) -{ - MOZ_CRASH("unum_open: Intl API disabled"); -} - -static void -unum_setAttribute(UNumberFormat* fmt, UNumberFormatAttribute attr, int32_t newValue) -{ - MOZ_CRASH("unum_setAttribute: Intl API disabled"); -} - -static int32_t -unum_formatDouble(const UNumberFormat* fmt, double number, UChar* result, - int32_t resultLength, UFieldPosition* pos, UErrorCode* status) -{ - MOZ_CRASH("unum_formatDouble: Intl API disabled"); -} - -static void -unum_close(UNumberFormat* fmt) -{ - MOZ_CRASH("unum_close: Intl API disabled"); -} - -static void -unum_setTextAttribute(UNumberFormat* fmt, UNumberFormatTextAttribute tag, const UChar* newValue, - int32_t newValueLength, UErrorCode* status) -{ - MOZ_CRASH("unum_setTextAttribute: Intl API disabled"); -} - -typedef void* UNumberingSystem; - -static UNumberingSystem* -unumsys_open(const char* locale, UErrorCode* status) -{ - MOZ_CRASH("unumsys_open: Intl API disabled"); -} - -static const char* -unumsys_getName(const UNumberingSystem* unumsys) -{ - MOZ_CRASH("unumsys_getName: Intl API disabled"); -} - -static void -unumsys_close(UNumberingSystem* unumsys) -{ - MOZ_CRASH("unumsys_close: Intl API disabled"); -} - -typedef void* UCalendar; - -enum UCalendarType { - UCAL_TRADITIONAL, - UCAL_DEFAULT = UCAL_TRADITIONAL, - UCAL_GREGORIAN -}; - -enum UCalendarAttribute { - UCAL_FIRST_DAY_OF_WEEK, - UCAL_MINIMAL_DAYS_IN_FIRST_WEEK -}; - -enum UCalendarDaysOfWeek { - UCAL_SUNDAY, - UCAL_MONDAY, - UCAL_TUESDAY, - UCAL_WEDNESDAY, - UCAL_THURSDAY, - UCAL_FRIDAY, - UCAL_SATURDAY -}; - -enum UCalendarWeekdayType { - UCAL_WEEKDAY, - UCAL_WEEKEND, - UCAL_WEEKEND_ONSET, - UCAL_WEEKEND_CEASE -}; - -enum UCalendarDateFields { - UCAL_ERA, - UCAL_YEAR, - UCAL_MONTH, - UCAL_WEEK_OF_YEAR, - UCAL_WEEK_OF_MONTH, - UCAL_DATE, - UCAL_DAY_OF_YEAR, - UCAL_DAY_OF_WEEK, - UCAL_DAY_OF_WEEK_IN_MONTH, - UCAL_AM_PM, - UCAL_HOUR, - UCAL_HOUR_OF_DAY, - UCAL_MINUTE, - UCAL_SECOND, - UCAL_MILLISECOND, - UCAL_ZONE_OFFSET, - UCAL_DST_OFFSET, - UCAL_YEAR_WOY, - UCAL_DOW_LOCAL, - UCAL_EXTENDED_YEAR, - UCAL_JULIAN_DAY, - UCAL_MILLISECONDS_IN_DAY, - UCAL_IS_LEAP_MONTH, - UCAL_FIELD_COUNT, - UCAL_DAY_OF_MONTH = UCAL_DATE -}; - -enum UCalendarMonths { - UCAL_JANUARY, - UCAL_FEBRUARY, - UCAL_MARCH, - UCAL_APRIL, - UCAL_MAY, - UCAL_JUNE, - UCAL_JULY, - UCAL_AUGUST, - UCAL_SEPTEMBER, - UCAL_OCTOBER, - UCAL_NOVEMBER, - UCAL_DECEMBER, - UCAL_UNDECIMBER -}; - -enum UCalendarAMPMs { - UCAL_AM, - UCAL_PM -}; - -static UCalendar* -ucal_open(const UChar* zoneID, int32_t len, const char* locale, - UCalendarType type, UErrorCode* status) -{ - MOZ_CRASH("ucal_open: Intl API disabled"); -} - -static const char* -ucal_getType(const UCalendar* cal, UErrorCode* status) -{ - MOZ_CRASH("ucal_getType: Intl API disabled"); -} - -static UEnumeration* -ucal_getKeywordValuesForLocale(const char* key, const char* locale, - UBool commonlyUsed, UErrorCode* status) -{ - MOZ_CRASH("ucal_getKeywordValuesForLocale: Intl API disabled"); -} - -static void -ucal_close(UCalendar* cal) -{ - MOZ_CRASH("ucal_close: Intl API disabled"); -} - -static UCalendarWeekdayType -ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status) -{ - MOZ_CRASH("ucal_getDayOfWeekType: Intl API disabled"); -} - -static int32_t -ucal_getAttribute(const UCalendar* cal, - UCalendarAttribute attr) -{ - MOZ_CRASH("ucal_getAttribute: Intl API disabled"); -} - -static int32_t -ucal_get(const UCalendar *cal, UCalendarDateFields field, UErrorCode *status) -{ - MOZ_CRASH("ucal_get: Intl API disabled"); -} - -static UEnumeration* -ucal_openTimeZones(UErrorCode* status) -{ - MOZ_CRASH("ucal_openTimeZones: Intl API disabled"); -} - -static int32_t -ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, UChar* result, int32_t resultCapacity, - UBool* isSystemID, UErrorCode* status) -{ - MOZ_CRASH("ucal_getCanonicalTimeZoneID: Intl API disabled"); -} - -static int32_t -ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* status) -{ - MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled"); -} - -enum UDateTimePatternField { - UDATPG_YEAR_FIELD, - UDATPG_MONTH_FIELD, - UDATPG_WEEK_OF_YEAR_FIELD, - UDATPG_DAY_FIELD, -}; - -typedef void* UDateTimePatternGenerator; - -static UDateTimePatternGenerator* -udatpg_open(const char* locale, UErrorCode* pErrorCode) -{ - MOZ_CRASH("udatpg_open: Intl API disabled"); -} - -static int32_t -udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton, - int32_t length, UChar* bestPattern, int32_t capacity, - UErrorCode* pErrorCode) -{ - MOZ_CRASH("udatpg_getBestPattern: Intl API disabled"); -} - -static const UChar * -udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg, - UDateTimePatternField field, - int32_t *pLength) -{ - MOZ_CRASH("udatpg_getAppendItemName: Intl API disabled"); -} - -static void -udatpg_close(UDateTimePatternGenerator* dtpg) -{ - MOZ_CRASH("udatpg_close: Intl API disabled"); -} - -typedef void* UCalendar; -typedef void* UDateFormat; - -enum UDateFormatField { - UDAT_ERA_FIELD = 0, - UDAT_YEAR_FIELD = 1, - UDAT_MONTH_FIELD = 2, - UDAT_DATE_FIELD = 3, - UDAT_HOUR_OF_DAY1_FIELD = 4, - UDAT_HOUR_OF_DAY0_FIELD = 5, - UDAT_MINUTE_FIELD = 6, - UDAT_SECOND_FIELD = 7, - UDAT_FRACTIONAL_SECOND_FIELD = 8, - UDAT_DAY_OF_WEEK_FIELD = 9, - UDAT_DAY_OF_YEAR_FIELD = 10, - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11, - UDAT_WEEK_OF_YEAR_FIELD = 12, - UDAT_WEEK_OF_MONTH_FIELD = 13, - UDAT_AM_PM_FIELD = 14, - UDAT_HOUR1_FIELD = 15, - UDAT_HOUR0_FIELD = 16, - UDAT_TIMEZONE_FIELD = 17, - UDAT_YEAR_WOY_FIELD = 18, - UDAT_DOW_LOCAL_FIELD = 19, - UDAT_EXTENDED_YEAR_FIELD = 20, - UDAT_JULIAN_DAY_FIELD = 21, - UDAT_MILLISECONDS_IN_DAY_FIELD = 22, - UDAT_TIMEZONE_RFC_FIELD = 23, - UDAT_TIMEZONE_GENERIC_FIELD = 24, - UDAT_STANDALONE_DAY_FIELD = 25, - UDAT_STANDALONE_MONTH_FIELD = 26, - UDAT_QUARTER_FIELD = 27, - UDAT_STANDALONE_QUARTER_FIELD = 28, - UDAT_TIMEZONE_SPECIAL_FIELD = 29, - UDAT_YEAR_NAME_FIELD = 30, - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31, - UDAT_TIMEZONE_ISO_FIELD = 32, - UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33, - UDAT_RELATED_YEAR_FIELD = 34, - UDAT_AM_PM_MIDNIGHT_NOON_FIELD = 35, - UDAT_FLEXIBLE_DAY_PERIOD_FIELD = 36, - UDAT_TIME_SEPARATOR_FIELD = 37, - UDAT_FIELD_COUNT = 38 -}; - -enum UDateFormatStyle { - UDAT_FULL, - UDAT_LONG, - UDAT_MEDIUM, - UDAT_SHORT, - UDAT_DEFAULT = UDAT_MEDIUM, - UDAT_PATTERN = -2, - UDAT_IGNORE = UDAT_PATTERN -}; - -enum UDateFormatSymbolType { - UDAT_ERAS, - UDAT_MONTHS, - UDAT_SHORT_MONTHS, - UDAT_WEEKDAYS, - UDAT_SHORT_WEEKDAYS, - UDAT_AM_PMS, - UDAT_LOCALIZED_CHARS, - UDAT_ERA_NAMES, - UDAT_NARROW_MONTHS, - UDAT_NARROW_WEEKDAYS, - UDAT_STANDALONE_MONTHS, - UDAT_STANDALONE_SHORT_MONTHS, - UDAT_STANDALONE_NARROW_MONTHS, - UDAT_STANDALONE_WEEKDAYS, - UDAT_STANDALONE_SHORT_WEEKDAYS, - UDAT_STANDALONE_NARROW_WEEKDAYS, - UDAT_QUARTERS, - UDAT_SHORT_QUARTERS, - UDAT_STANDALONE_QUARTERS, - UDAT_STANDALONE_SHORT_QUARTERS, - UDAT_SHORTER_WEEKDAYS, - UDAT_STANDALONE_SHORTER_WEEKDAYS, - UDAT_CYCLIC_YEARS_WIDE, - UDAT_CYCLIC_YEARS_ABBREVIATED, - UDAT_CYCLIC_YEARS_NARROW, - UDAT_ZODIAC_NAMES_WIDE, - UDAT_ZODIAC_NAMES_ABBREVIATED, - UDAT_ZODIAC_NAMES_NARROW -}; - -static int32_t -udat_countAvailable() -{ - MOZ_CRASH("udat_countAvailable: Intl API disabled"); -} - -static const char* -udat_getAvailable(int32_t localeIndex) -{ - MOZ_CRASH("udat_getAvailable: Intl API disabled"); -} - -static UDateFormat* -udat_open(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const char* locale, - const UChar* tzID, int32_t tzIDLength, const UChar* pattern, - int32_t patternLength, UErrorCode* status) -{ - MOZ_CRASH("udat_open: Intl API disabled"); -} - -static const UCalendar* -udat_getCalendar(const UDateFormat* fmt) -{ - MOZ_CRASH("udat_getCalendar: Intl API disabled"); -} - -static void -ucal_setGregorianChange(UCalendar* cal, UDate date, UErrorCode* pErrorCode) -{ - MOZ_CRASH("ucal_setGregorianChange: Intl API disabled"); -} - -static int32_t -udat_format(const UDateFormat* format, UDate dateToFormat, UChar* result, - int32_t resultLength, UFieldPosition* position, UErrorCode* status) -{ - MOZ_CRASH("udat_format: Intl API disabled"); -} - -static int32_t -udat_formatForFields(const UDateFormat* format, UDate dateToFormat, - UChar* result, int32_t resultLength, UFieldPositionIterator* fpositer, - UErrorCode* status) -{ - MOZ_CRASH("udat_formatForFields: Intl API disabled"); -} - -static UFieldPositionIterator* -ufieldpositer_open(UErrorCode* status) -{ - MOZ_CRASH("ufieldpositer_open: Intl API disabled"); -} - -static void -ufieldpositer_close(UFieldPositionIterator* fpositer) -{ - MOZ_CRASH("ufieldpositer_close: Intl API disabled"); -} - -static int32_t -ufieldpositer_next(UFieldPositionIterator* fpositer, int32_t* beginIndex, int32_t* endIndex) -{ - MOZ_CRASH("ufieldpositer_next: Intl API disabled"); -} - -static void -udat_close(UDateFormat* format) -{ - MOZ_CRASH("udat_close: Intl API disabled"); -} - -static int32_t -udat_getSymbols(const UDateFormat *fmt, UDateFormatSymbolType type, int32_t symbolIndex, - UChar *result, int32_t resultLength, UErrorCode *status) -{ - MOZ_CRASH("udat_getSymbols: Intl API disabled"); -} - -#endif - - /******************** Common to Intl constructors ********************/ static bool @@ -706,7 +107,6 @@ intl_availableLocales(JSContext* cx, CountAvailable countAvailable, if (!locales) return false; -#if ENABLE_INTL_API uint32_t count = countAvailable(); RootedValue t(cx, BooleanValue(true)); for (uint32_t i = 0; i < count; i++) { @@ -726,7 +126,7 @@ intl_availableLocales(JSContext* cx, CountAvailable countAvailable, return false; } } -#endif + result.setObject(*locales); return true; } diff --git a/js/src/builtin/Intl.h b/js/src/builtin/Intl.h index b2197060d..9a1e44913 100644 --- a/js/src/builtin/Intl.h +++ b/js/src/builtin/Intl.h @@ -16,9 +16,7 @@ #include "js/GCAPI.h" #include "js/GCHashTable.h" -#if ENABLE_INTL_API #include "unicode/utypes.h" -#endif /* * The Intl module specified by standard ECMA-402, @@ -429,7 +427,6 @@ intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp); extern MOZ_MUST_USE bool intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp); -#if ENABLE_INTL_API /** * Cast char16_t* strings to UChar* strings used by ICU. */ @@ -456,7 +453,6 @@ UCharToChar16(const UChar* chars) { return reinterpret_cast(chars); } -#endif // ENABLE_INTL_API } // namespace js diff --git a/js/src/gdb/moz.build b/js/src/gdb/moz.build index 681f9807c..faa69eb7b 100644 --- a/js/src/gdb/moz.build +++ b/js/src/gdb/moz.build @@ -34,7 +34,7 @@ USE_LIBS += [ 'static:js', ] -if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']: +if CONFIG['MOZ_ICU_DATA_ARCHIVE']: # The ICU libraries linked into libmozjs will not include the ICU data, # so link it directly. USE_LIBS += ['icudata'] diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index f7a6080aa..277a145b0 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -135,7 +135,7 @@ LOCAL_INCLUDES += [ '..', ] -if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']: +if CONFIG['MOZ_ICU_DATA_ARCHIVE']: # The ICU libraries linked into libmozjs will not include the ICU data, # so link it directly. USE_LIBS += ['icudata'] diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 7adeed620..a97a73237 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -36,9 +36,7 @@ #include "jit/InlinableNatives.h" #include "js/Conversions.h" #include "js/UniquePtr.h" -#if ENABLE_INTL_API #include "unicode/unorm.h" -#endif #include "vm/GlobalObject.h" #include "vm/Interpreter.h" #include "vm/Opcodes.h" diff --git a/js/src/moz.build b/js/src/moz.build index 2d4e83db3..a3283b5d6 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -645,18 +645,17 @@ else: FORCE_STATIC_LIB = True STATIC_LIBRARY_NAME = 'js_static' -if CONFIG['ENABLE_INTL_API']: - if not CONFIG['MOZ_ICU_DATA_ARCHIVE']: - USE_LIBS += [ - 'icu', - ] - else: - # Linking 'icu' will pull in the stubdata library, - # which the shell doesn't want, so link the other bits. - USE_LIBS += [ - 'icui18n', - 'icuuc', - ] +if not CONFIG['MOZ_ICU_DATA_ARCHIVE']: + USE_LIBS += [ + 'icu', + ] +else: + # Linking 'icu' will pull in the stubdata library, + # which the shell doesn't want, so link the other bits. + USE_LIBS += [ + 'icui18n', + 'icuuc', + ] USE_LIBS += [ 'nspr', diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8d69ca942..8d144417a 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -893,7 +893,6 @@ SetPromiseRejectionTrackerCallback(JSContext* cx, unsigned argc, Value* vp) return true; } -#ifdef ENABLE_INTL_API static bool AddIntlExtras(JSContext* cx, unsigned argc, Value* vp) { @@ -916,7 +915,6 @@ AddIntlExtras(JSContext* cx, unsigned argc, Value* vp) args.rval().setUndefined(); return true; } -#endif // ENABLE_INTL_API static bool EvalAndPrint(JSContext* cx, const char* bytes, size_t length, @@ -6140,7 +6138,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "Sets the callback to be invoked whenever a Promise rejection is unhandled\n" "or a previously-unhandled rejection becomes handled."), -#ifdef ENABLE_INTL_API JS_FN_HELP("addIntlExtras", AddIntlExtras, 1, 0, "addIntlExtras(obj)", "Adds various not-yet-standardized Intl functions as properties on the\n" @@ -6148,7 +6145,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "functions and their behavior are experimental: don't depend upon them\n" "unless you're willing to update your code if these experimental APIs change\n" "underneath you."), -#endif // ENABLE_INTL_API JS_FS_HELP_END }; diff --git a/js/src/shell/moz.build b/js/src/shell/moz.build index 72ea8145c..e18bad238 100644 --- a/js/src/shell/moz.build +++ b/js/src/shell/moz.build @@ -36,7 +36,7 @@ LOCAL_INCLUDES += [ OS_LIBS += CONFIG['EDITLINE_LIBS'] OS_LIBS += CONFIG['MOZ_ZLIB_LIBS'] -if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']: +if CONFIG['MOZ_ICU_DATA_ARCHIVE']: # The ICU libraries linked into libmozjs will not include the ICU data, # so link it directly. USE_LIBS += ['icudata'] diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp index e35ad4285..ba3145af2 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp @@ -13,9 +13,7 @@ #include "jsutil.h" #include "js/Date.h" -#if ENABLE_INTL_API #include "unicode/timezone.h" -#endif using mozilla::Atomic; using mozilla::ReleaseAcquire; @@ -333,7 +331,7 @@ JS::ResetTimeZone() { js::DateTimeInfo::updateTimeZoneAdjustment(); -#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT) +#if defined(ICU_TZ_HAS_RECREATE_DEFAULT) TZInfo.acquire(); TZInfo.status = IcuTimeZoneInfo::NeedsUpdate; TZInfo.release(); @@ -343,7 +341,7 @@ JS::ResetTimeZone() void js::ResyncICUDefaultTimeZone() { -#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT) +#if defined(ICU_TZ_HAS_RECREATE_DEFAULT) TZInfo.acquire(); if (TZInfo.status == IcuTimeZoneInfo::NeedsUpdate) { icu::TimeZone::recreateDefault(); diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp index 05cc087cc..b4108761f 100644 --- a/js/src/vm/Initialization.cpp +++ b/js/src/vm/Initialization.cpp @@ -20,10 +20,8 @@ #include "jit/ExecutableAllocator.h" #include "jit/Ion.h" #include "js/Utility.h" -#if ENABLE_INTL_API #include "unicode/uclean.h" #include "unicode/utypes.h" -#endif // ENABLE_INTL_API #include "vm/DateTime.h" #include "vm/HelperThreads.h" #include "vm/Runtime.h" -- cgit v1.2.3 From adf982f3cb42be25c01301d107d90c3a8a9ce179 Mon Sep 17 00:00:00 2001 From: JustOff Date: Fri, 4 May 2018 17:28:00 +0300 Subject: Fix regex escaping in old-configure and js/src/old-configure --- js/src/old-configure.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'js') diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 162a071d7..8abea5956 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -734,12 +734,14 @@ case "$target" in dnl VS2012+ defaults to -arch:SSE2. We want to target nothing dnl more recent, so set that explicitly here unless another dnl target arch has already been set. + changequote(,) if test -z `echo $CFLAGS | grep -i [-/]arch:` ; then CFLAGS="$CFLAGS -arch:SSE2" - fi + fi if test -z `echo $CXXFLAGS | grep -i [-/]arch:` ; then CXXFLAGS="$CXXFLAGS -arch:SSE2" fi + changequote([,]) fi dnl VS2013+ requires -FS when parallel building by make -jN. dnl If nothing, compiler sometimes causes C1041 error. -- cgit v1.2.3 From 74c62cd3373e23fe77f509373f581c33872d813d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 4 May 2018 21:47:32 +0200 Subject: Issue #325 Part 14: Remove EXPOSE_INTL_API conditionals. --- js/src/builtin/Array.js | 8 -- js/src/builtin/String.js | 6 -- js/src/builtin/TestingFunctions.cpp | 4 - js/src/builtin/TypedArray.js | 8 -- js/src/jsapi.h | 2 +- js/src/jsdate.cpp | 77 -------------- js/src/jsnum.cpp | 204 +----------------------------------- js/src/jsnum.h | 5 - js/src/jsprototypes.h | 4 - js/src/jsstr.cpp | 41 -------- js/src/jsstr.h | 5 - js/src/vm/GlobalObject.cpp | 4 +- js/src/vm/Initialization.cpp | 8 -- js/src/vm/Runtime.cpp | 9 -- js/src/vm/Runtime.h | 7 -- js/src/vm/SelfHosting.cpp | 4 - 16 files changed, 4 insertions(+), 392 deletions(-) (limited to 'js') diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 45f90a7b8..360dd2af1 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -900,11 +900,7 @@ function ArrayToLocaleString(locales, options) { if (firstElement === undefined || firstElement === null) { R = ""; } else { -#if EXPOSE_INTL_API R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options)); -#else - R = ToString(callContentFunction(firstElement.toLocaleString, firstElement)); -#endif } // Step 3 (reordered). @@ -919,11 +915,7 @@ function ArrayToLocaleString(locales, options) { // Steps 9.a, 9.c-e. R += separator; if (!(nextElement === undefined || nextElement === null)) { -#if EXPOSE_INTL_API R += ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options)); -#else - R += ToString(callContentFunction(nextElement.toLocaleString, nextElement)); -#endif } } diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index 4202d0de6..6d1d335a0 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -659,11 +659,7 @@ function String_static_localeCompare(str1, str2) { ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "String.localeCompare"); var locales = arguments.length > 2 ? arguments[2] : undefined; var options = arguments.length > 3 ? arguments[3] : undefined; -#if EXPOSE_INTL_API return callFunction(String_localeCompare, str1, str2, locales, options); -#else - return callFunction(std_String_localeCompare, str1, str2, locales, options); -#endif } // ES6 draft 2014-04-27 B.2.3.3 @@ -855,14 +851,12 @@ function String_static_toLocaleUpperCase(string) { return callFunction(std_String_toLocaleUpperCase, string); } -#if EXPOSE_INTL_API function String_static_normalize(string) { if (arguments.length < 1) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.normalize'); var form = arguments.length > 1 ? arguments[1] : undefined; return callFunction(std_String_normalize, string, form); } -#endif function String_static_concat(string, arg1) { if (arguments.length < 1) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index a14f9ba69..00637a7a5 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -236,11 +236,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) if (!JS_SetProperty(cx, info, "binary-data", value)) return false; -#ifdef EXPOSE_INTL_API value = BooleanValue(true); -#else - value = BooleanValue(false); -#endif if (!JS_SetProperty(cx, info, "intl-api", value)) return false; diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index a2205dc92..a1934051d 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -1232,11 +1232,7 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) { // Steps 6-7. // Omit the 'if' clause in step 6, since typed arrays can't have undefined // or null elements. -#if EXPOSE_INTL_API var R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options)); -#else - var R = ToString(callContentFunction(firstElement.toLocaleString, firstElement)); -#endif // Step 3 (reordered). // We don't (yet?) implement locale-dependent separators. @@ -1258,11 +1254,7 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) { // the error message. So despite bug 1079853, we can skip step 9.c. // Step 9.d. -#if EXPOSE_INTL_API R = ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options)); -#else - R = ToString(callContentFunction(nextElement.toLocaleString, nextElement)); -#endif // Step 9.e. R = S + R; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 989abe47c..c1195cc00 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5222,7 +5222,7 @@ JS_ResetDefaultLocale(JSContext* cx); struct JSLocaleCallbacks { JSLocaleToUpperCase localeToUpperCase; JSLocaleToLowerCase localeToLowerCase; - JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API + JSLocaleCompare localeCompare; // not used JSLocaleToUnicode localeToUnicode; }; diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 00a8abf84..52294a5df 100755 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -2743,77 +2743,6 @@ ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, Mutabl return true; } -#if !EXPOSE_INTL_API -/* 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. - */ - static const char format[] = -#if defined(_WIN32) && !defined(__MWERKS__) - "%#c" -#else - "%c" -#endif - ; - - Rooted dateObj(cx, &args.thisv().toObject().as()); - return ToLocaleFormatHelper(cx, dateObj, format, args.rval()); -} - -static bool -date_toLocaleString(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -/* ES5 15.9.5.6. */ -MOZ_ALWAYS_INLINE bool -date_toLocaleDateString_impl(JSContext* cx, const CallArgs& args) -{ - /* - * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k - * with msvc; '%#x' requests that a full year be used in the result string. - */ - static const char format[] = -#if defined(_WIN32) && !defined(__MWERKS__) - "%#x" -#else - "%x" -#endif - ; - - Rooted dateObj(cx, &args.thisv().toObject().as()); - return ToLocaleFormatHelper(cx, dateObj, format, args.rval()); -} - -static bool -date_toLocaleDateString(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -/* ES5 15.9.5.7. */ -MOZ_ALWAYS_INLINE bool -date_toLocaleTimeString_impl(JSContext* cx, const CallArgs& args) -{ - Rooted dateObj(cx, &args.thisv().toObject().as()); - return ToLocaleFormatHelper(cx, dateObj, "%X", args.rval()); -} - -static bool -date_toLocaleTimeString(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} -#endif /* !EXPOSE_INTL_API */ - MOZ_ALWAYS_INLINE bool date_toLocaleFormat_impl(JSContext* cx, const CallArgs& args) { @@ -3037,15 +2966,9 @@ static const JSFunctionSpec date_methods[] = { JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0), JS_FN("toUTCString", date_toGMTString, 0,0), JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0), -#if EXPOSE_INTL_API JS_SELF_HOSTED_FN(js_toLocaleString_str, "Date_toLocaleString", 0,0), JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0), JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0), -#else - JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0), - JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0), - JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0), -#endif JS_FN("toDateString", date_toDateString, 0,0), JS_FN("toTimeString", date_toTimeString, 0,0), JS_FN("toISOString", date_toISOString, 0,0), diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 8885737f7..98d045987 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -724,141 +724,6 @@ js::num_toString(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } -#if !EXPOSE_INTL_API -MOZ_ALWAYS_INLINE bool -num_toLocaleString_impl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsNumber(args.thisv())); - - double d = Extract(args.thisv()); - - RootedString str(cx, NumberToStringWithBase(cx, d, 10)); - if (!str) { - JS_ReportOutOfMemory(cx); - return false; - } - - /* - * Create the string, move back to bytes to make string twiddling - * a bit easier and so we can insert platform charset seperators. - */ - JSAutoByteString numBytes(cx, str); - if (!numBytes) - return false; - const char* num = numBytes.ptr(); - if (!num) - return false; - - /* - * Find the first non-integer value, whether it be a letter as in - * 'Infinity', a decimal point, or an 'e' from exponential notation. - */ - const char* nint = num; - if (*nint == '-') - nint++; - while (*nint >= '0' && *nint <= '9') - nint++; - int digits = nint - num; - const char* end = num + digits; - if (!digits) { - args.rval().setString(str); - return true; - } - - JSRuntime* rt = cx->runtime(); - size_t thousandsLength = strlen(rt->thousandsSeparator); - size_t decimalLength = strlen(rt->decimalSeparator); - - /* Figure out how long resulting string will be. */ - int buflen = strlen(num); - if (*nint == '.') - buflen += decimalLength - 1; /* -1 to account for existing '.' */ - - const char* numGrouping; - const char* tmpGroup; - numGrouping = tmpGroup = rt->numGrouping; - int remainder = digits; - if (*num == '-') - remainder--; - - while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') { - if (*tmpGroup >= remainder) - break; - buflen += thousandsLength; - remainder -= *tmpGroup; - tmpGroup++; - } - - int nrepeat; - if (*tmpGroup == '\0' && *numGrouping != '\0') { - nrepeat = (remainder - 1) / tmpGroup[-1]; - buflen += thousandsLength * nrepeat; - remainder -= nrepeat * tmpGroup[-1]; - } else { - nrepeat = 0; - } - tmpGroup--; - - char* buf = cx->pod_malloc(buflen + 1); - if (!buf) - return false; - - char* tmpDest = buf; - const char* tmpSrc = num; - - while (*tmpSrc == '-' || remainder--) { - MOZ_ASSERT(tmpDest - buf < buflen); - *tmpDest++ = *tmpSrc++; - } - while (tmpSrc < end) { - MOZ_ASSERT(tmpDest - buf + ptrdiff_t(thousandsLength) <= buflen); - strcpy(tmpDest, rt->thousandsSeparator); - tmpDest += thousandsLength; - MOZ_ASSERT(tmpDest - buf + *tmpGroup <= buflen); - js_memcpy(tmpDest, tmpSrc, *tmpGroup); - tmpDest += *tmpGroup; - tmpSrc += *tmpGroup; - if (--nrepeat < 0) - tmpGroup--; - } - - if (*nint == '.') { - MOZ_ASSERT(tmpDest - buf + ptrdiff_t(decimalLength) <= buflen); - strcpy(tmpDest, rt->decimalSeparator); - tmpDest += decimalLength; - MOZ_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint + 1)) <= buflen); - strcpy(tmpDest, nint + 1); - } else { - MOZ_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen); - strcpy(tmpDest, nint); - } - - if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUnicode) { - Rooted v(cx, StringValue(str)); - bool ok = !!cx->runtime()->localeCallbacks->localeToUnicode(cx, buf, &v); - if (ok) - args.rval().set(v); - js_free(buf); - return ok; - } - - str = NewStringCopyN(cx, buf, buflen); - js_free(buf); - if (!str) - return false; - - args.rval().setString(str); - return true; -} - -static bool -num_toLocaleString(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} -#endif /* !EXPOSE_INTL_API */ - MOZ_ALWAYS_INLINE bool num_valueOf_impl(JSContext* cx, const CallArgs& args) { @@ -1075,11 +940,7 @@ static const JSFunctionSpec number_methods[] = { JS_FN(js_toSource_str, num_toSource, 0, 0), #endif JS_FN(js_toString_str, num_toString, 1, 0), -#if EXPOSE_INTL_API JS_SELF_HOSTED_FN(js_toLocaleString_str, "Number_toLocaleString", 0,0), -#else - JS_FN(js_toLocaleString_str, num_toLocaleString, 0,0), -#endif JS_FN(js_valueOf_str, num_valueOf, 0, 0), JS_FN("toFixed", num_toFixed, 1, 0), JS_FN("toExponential", num_toExponential, 1, 0), @@ -1135,72 +996,11 @@ js::InitRuntimeNumberState(JSRuntime* rt) { FIX_FPU(); - // XXX If EXPOSE_INTL_API becomes true all the time at some point, - // js::InitRuntimeNumberState is no longer fallible, and we should - // change its return type. -#if !EXPOSE_INTL_API - /* Copy locale-specific separators into the runtime strings. */ - const char* thousandsSeparator; - const char* decimalPoint; - const char* grouping; -#ifdef HAVE_LOCALECONV - struct lconv* locale = localeconv(); - thousandsSeparator = locale->thousands_sep; - decimalPoint = locale->decimal_point; - grouping = locale->grouping; -#else - thousandsSeparator = getenv("LOCALE_THOUSANDS_SEP"); - decimalPoint = getenv("LOCALE_DECIMAL_POINT"); - grouping = getenv("LOCALE_GROUPING"); -#endif - if (!thousandsSeparator) - thousandsSeparator = "'"; - if (!decimalPoint) - decimalPoint = "."; - if (!grouping) - grouping = "\3\0"; - - /* - * We use single malloc to get the memory for all separator and grouping - * strings. - */ - size_t thousandsSeparatorSize = strlen(thousandsSeparator) + 1; - size_t decimalPointSize = strlen(decimalPoint) + 1; - size_t groupingSize = strlen(grouping) + 1; - - char* storage = js_pod_malloc(thousandsSeparatorSize + - decimalPointSize + - groupingSize); - if (!storage) - return false; - - js_memcpy(storage, thousandsSeparator, thousandsSeparatorSize); - rt->thousandsSeparator = storage; - storage += thousandsSeparatorSize; - - js_memcpy(storage, decimalPoint, decimalPointSize); - rt->decimalSeparator = storage; - storage += decimalPointSize; - - js_memcpy(storage, grouping, groupingSize); - rt->numGrouping = grouping; -#endif /* !EXPOSE_INTL_API */ + // XXX EXPOSE_INTL_API has become true all the time, meaning this is + // no longer fallible, and we should change its return type. return true; } -#if !EXPOSE_INTL_API -void -js::FinishRuntimeNumberState(JSRuntime* rt) -{ - /* - * The free also releases the memory for decimalSeparator and numGrouping - * strings. - */ - char* storage = const_cast(rt->thousandsSeparator); - js_free(storage); -} -#endif - JSObject* js::InitNumberClass(JSContext* cx, HandleObject obj) { diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 62b3d617f..2e7049888 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -37,11 +37,6 @@ class StringBuffer; extern MOZ_MUST_USE bool InitRuntimeNumberState(JSRuntime* rt); -#if !EXPOSE_INTL_API -extern void -FinishRuntimeNumberState(JSRuntime* rt); -#endif - /* Initialize the Number class, returning its prototype object. */ extern JSObject* InitNumberClass(JSContext* cx, HandleObject obj); diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index f409dce95..dc7cdb85a 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -37,11 +37,7 @@ #define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[Scalar::type]) #define ERROR_CLASP(type) (&ErrorObject::classes[type]) -#ifdef EXPOSE_INTL_API #define IF_INTL(real,imaginary) real -#else -#define IF_INTL(real,imaginary) imaginary -#endif #ifdef ENABLE_BINARYDATA #define IF_BDATA(real,imaginary) real diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index a97a73237..01b407626 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -897,38 +897,6 @@ js::str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp) return ToUpperCaseHelper(cx, args); } -#if !EXPOSE_INTL_API -bool -js::str_localeCompare(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - RootedString str(cx, ToStringForStringFunction(cx, args.thisv())); - if (!str) - return false; - - RootedString thatStr(cx, ToString(cx, args.get(0))); - if (!thatStr) - return false; - - if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeCompare) { - RootedValue result(cx); - if (!cx->runtime()->localeCallbacks->localeCompare(cx, str, thatStr, &result)) - return false; - - args.rval().set(result); - return true; - } - - int32_t result; - if (!CompareStrings(cx, str, thatStr, &result)) - return false; - - args.rval().setInt32(result); - return true; -} -#endif - -#if EXPOSE_INTL_API /* ES6 20140210 draft 21.1.3.12. */ bool js::str_normalize(JSContext* cx, unsigned argc, Value* vp) @@ -1005,7 +973,6 @@ js::str_normalize(JSContext* cx, unsigned argc, Value* vp) args.rval().setString(ns); return true; } -#endif bool js::str_charAt(JSContext* cx, unsigned argc, Value* vp) @@ -2597,15 +2564,9 @@ static const JSFunctionSpec string_methods[] = { JS_FN("trimRight", str_trimRight, 0,0), JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0), JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0), -#if EXPOSE_INTL_API JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0), -#else - JS_FN("localeCompare", str_localeCompare, 1,0), -#endif JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0), -#if EXPOSE_INTL_API JS_FN("normalize", str_normalize, 0,0), -#endif /* Perl-ish methods (search is actually Python-esque). */ JS_SELF_HOSTED_FN("match", "String_match", 1,0), @@ -2916,9 +2877,7 @@ static const JSFunctionSpec string_static_methods[] = { JS_SELF_HOSTED_FN("trimRight", "String_static_trimRight", 1,0), JS_SELF_HOSTED_FN("toLocaleLowerCase","String_static_toLocaleLowerCase",1,0), JS_SELF_HOSTED_FN("toLocaleUpperCase","String_static_toLocaleUpperCase",1,0), -#if EXPOSE_INTL_API JS_SELF_HOSTED_FN("normalize", "String_static_normalize", 1,0), -#endif JS_SELF_HOSTED_FN("concat", "String_static_concat", 2,0), JS_SELF_HOSTED_FN("localeCompare", "String_static_localeCompare", 2,0), diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 7e9621d4a..118118839 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -378,13 +378,8 @@ str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp); extern bool str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp); -#if !EXPOSE_INTL_API -extern bool -str_localeCompare(JSContext* cx, unsigned argc, Value* vp); -#else extern bool str_normalize(JSContext* cx, unsigned argc, Value* vp); -#endif extern bool str_concat(JSContext* cx, unsigned argc, Value* vp); diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 280548cd6..c90b6b85f 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -17,9 +17,7 @@ #include "builtin/AtomicsObject.h" #include "builtin/Eval.h" -#if EXPOSE_INTL_API -# include "builtin/Intl.h" -#endif +#include "builtin/Intl.h" #include "builtin/MapObject.h" #include "builtin/ModuleObject.h" #include "builtin/Object.h" diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp index b4108761f..39acdf9a8 100644 --- a/js/src/vm/Initialization.cpp +++ b/js/src/vm/Initialization.cpp @@ -111,12 +111,10 @@ JS::detail::InitWithFailureDiagnostic(bool isDebugBuild) js::DateTimeInfo::init(); -#if EXPOSE_INTL_API UErrorCode err = U_ZERO_ERROR; u_init(&err); if (U_FAILURE(err)) return "u_init() failed"; -#endif // EXPOSE_INTL_API RETURN_IF_FAIL(js::CreateHelperThreadsState()); RETURN_IF_FAIL(FutexRuntime::initialize()); @@ -169,9 +167,7 @@ JS_ShutDown(void) // to do it only when PRMJ_Now is eventually called. PRMJ_NowShutdown(); -#if EXPOSE_INTL_API u_cleanup(); -#endif // EXPOSE_INTL_API if (!JSRuntime::hasLiveRuntimes()) js::jit::ReleaseProcessExecutableMemory(); @@ -186,11 +182,7 @@ JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_IC "must call JS_SetICUMemoryFunctions before any other JSAPI " "operation (including JS_Init)"); -#if EXPOSE_INTL_API UErrorCode status = U_ZERO_ERROR; u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status); return U_SUCCESS(status); -#else - return true; -#endif } diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 0d6a3922c..0e7ce7f10 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -213,11 +213,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime) warningReporter(nullptr), buildIdOp(nullptr), propertyRemovals(0), -#if !EXPOSE_INTL_API - thousandsSeparator(0), - decimalSeparator(0), - numGrouping(0), -#endif keepAtoms_(0), trustedPrincipals_(nullptr), beingDestroyed_(false), @@ -425,10 +420,6 @@ JSRuntime::destroyRuntime() */ FreeScriptData(this, lock); -#if !EXPOSE_INTL_API - FinishRuntimeNumberState(this); -#endif - gc.finish(); atomsCompartment_ = nullptr; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 734543c4e..735adadf2 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -978,13 +978,6 @@ struct JSRuntime : public JS::shadow::Runtime, */ uint32_t propertyRemovals; -#if !EXPOSE_INTL_API - /* Number localization, used by jsnum.cpp. */ - const char* thousandsSeparator; - const char* decimalSeparator; - const char* numGrouping; -#endif - private: mozilla::Maybe sharedImmutableStrings_; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 9a8ec7679..653807ce8 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2205,11 +2205,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("std_String_trimRight", str_trimRight, 0,0), JS_FN("std_String_toLocaleLowerCase", str_toLocaleLowerCase, 0,0), JS_FN("std_String_toLocaleUpperCase", str_toLocaleUpperCase, 0,0), -#if !EXPOSE_INTL_API - JS_FN("std_String_localeCompare", str_localeCompare, 1,0), -#else JS_FN("std_String_normalize", str_normalize, 0,0), -#endif JS_FN("std_String_concat", str_concat, 1,0), JS_FN("std_TypedArray_buffer", js::TypedArray_bufferGetter, 1,0), -- cgit v1.2.3 From 891026d00551992f4c957eb20c13d65183126605 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 4 May 2018 22:02:48 +0200 Subject: Make InitRuntimeNumberState's return type reflect its infallible nature. --- js/src/jsnum.cpp | 6 +----- js/src/jsnum.h | 3 +-- js/src/vm/Runtime.cpp | 3 +-- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'js') diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 98d045987..28ed15159 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -991,14 +991,10 @@ js::FIX_FPU() #endif } -bool +void js::InitRuntimeNumberState(JSRuntime* rt) { FIX_FPU(); - - // XXX EXPOSE_INTL_API has become true all the time, meaning this is - // no longer fallible, and we should change its return type. - return true; } JSObject* diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 2e7049888..8dff45f69 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -34,8 +34,7 @@ namespace js { class StringBuffer; -extern MOZ_MUST_USE bool -InitRuntimeNumberState(JSRuntime* rt); +void InitRuntimeNumberState(JSRuntime* rt); /* Initialize the Number class, returning its prototype object. */ extern JSObject* diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 0e7ce7f10..174e23594 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -325,8 +325,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) /* The garbage collector depends on everything before this point being initialized. */ gcInitialized = true; - if (!InitRuntimeNumberState(this)) - return false; + InitRuntimeNumberState(this); JS::ResetTimeZone(); -- cgit v1.2.3 From ac25827a87d86f1cf9e48aab6605f77a2c89041a Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 24 May 2018 14:06:04 +0200 Subject: Remove SPS profiler. - Conditionals and code blocks. (MOZ_ENABLE_PROFILER_SPS) - Stub out several profiler-only functions. --- js/xpconnect/src/XPCJSContext.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'js') diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 8862bca32..f352607d4 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -1528,12 +1528,6 @@ XPCJSContext::~XPCJSContext() delete mDyingWrappedNativeProtoMap; mDyingWrappedNativeProtoMap = nullptr; -#ifdef MOZ_ENABLE_PROFILER_SPS - // Tell the profiler that the context is gone - if (PseudoStack* stack = mozilla_get_pseudo_stack()) - stack->sampleContext(nullptr); -#endif - Preferences::UnregisterCallback(ReloadPrefsCallback, JS_OPTIONS_DOT_STR, this); } @@ -3382,10 +3376,6 @@ XPCJSContext::Initialize() JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this); JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks); js::SetPreserveWrapperCallback(cx, PreserveWrapper); -#ifdef MOZ_ENABLE_PROFILER_SPS - if (PseudoStack* stack = mozilla_get_pseudo_stack()) - stack->sampleContext(cx); -#endif JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback); js::SetActivityCallback(cx, ActivityCallback, this); JS_AddInterruptCallback(cx, InterruptCallback); -- cgit v1.2.3 From bd851735628cd6b07285e87fa60081e9d11a3b7e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 26 May 2018 15:00:01 -0400 Subject: Remove support and tests for HSTS priming from the tree. Fixes #384 --- js/ipc/JavaScriptParent.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'js') diff --git a/js/ipc/JavaScriptParent.cpp b/js/ipc/JavaScriptParent.cpp index 7fe92d662..ca0a0bd21 100644 --- a/js/ipc/JavaScriptParent.cpp +++ b/js/ipc/JavaScriptParent.cpp @@ -16,6 +16,7 @@ #include "xpcprivate.h" #include "mozilla/Casting.h" #include "mozilla/Telemetry.h" +#include "mozilla/Unused.h" #include "nsAutoPtr.h" using namespace js; -- cgit v1.2.3 From 12e3ee76966664ca0330738a07c7afb9fd754857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Mon, 14 May 2018 10:39:09 -0700 Subject: Update tzdata in ICU data files to 2018e. --- js/src/builtin/IntlTimeZoneData.h | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js | 2 +- js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'js') diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index 3d5c1b0d5..fa808c0b9 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018d +// tzdata version = 2018e #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js index 7b3a46a60..d87abd7be 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018d +// tzdata version = 2018e const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js index ed63df921..b96dac96f 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018d +// tzdata version = 2018e const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js index 215808765..66ef3075d 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018d +// tzdata version = 2018e const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js index 48242dfbd..8d44204bc 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018d +// tzdata version = 2018e const tzMapper = [ x => x, -- cgit v1.2.3 From ff901dc5267903b165c53139ddcff5f31bbf6964 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 6 Apr 2018 13:24:25 -0400 Subject: Change inlining of intrinsics. --- js/src/builtin/Array.js | 13 +++++----- js/src/builtin/Map.js | 6 ++--- js/src/builtin/Set.js | 6 ++--- js/src/builtin/String.js | 9 ++++--- js/src/jit/CodeGenerator.cpp | 26 +++++++++++++++++++ js/src/jit/CodeGenerator.h | 1 + js/src/jit/InlinableNatives.h | 10 +++++--- js/src/jit/IonBuilder.h | 1 + js/src/jit/Lowering.cpp | 10 ++++++++ js/src/jit/Lowering.h | 1 + js/src/jit/MCallOptimize.cpp | 51 +++++++++++++++++++++++++++++++------ js/src/jit/MIR.h | 42 ++++++++++++++++++++++++++++++ js/src/jit/MOpcodes.h | 1 + js/src/jit/shared/LIR-shared.h | 23 +++++++++++++++++ js/src/jit/shared/LOpcodes-shared.h | 1 + js/src/vm/SelfHosting.cpp | 45 +++++++++++++++++++++++--------- 16 files changed, 206 insertions(+), 40 deletions(-) (limited to 'js') diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 360dd2af1..30e6fb35f 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -711,13 +711,14 @@ function CreateArrayIterator(obj, kind) { // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next function ArrayIteratorNext() { // Step 1-3. - if (!IsObject(this) || !IsArrayIterator(this)) { + var obj; + if (!IsObject(this) || (obj = GuardToArrayIterator(this)) === null) { return callFunction(CallArrayIteratorMethodIfWrapped, this, "ArrayIteratorNext"); } // Step 4. - var a = UnsafeGetReservedSlot(this, ITERATOR_SLOT_TARGET); + var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET); var result = { value: undefined, done: false }; // Step 5. @@ -728,10 +729,10 @@ function ArrayIteratorNext() { // Step 6. // The index might not be an integer, so we have to do a generic get here. - var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); + var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); // Step 7. - var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND); + var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND); // Step 8-9. var len = IsPossiblyWrappedTypedArray(a) @@ -740,13 +741,13 @@ function ArrayIteratorNext() { // Step 10. if (index >= len) { - UnsafeSetReservedSlot(this, ITERATOR_SLOT_TARGET, null); + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null); result.done = true; return result; } // Step 11. - UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1); + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1); // Step 16. if (itemKind === ITEM_KIND_VALUE) { diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 580629a13..434cd6529 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -62,8 +62,8 @@ function MapIteratorNext() { var O = this; // Steps 2-3. - if (!IsObject(O) || !IsMapIterator(O)) - return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext"); + if (!IsObject(O) || (O = GuardToMapIterator(O)) === null) + return callFunction(CallMapIteratorMethodIfWrapped, this, "MapIteratorNext"); // Steps 4-5 (implemented in _GetNextMapEntryForIterator). // Steps 8-9 (omitted). @@ -82,7 +82,7 @@ function MapIteratorNext() { // Steps 10.b-c (omitted). // Step 6. - var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND); + var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND); var result; if (itemKind === ITEM_KIND_KEY) { diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js index 9af6cf8d1..e2571e66a 100644 --- a/js/src/builtin/Set.js +++ b/js/src/builtin/Set.js @@ -64,8 +64,8 @@ function SetIteratorNext() { var O = this; // Steps 2-3. - if (!IsObject(O) || !IsSetIterator(O)) - return callFunction(CallSetIteratorMethodIfWrapped, O, "SetIteratorNext"); + if (!IsObject(O) || (O = GuardToSetIterator(O)) === null) + return callFunction(CallSetIteratorMethodIfWrapped, this, "SetIteratorNext"); // Steps 4-5 (implemented in _GetNextSetEntryForIterator). // Steps 8-9 (omitted). @@ -83,7 +83,7 @@ function SetIteratorNext() { // Steps 10.b-c (omitted). // Step 6. - var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND); + var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND); var result; if (itemKind === ITEM_KIND_VALUE) { diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index 6d1d335a0..e5b2ad552 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -529,16 +529,17 @@ function String_iterator() { } function StringIteratorNext() { - if (!IsObject(this) || !IsStringIterator(this)) { + var obj; + if (!IsObject(this) || (obj = GuardToStringIterator(this)) === null) { return callFunction(CallStringIteratorMethodIfWrapped, this, "StringIteratorNext"); } - var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET); + var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET); // We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in // SelfHostring.cpp) so our current index can never be anything other than // an Int32Value. - var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); + var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); var size = S.length; var result = { value: undefined, done: false }; @@ -556,7 +557,7 @@ function StringIteratorNext() { } } - UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount); + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount); result.value = callFunction(String_substring, S, index, index + charCount); return result; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 7b2f8214b..16d026092 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -11528,6 +11528,32 @@ CodeGenerator::visitHasClass(LHasClass* ins) masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output); } +void +CodeGenerator::visitGuardToClass(LGuardToClass* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register output = ToRegister(ins->output()); + Register temp = ToRegister(ins->temp()); + + Label notEqual; + + masm.branchTestObjClass(Assembler::NotEqual, lhs, temp, ins->mir()->getClass(), ¬Equal); + masm.mov(lhs, output); + + if (ins->mir()->type() == MIRType::Object) { + // Can't return null-return here, so bail + bailoutFrom(¬Equal, ins->snapshot()); + } else { + Label done; + masm.jump(&done); + + masm.bind(¬Equal); + masm.mov(ImmPtr(0), output); + + masm.bind(&done); + } +} + void CodeGenerator::visitWasmParameter(LWasmParameter* lir) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index d3126651b..b226f6cc9 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -377,6 +377,7 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitIsObject(LIsObject* lir); void visitIsObjectAndBranch(LIsObjectAndBranch* lir); void visitHasClass(LHasClass* lir); + void visitGuardToClass(LGuardToClass* lir); void visitWasmParameter(LWasmParameter* lir); void visitWasmParameterI64(LWasmParameterI64* lir); void visitWasmReturn(LWasmReturn* ret); diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 89c2ff0a4..18535389a 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -117,14 +117,16 @@ _(IntrinsicDefineDataProperty) \ _(IntrinsicObjectHasPrototype) \ \ - _(IntrinsicIsArrayIterator) \ - _(IntrinsicIsMapIterator) \ - _(IntrinsicIsSetIterator) \ - _(IntrinsicIsStringIterator) \ + _(IntrinsicGuardToArrayIterator) \ + _(IntrinsicGuardToMapIterator) \ + _(IntrinsicGuardToSetIterator) \ _(IntrinsicIsListIterator) \ + _(IntrinsicGuardToStringIterator) \ \ + _(IntrinsicGuardToMapObject) \ _(IntrinsicGetNextMapEntryForIterator) \ \ + _(IntrinsicGuardToSetObject) \ _(IntrinsicGetNextSetEntryForIterator) \ \ _(IntrinsicArrayBufferByteLength) \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 35ad120f7..f24ef30c8 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -969,6 +969,7 @@ class IonBuilder const Class* clasp2 = nullptr, const Class* clasp3 = nullptr, const Class* clasp4 = nullptr); + InliningStatus inlineGuardToClass(CallInfo& callInfo, const Class* clasp); InliningStatus inlineIsConstructing(CallInfo& callInfo); InliningStatus inlineSubstringKernel(CallInfo& callInfo); InliningStatus inlineObjectHasPrototype(CallInfo& callInfo); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 730697163..709de9987 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4170,6 +4170,16 @@ LIRGenerator::visitHasClass(MHasClass* ins) define(new(alloc()) LHasClass(useRegister(ins->object())), ins); } +void +LIRGenerator::visitGuardToClass(MGuardToClass* ins) +{ + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::ObjectOrNull|| ins->type() == MIRType::Object); + LGuardToClass* lir = new(alloc()) LGuardToClass(useRegister(ins->object()), temp()); + assignSnapshot(lir, Bailout_TypeBarrierO); + define(lir, ins); +} + void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index b2805cb7a..9b4095aec 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -289,6 +289,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitIsConstructor(MIsConstructor* ins); void visitIsObject(MIsObject* ins); void visitHasClass(MHasClass* ins); + void visitGuardToClass(MGuardToClass* ins); void visitWasmAddOffset(MWasmAddOffset* ins); void visitWasmBoundsCheck(MWasmBoundsCheck* ins); void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 202aef497..01755094a 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -280,14 +280,14 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineIsConstructing(callInfo); case InlinableNative::IntrinsicSubstringKernel: return inlineSubstringKernel(callInfo); - case InlinableNative::IntrinsicIsArrayIterator: - return inlineHasClass(callInfo, &ArrayIteratorObject::class_); - case InlinableNative::IntrinsicIsMapIterator: - return inlineHasClass(callInfo, &MapIteratorObject::class_); - case InlinableNative::IntrinsicIsSetIterator: - return inlineHasClass(callInfo, &SetIteratorObject::class_); - case InlinableNative::IntrinsicIsStringIterator: - return inlineHasClass(callInfo, &StringIteratorObject::class_); + case InlinableNative::IntrinsicGuardToArrayIterator: + return inlineGuardToClass(callInfo, &ArrayIteratorObject::class_); + case InlinableNative::IntrinsicGuardToMapIterator: + return inlineGuardToClass(callInfo, &MapIteratorObject::class_); + case InlinableNative::IntrinsicGuardToSetIterator: + return inlineGuardToClass(callInfo, &SetIteratorObject::class_); + case InlinableNative::IntrinsicGuardToStringIterator: + return inlineGuardToClass(callInfo, &StringIteratorObject::class_); case InlinableNative::IntrinsicIsListIterator: return inlineHasClass(callInfo, &ListIteratorObject::class_); case InlinableNative::IntrinsicDefineDataProperty: @@ -296,10 +296,14 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineObjectHasPrototype(callInfo); // Map intrinsics. + case InlinableNative::IntrinsicGuardToMapObject: + return inlineGuardToClass(callInfo, &MapObject::class_); case InlinableNative::IntrinsicGetNextMapEntryForIterator: return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map); // Set intrinsics. + case InlinableNative::IntrinsicGuardToSetObject: + return inlineGuardToClass(callInfo, &SetObject::class_); case InlinableNative::IntrinsicGetNextSetEntryForIterator: return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set); @@ -2219,6 +2223,37 @@ IonBuilder::inlineHasClass(CallInfo& callInfo, return InliningStatus_Inlined; } +IonBuilder::InliningStatus +IonBuilder::inlineGuardToClass(CallInfo& callInfo, const Class* clasp) +{ + MOZ_ASSERT(!callInfo.constructing()); + MOZ_ASSERT(callInfo.argc() == 1); + + if (callInfo.getArg(0)->type() != MIRType::Object) + return InliningStatus_NotInlined; + + if (getInlineReturnType() != MIRType::ObjectOrNull && + getInlineReturnType() != MIRType::Object) + { + return InliningStatus_NotInlined; + } + + TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet(); + const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr; + + if (knownClass && knownClass == clasp) { + current->push(callInfo.getArg(0)); + } else { + MGuardToClass* guardToClass = MGuardToClass::New(alloc(), callInfo.getArg(0), + clasp, getInlineReturnType()); + current->add(guardToClass); + current->push(guardToClass); + } + + callInfo.setImplicitlyUsedUnchecked(); + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 2de91e2df..6ec05af76 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -13192,6 +13192,48 @@ class MHasClass } }; +class MGuardToClass + : public MUnaryInstruction, + public SingleObjectPolicy::Data +{ + const Class* class_; + + MGuardToClass(MDefinition* object, const Class* clasp, MIRType resultType) + : MUnaryInstruction(object) + , class_(clasp) + { + MOZ_ASSERT(object->type() == MIRType::Object || + (object->type() == MIRType::Value && object->mightBeType(MIRType::Object))); + MOZ_ASSERT(resultType == MIRType::Object || resultType == MIRType::ObjectOrNull); + setResultType(resultType); + setMovable(); + if (resultType == MIRType::Object) { + // We will bail out if the class type is incorrect, + // so we need to ensure we don't eliminate this instruction + setGuard(); + } + } + + public: + INSTRUCTION_HEADER(GuardToClass) + TRIVIAL_NEW_WRAPPERS + NAMED_OPERANDS((0, object)) + + const Class* getClass() const { + return class_; + } + AliasSet getAliasSet() const override { + return AliasSet::None(); + } + bool congruentTo(const MDefinition* ins) const override { + if (!ins->isGuardToClass()) + return false; + if (getClass() != ins->toGuardToClass()->getClass()) + return false; + return congruentIfOperandsEqual(ins); + } +}; + class MCheckReturn : public MBinaryInstruction, public BoxInputsPolicy::Data diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index bb2ab8190..fddc1e637 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -272,6 +272,7 @@ namespace jit { _(IsCallable) \ _(IsObject) \ _(HasClass) \ + _(GuardToClass) \ _(CopySign) \ _(Rotate) \ _(NewDerivedTypedObject) \ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 9dcb527c5..f4adcc63c 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -7867,6 +7867,29 @@ class LHasClass : public LInstructionHelper<1, 1, 0> } }; +class LGuardToClass : public LInstructionHelper<1, 1, 1> +{ + public: + LIR_HEADER(GuardToClass); + explicit LGuardToClass(const LAllocation& lhs, const LDefinition& temp) + { + setOperand(0, lhs); + setTemp(0, temp); + } + + const LAllocation* lhs() { + return getOperand(0); + } + + const LDefinition* temp() { + return getTemp(0); + } + + MGuardToClass* mir() const { + return mir_->toGuardToClass(); + } +}; + template class LWasmSelectBase : public LInstructionHelper { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 3eea1b449..fe2ab5ea3 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -386,6 +386,7 @@ _(IsObject) \ _(IsObjectAndBranch) \ _(HasClass) \ + _(GuardToClass) \ _(RecompileCheck) \ _(MemoryBarrier) \ _(AssertRangeI) \ diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 653807ce8..08670c833 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -189,6 +189,22 @@ intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp) return true; } +template +static bool +intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + if (args[0].toObject().is()) { + args.rval().setObject(args[0].toObject()); + return true; + } + args.rval().setNull(); + return true; +} + /** * Self-hosting intrinsic returning the original constructor for a builtin * the name of which is the first and only argument. @@ -2297,18 +2313,18 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0), - JS_INLINABLE_FN("IsArrayIterator", - intrinsic_IsInstanceOfBuiltin, 1,0, - IntrinsicIsArrayIterator), - JS_INLINABLE_FN("IsMapIterator", - intrinsic_IsInstanceOfBuiltin, 1,0, - IntrinsicIsMapIterator), - JS_INLINABLE_FN("IsSetIterator", - intrinsic_IsInstanceOfBuiltin, 1,0, - IntrinsicIsSetIterator), - JS_INLINABLE_FN("IsStringIterator", - intrinsic_IsInstanceOfBuiltin, 1,0, - IntrinsicIsStringIterator), + JS_INLINABLE_FN("GuardToArrayIterator", + intrinsic_GuardToBuiltin, 1,0, + IntrinsicGuardToArrayIterator), + JS_INLINABLE_FN("GuardToMapIterator", + intrinsic_GuardToBuiltin, 1,0, + IntrinsicGuardToMapIterator), + JS_INLINABLE_FN("GuardToSetIterator", + intrinsic_GuardToBuiltin, 1,0, + IntrinsicGuardToSetIterator), + JS_INLINABLE_FN("GuardToStringIterator", + intrinsic_GuardToBuiltin, 1,0, + IntrinsicGuardToStringIterator), JS_INLINABLE_FN("IsListIterator", intrinsic_IsInstanceOfBuiltin, 1,0, IntrinsicIsListIterator), @@ -2412,7 +2428,12 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("CallStarGeneratorMethodIfWrapped", CallNonGenericSelfhostedMethod>, 2, 0), + JS_INLINABLE_FN("GuardToMapObject", intrinsic_GuardToBuiltin, 1, 0, + IntrinsicGuardToMapObject), JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin, 1,0), + + JS_INLINABLE_FN("GuardToSetObject", intrinsic_GuardToBuiltin, 1, 0, + IntrinsicGuardToSetObject), JS_FN("CallWeakSetMethodIfWrapped", CallNonGenericSelfhostedMethod>, 2, 0), -- cgit v1.2.3 From 0e550f2fb90ada0b608bc1e1982b100291651806 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 2 May 2018 11:07:35 -0700 Subject: Refactor structured clone JSAPI to prevent mismatched scopes. Roll-up of bugs 1442722, 1455071, 1433642, 1456604 and 1458320. --- js/public/StructuredClone.h | 207 +++++++++-- js/src/builtin/TestingFunctions.cpp | 30 +- js/src/tests/js1_8_5/extensions/clone-errors.js | 1 + .../js1_8_5/extensions/clone-transferables.js | 12 +- js/src/vm/StructuredClone.cpp | 389 ++++++++++----------- 5 files changed, 385 insertions(+), 254 deletions(-) (limited to 'js') diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index c48975cb9..ebff84387 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -9,6 +9,7 @@ #include "mozilla/Attributes.h" #include "mozilla/BufferList.h" +#include "mozilla/Move.h" #include @@ -29,7 +30,35 @@ namespace JS { enum class StructuredCloneScope : uint32_t { SameProcessSameThread, SameProcessDifferentThread, - DifferentProcess + + /** + * When writing, this means we're writing for an audience in a different + * process. Produce serialized data that can be sent to other processes, + * bitwise copied, or even stored as bytes in a database and read by later + * versions of Firefox years from now. The HTML5 spec refers to this as + * "ForStorage" as in StructuredSerializeForStorage, though we use + * DifferentProcess for IPC as well as storage. + * + * Transferable objects are limited to ArrayBuffers, whose contents are + * copied into the serialized data (rather than just writing a pointer). + */ + DifferentProcess, + + /** + * Handle a backwards-compatibility case with IndexedDB (bug 1434308): when + * reading, this means to treat legacy SameProcessSameThread data as if it + * were DifferentProcess. + * + * Do not use this for writing; use DifferentProcess instead. + */ + DifferentProcessForIndexedDB, + + /** + * Existing code wants to be able to create an uninitialized + * JSStructuredCloneData without knowing the scope, then populate it with + * data (at which point the scope *is* known.) + */ + Unassigned }; enum TransferableOwnership { @@ -89,6 +118,10 @@ class CloneDataPolicy } /* namespace JS */ +namespace js { +template struct BufferIterator; +} + /** * Read structured data from the reader r. This hook is used to read a value * previously serialized by a call to the WriteStructuredCloneOp hook. @@ -188,49 +221,152 @@ enum OwnTransferablePolicy { NoTransferables }; -class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) : - public mozilla::BufferList -{ - typedef js::SystemAllocPolicy AllocPolicy; - typedef mozilla::BufferList BufferList; +/** + * JSStructuredCloneData represents structured clone data together with the + * information needed to read/write/transfer/free the records within it, in the + * form of a set of callbacks. + */ +class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) { + public: + using BufferList = mozilla::BufferList; + using Iterator = BufferList::IterImpl; - static const size_t kInitialSize = 0; - static const size_t kInitialCapacity = 4096; + private: static const size_t kStandardCapacity = 4096; + BufferList bufList_; + + // The (address space, thread) scope within which this clone is valid. Note + // that this must be either set during construction, or start out as + // Unassigned and transition once to something else. + JS::StructuredCloneScope scope_; + const JSStructuredCloneCallbacks* callbacks_; void* closure_; OwnTransferablePolicy ownTransferables_; - void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks, - void* closure, - OwnTransferablePolicy policy) { - callbacks_ = callbacks; - closure_ = closure; - ownTransferables_ = policy; - } - friend struct JSStructuredCloneWriter; friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer); + template friend struct js::BufferIterator; -public: - explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy()) - : BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP) + public: + // The constructor must be infallible but SystemAllocPolicy is not, so both + // the initial size and initial capacity of the BufferList must be zero. + explicit JSStructuredCloneData(JS::StructuredCloneScope aScope) + : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy()) + , scope_(aScope) , callbacks_(nullptr) , closure_(nullptr) , ownTransferables_(OwnTransferablePolicy::NoTransferables) {} - MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers) - : BufferList(Move(buffers)) + + // Steal the raw data from a BufferList. In this case, we don't know the + // scope and none of the callback info is assigned yet. + JSStructuredCloneData(BufferList&& buffers, JS::StructuredCloneScope aScope) + : bufList_(mozilla::Move(buffers)) + , scope_(aScope) , callbacks_(nullptr) , closure_(nullptr) , ownTransferables_(OwnTransferablePolicy::NoTransferables) {} + MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers) + : JSStructuredCloneData(mozilla::Move(buffers), JS::StructuredCloneScope::Unassigned) + {} JSStructuredCloneData(JSStructuredCloneData&& other) = default; JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default; - ~JSStructuredCloneData(); + ~JSStructuredCloneData() { discardTransferables(); } + + void setCallbacks(const JSStructuredCloneCallbacks* callbacks, + void* closure, + OwnTransferablePolicy policy) + { + callbacks_ = callbacks; + closure_ = closure; + ownTransferables_ = policy; + } + + JS::StructuredCloneScope scope() const { return scope_; } + + void initScope(JS::StructuredCloneScope aScope) { + MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData"); + if (scope_ != JS::StructuredCloneScope::Unassigned) + MOZ_ASSERT(scope_ == aScope, "Cannot change scope after it has been initialized"); + scope_ = aScope; + } + + size_t Size() const { return bufList_.Size(); } + + const Iterator Start() const { return bufList_.Iter(); } + + bool Advance(Iterator& iter, size_t distance) const { + return iter.AdvanceAcrossSegments(bufList_, distance); + } + + bool ReadBytes(Iterator& iter, char* buffer, size_t size) const { + return bufList_.ReadBytes(iter, buffer, size); + } + + // Append new data to the end of the buffer. + bool AppendBytes(const char* data, size_t size) { + MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned); + return bufList_.WriteBytes(data, size); + } - using BufferList::BufferList; + // Update data stored within the existing buffer. There must be at least + // 'size' bytes between the position of 'iter' and the end of the buffer. + bool UpdateBytes(Iterator& iter, const char* data, size_t size) const { + MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned); + while (size > 0) { + size_t remaining = iter.RemainingInSegment(); + size_t nbytes = std::min(remaining, size); + memcpy(iter.Data(), data, nbytes); + data += nbytes; + size -= nbytes; + iter.Advance(bufList_, nbytes); + } + return true; + } + + void Clear() { + discardTransferables(); + bufList_.Clear(); + } + + // Return a new read-only JSStructuredCloneData that "borrows" the contents + // of |this|. Its lifetime should not exceed the donor's. This is only + // allowed for DifferentProcess clones, so finalization of the borrowing + // clone will do nothing. + JSStructuredCloneData Borrow(Iterator& iter, size_t size, bool* success) const + { + MOZ_ASSERT(scope_ == JS::StructuredCloneScope::DifferentProcess); + return JSStructuredCloneData(bufList_.Borrow(iter, size, success), + scope_); + } + + // Iterate over all contained data, one BufferList segment's worth at a + // time, and invoke the given FunctionToApply with the data pointer and + // size. The function should return a bool value, and this loop will exit + // with false if the function ever returns false. + template + bool ForEachDataChunk(FunctionToApply&& function) const { + Iterator iter = bufList_.Iter(); + while (!iter.Done()) { + if (!function(iter.Data(), iter.RemainingInSegment())) + return false; + iter.Advance(bufList_, iter.RemainingInSegment()); + } + return true; + } + + // Append the entire contents of other's bufList_ to our own. + bool Append(const JSStructuredCloneData& other) { + MOZ_ASSERT(scope_ == other.scope_); + return other.ForEachDataChunk([&](const char* data, size_t size) { + return AppendBytes(data, size); + }); + } + + void discardTransferables(); }; /** Note: if the *data contains transferable objects, it can be read only once. */ @@ -254,18 +390,29 @@ JS_PUBLIC_API(bool) JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); -/** RAII sugar for JS_WriteStructuredClone. */ +/** + * The C-style API calls to read and write structured clones are fragile -- + * they rely on the caller to properly handle ownership of the clone data, and + * the handling of the input data as well as the interpretation of the contents + * of the clone buffer are dependent on the callbacks passed in. If you + * serialize and deserialize with different callbacks, the results are + * questionable. + * + * JSAutoStructuredCloneBuffer wraps things up in an RAII class for data + * management, and uses the same callbacks for both writing and reading + * (serializing and deserializing). + */ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { const JS::StructuredCloneScope scope_; JSStructuredCloneData data_; uint32_t version_; public: - JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope, + JSAutoStructuredCloneBuffer(JS::StructuredCloneScope aScope, const JSStructuredCloneCallbacks* callbacks, void* closure) - : scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION) + : scope_(aScope), data_(aScope), version_(JS_STRUCTURED_CLONE_VERSION) { - data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); + data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); } JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other); @@ -276,11 +423,9 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { JSStructuredCloneData& data() { return data_; } bool empty() const { return !data_.Size(); } - void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); + void clear(); - /** Copy some memory. It will be automatically freed by the destructor. */ - bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION, - const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); + JS::StructuredCloneScope scope() const { return scope_; } /** * Adopt some memory. It will be automatically freed by the destructor. diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 00637a7a5..373b6c9ed 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2088,7 +2088,7 @@ class CloneBufferObject : public NativeObject { Rooted obj(cx, Create(cx)); if (!obj) return nullptr; - auto data = js::MakeUnique(); + auto data = js::MakeUnique(buffer->scope()); if (!data) { ReportOutOfMemory(cx); return nullptr; @@ -2141,8 +2141,11 @@ class CloneBufferObject : public NativeObject { return false; size_t nbytes = JS_GetStringLength(args[0].toString()); MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0); - auto buf = js::MakeUnique(nbytes, nbytes, nbytes); - js_memcpy(buf->Start(), str, nbytes); + auto buf = js::MakeUnique(JS::StructuredCloneScope::DifferentProcess); + if (!buf->AppendBytes(str, nbytes)) { + ReportOutOfMemory(cx); + return false; + } JS_free(cx, str); obj->setData(buf.release()); @@ -2186,7 +2189,7 @@ class CloneBufferObject : public NativeObject { ReportOutOfMemory(cx); return false; } - auto iter = obj->data()->Iter(); + auto iter = obj->data()->Start(); obj->data()->ReadBytes(iter, buffer.get(), size); JSString* str = JS_NewStringCopyN(cx, buffer.get(), size); if (!str) @@ -2244,6 +2247,8 @@ ParseCloneScope(JSContext* cx, HandleString str) scope.emplace(JS::StructuredCloneScope::SameProcessDifferentThread); else if (strcmp(scopeStr.ptr(), "DifferentProcess") == 0) scope.emplace(JS::StructuredCloneScope::DifferentProcess); + else if (strcmp(scopeStr.ptr(), "DifferentProcessForIndexedDB") == 0) + scope.emplace(JS::StructuredCloneScope::DifferentProcessForIndexedDB); return scope; } @@ -4370,19 +4375,22 @@ JS_FN_HELP("rejectPromise", RejectPromise, 2, 0, " clone buffer object. 'policy' may be an options hash. Valid keys:\n" " 'SharedArrayBuffer' - either 'allow' (the default) or 'deny'\n" " to specify whether SharedArrayBuffers may be serialized.\n" -"\n" -" 'scope' - SameProcessSameThread, SameProcessDifferentThread, or\n" -" DifferentProcess. Determines how some values will be serialized.\n" -" Clone buffers may only be deserialized with a compatible scope."), +" 'scope' - SameProcessSameThread, SameProcessDifferentThread,\n" +" DifferentProcess, or DifferentProcessForIndexedDB. Determines how some\n" +" values will be serialized. Clone buffers may only be deserialized with a\n" +" compatible scope. NOTE - For DifferentProcess/DifferentProcessForIndexedDB,\n" +" must also set SharedArrayBuffer:'deny' if data contains any shared memory\n" +" object."), JS_FN_HELP("deserialize", Deserialize, 1, 0, "deserialize(clonebuffer[, opts])", " Deserialize data generated by serialize. 'opts' is an options hash with one\n" " recognized key 'scope', which limits the clone buffers that are considered\n" " valid. Allowed values: 'SameProcessSameThread', 'SameProcessDifferentThread',\n" -" and 'DifferentProcess'. So for example, a DifferentProcess clone buffer\n" -" may be deserialized in any scope, but a SameProcessSameThread clone buffer\n" -" cannot be deserialized in a DifferentProcess scope."), +" 'DifferentProcess', and 'DifferentProcessForIndexedDB'. So for example, a\n" +" DifferentProcessForIndexedDB clone buffer may be deserialized in any scope, but\n" +" a SameProcessSameThread clone buffer cannot be deserialized in a\n" +" DifferentProcess scope."), JS_FN_HELP("detachArrayBuffer", DetachArrayBuffer, 1, 0, "detachArrayBuffer(buffer)", diff --git a/js/src/tests/js1_8_5/extensions/clone-errors.js b/js/src/tests/js1_8_5/extensions/clone-errors.js index f65578a06..d2ccea2e8 100644 --- a/js/src/tests/js1_8_5/extensions/clone-errors.js +++ b/js/src/tests/js1_8_5/extensions/clone-errors.js @@ -25,6 +25,7 @@ check({get x() { throw new Error("fail"); }}); // Mismatched scopes. for (let [write_scope, read_scope] of [['SameProcessSameThread', 'SameProcessDifferentThread'], ['SameProcessSameThread', 'DifferentProcess'], + ['SameProcessDifferentThread', 'DifferentProcessForIndexedDB'], ['SameProcessDifferentThread', 'DifferentProcess']]) { var ab = new ArrayBuffer(12); diff --git a/js/src/tests/js1_8_5/extensions/clone-transferables.js b/js/src/tests/js1_8_5/extensions/clone-transferables.js index 673684b95..9aad27208 100644 --- a/js/src/tests/js1_8_5/extensions/clone-transferables.js +++ b/js/src/tests/js1_8_5/extensions/clone-transferables.js @@ -3,11 +3,15 @@ // http://creativecommons.org/licenses/publicdomain/ function* buffer_options() { - for (var scope of ["SameProcessSameThread", "SameProcessDifferentThread", "DifferentProcess"]) { - for (var size of [0, 8, 16, 200, 1000, 4096, 8192, 65536]) { - yield { scope, size }; + for (var scope of ["SameProcessSameThread", + "SameProcessDifferentThread", + "DifferentProcess", + "DifferentProcessForIndexedDB"]) + { + for (var size of [0, 8, 16, 200, 1000, 4096, 8192, 65536]) { + yield { scope, size }; + } } - } } diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 3a062c3b8..42e909000 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -160,16 +160,16 @@ template struct BufferIterator { typedef mozilla::BufferList BufferList; - explicit BufferIterator(BufferList& buffer) + explicit BufferIterator(const BufferList& buffer) : mBuffer(buffer) , mIter(buffer.Iter()) { JS_STATIC_ASSERT(8 % sizeof(T) == 0); } - BufferIterator(const BufferIterator& other) - : mBuffer(other.mBuffer) - , mIter(other.mIter) + explicit BufferIterator(const JSStructuredCloneData& data) + : mBuffer(data.bufList_) + , mIter(data.Start()) { } @@ -228,17 +228,26 @@ struct BufferIterator { return mIter.HasRoomFor(sizeof(T)); } - BufferList& mBuffer; + const BufferList& mBuffer; typename BufferList::IterImpl mIter; }; +// SCOutput provides an interface to write raw data -- eg uint64_ts, doubles, +// arrays of bytes -- into a structured clone data output stream. It also knows +// how to free any transferable data within that stream. +// +// Note that it contains a full JSStructuredCloneData object, which holds the +// callbacks necessary to read/write/transfer/free the data. For the purpose of +// this class, only the freeTransfer callback is relevant; the rest of the callbacks +// are used by the higher-level JSStructuredCloneWriter interface. struct SCOutput { public: - using Iter = BufferIterator; + using Iter = BufferIterator; - explicit SCOutput(JSContext* cx); + SCOutput(JSContext* cx, JS::StructuredCloneScope scope); JSContext* context() const { return cx; } + JS::StructuredCloneScope scope() const { return buf.scope(); } bool write(uint64_t u); bool writePair(uint32_t tag, uint32_t data); @@ -251,22 +260,25 @@ struct SCOutput { template bool writeArray(const T* p, size_t nbytes); - bool extractBuffer(JSStructuredCloneData* data); - void discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure); + void setCallbacks(const JSStructuredCloneCallbacks* callbacks, + void* closure, + OwnTransferablePolicy policy) + { + buf.setCallbacks(callbacks, closure, policy); + } + void extractBuffer(JSStructuredCloneData* data) { *data = Move(buf); } + void discardTransferables(); uint64_t tell() const { return buf.Size(); } uint64_t count() const { return buf.Size() / sizeof(uint64_t); } - Iter iter() { - return BufferIterator(buf); - } + Iter iter() { return Iter(buf); } size_t offset(Iter dest) { return dest - iter(); } - private: JSContext* cx; - mozilla::BufferList buf; + JSStructuredCloneData buf; }; class SCInput { @@ -356,13 +368,6 @@ struct JSStructuredCloneReader { // be valid cross-process.) JS::StructuredCloneScope allowedScope; - // The scope the buffer was generated for (what sort of buffer it is.) The - // scope is not just a permissions thing; it also affects the storage - // format (eg a Transferred ArrayBuffer can be stored as a pointer for - // SameProcessSameThread but must have its contents in the clone buffer for - // DifferentProcess.) - JS::StructuredCloneScope storedScope; - // Stack of objects with properties remaining to be read. AutoValueVector objs; @@ -386,13 +391,15 @@ struct JSStructuredCloneWriter { const JSStructuredCloneCallbacks* cb, void* cbClosure, const Value& tVal) - : out(cx), scope(scope), objs(out.context()), + : out(cx, scope), objs(out.context()), counts(out.context()), entries(out.context()), - memory(out.context()), callbacks(cb), - closure(cbClosure), transferable(out.context(), tVal), + memory(out.context()), + transferable(out.context(), tVal), transferableObjects(out.context(), GCHashSet(cx)), cloneDataPolicy(cloneDataPolicy) - {} + { + out.setCallbacks(cb, cbClosure, OwnTransferablePolicy::NoTransferables); + } ~JSStructuredCloneWriter(); @@ -408,17 +415,10 @@ struct JSStructuredCloneWriter { SCOutput& output() { return out; } - bool extractBuffer(JSStructuredCloneData* data) { - bool success = out.extractBuffer(data); - if (success) { - data->setOptionalCallbacks(callbacks, closure, - OwnTransferablePolicy::OwnsTransferablesIfAny); - } - return success; + void extractBuffer(JSStructuredCloneData* newData) { + out.extractBuffer(newData); } - JS::StructuredCloneScope cloneScope() const { return scope; } - private: JSStructuredCloneWriter() = delete; JSStructuredCloneWriter(const JSStructuredCloneWriter&) = delete; @@ -449,9 +449,6 @@ struct JSStructuredCloneWriter { SCOutput out; - // The (address space, thread) scope within which this clone is valid. - JS::StructuredCloneScope scope; - // Vector of objects with properties remaining to be written. // // NB: These can span multiple compartments, so the compartment must be @@ -477,12 +474,6 @@ struct JSStructuredCloneWriter { SystemAllocPolicy>; Rooted memory; - // The user defined callbacks that will be used for cloning. - const JSStructuredCloneCallbacks* callbacks; - - // Any value passed to JS_WriteStructuredClone. - void* closure; - // Set of transferable objects RootedValue transferable; Rooted> transferableObjects; @@ -542,7 +533,12 @@ WriteStructuredClone(JSContext* cx, HandleValue v, JSStructuredCloneData* bufp, const Value& transferable) { JSStructuredCloneWriter w(cx, scope, cloneDataPolicy, cb, cbClosure, transferable); - return w.init() && w.write(v) && w.extractBuffer(bufp); + if (!w.init()) + return false; + if (!w.write(v)) + return false; + w.extractBuffer(bufp); + return true; } bool @@ -555,91 +551,15 @@ ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, return r.read(vp); } -// If the given buffer contains Transferables, free them. Note that custom -// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to -// delete their transferables. -template -static void -DiscardTransferables(mozilla::BufferList& buffer, - const JSStructuredCloneCallbacks* cb, void* cbClosure) -{ - auto point = BufferIterator(buffer); - if (point.done()) - return; // Empty buffer - - uint32_t tag, data; - MOZ_RELEASE_ASSERT(point.canPeek()); - SCInput::getPair(point.peek(), &tag, &data); - point.next(); - - if (tag == SCTAG_HEADER) { - if (point.done()) - return; - - MOZ_RELEASE_ASSERT(point.canPeek()); - SCInput::getPair(point.peek(), &tag, &data); - point.next(); - } - - if (tag != SCTAG_TRANSFER_MAP_HEADER) - return; - - if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED) - return; - - // freeTransfer should not GC - JS::AutoSuppressGCAnalysis nogc; - - if (point.done()) - return; - - uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek()); - point.next(); - while (numTransferables--) { - if (!point.canPeek()) - return; - - uint32_t ownership; - SCInput::getPair(point.peek(), &tag, &ownership); - point.next(); - MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY); - if (!point.canPeek()) - return; - - void* content; - SCInput::getPtr(point.peek(), &content); - point.next(); - if (!point.canPeek()) - return; - - uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek()); - point.next(); - - if (ownership < JS::SCTAG_TMO_FIRST_OWNED) - continue; - - if (ownership == JS::SCTAG_TMO_ALLOC_DATA) { - js_free(content); - } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) { - JS_ReleaseMappedArrayBufferContents(content, extraData); - } else if (cb && cb->freeTransfer) { - cb->freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, cbClosure); - } else { - MOZ_ASSERT(false, "unknown ownership"); - } - } -} - static bool StructuredCloneHasTransferObjects(const JSStructuredCloneData& data) { - auto iter = data.Iter(); - if (data.Size() < sizeof(uint64_t)) return false; uint64_t u; - data.ReadBytes(iter, reinterpret_cast(&u), sizeof(u)); + BufferIterator iter(data); + MOZ_ALWAYS_TRUE(iter.readBytes(reinterpret_cast(&u), sizeof(u))); uint32_t tag = uint32_t(u >> 32); return (tag == SCTAG_TRANSFER_MAP_HEADER); } @@ -650,7 +570,7 @@ SCInput::SCInput(JSContext* cx, JSStructuredCloneData& data) : cx(cx), point(data) { - static_assert(JSStructuredCloneData::kSegmentAlignment % 8 == 0, + static_assert(JSStructuredCloneData::BufferList::kSegmentAlignment % 8 == 0, "structured clone buffer reads should be aligned"); MOZ_ASSERT(data.Size() % 8 == 0); } @@ -812,9 +732,8 @@ SCInput::readPtr(void** p) return true; } -SCOutput::SCOutput(JSContext* cx) - : cx(cx) - , buf(0, 0, 4096, cx) +SCOutput::SCOutput(JSContext* cx, JS::StructuredCloneScope scope) + : cx(cx), buf(scope) { } @@ -822,7 +741,11 @@ bool SCOutput::write(uint64_t u) { uint64_t v = NativeEndian::swapToLittleEndian(u); - return buf.WriteBytes(reinterpret_cast(&v), sizeof(u)); + if (!buf.AppendBytes(reinterpret_cast(&v), sizeof(u))) { + ReportOutOfMemory(context()); + return false; + } + return true; } bool @@ -883,7 +806,7 @@ SCOutput::writeArray(const T* p, size_t nelems) for (size_t i = 0; i < nelems; i++) { T value = swapToLittleEndian(p[i]); - if (!buf.WriteBytes(reinterpret_cast(&value), sizeof(value))) + if (!buf.AppendBytes(reinterpret_cast(&value), sizeof(value))) return false; } @@ -892,7 +815,7 @@ SCOutput::writeArray(const T* p, size_t nelems) size_t padbytes = sizeof(uint64_t) * nwords - sizeof(T) * nelems; char zero = 0; for (size_t i = 0; i < padbytes; i++) { - if (!buf.WriteBytes(&zero, sizeof(zero))) + if (!buf.AppendBytes(&zero, sizeof(zero))) return false; } @@ -927,34 +850,101 @@ SCOutput::writePtr(const void* p) return write(reinterpret_cast(p)); } -bool -SCOutput::extractBuffer(JSStructuredCloneData* data) -{ - bool success; - mozilla::BufferList out = - buf.MoveFallible(&success); - if (!success) { - ReportOutOfMemory(cx); - return false; - } - *data = JSStructuredCloneData(Move(out)); - return true; -} - void -SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure) +SCOutput::discardTransferables() { - DiscardTransferables(buf, cb, cbClosure); + buf.discardTransferables(); } } /* namespace js */ -JSStructuredCloneData::~JSStructuredCloneData() + +// If the buffer contains Transferables, free them. Note that custom +// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to +// delete their transferables. +void +JSStructuredCloneData::discardTransferables() { if (!Size()) return; - if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny) - DiscardTransferables(*this, callbacks_, closure_); + + if (ownTransferables_ != OwnTransferablePolicy::OwnsTransferablesIfAny) + return; + + // DifferentProcess clones cannot contain pointers, so nothing needs to be + // released. + if (scope_ == JS::StructuredCloneScope::DifferentProcess) + return; + + FreeTransferStructuredCloneOp freeTransfer = nullptr; + if (callbacks_) + freeTransfer = callbacks_->freeTransfer; + + auto point = BufferIterator(*this); + if (point.done()) + return; // Empty buffer + + uint32_t tag, data; + MOZ_RELEASE_ASSERT(point.canPeek()); + SCInput::getPair(point.peek(), &tag, &data); + point.next(); + + if (tag == SCTAG_HEADER) { + if (point.done()) + return; + + MOZ_RELEASE_ASSERT(point.canPeek()); + SCInput::getPair(point.peek(), &tag, &data); + point.next(); + } + + if (tag != SCTAG_TRANSFER_MAP_HEADER) + return; + + if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED) + return; + + // freeTransfer should not GC + JS::AutoSuppressGCAnalysis nogc; + + if (point.done()) + return; + + uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek()); + point.next(); + while (numTransferables--) { + if (!point.canPeek()) + return; + + uint32_t ownership; + SCInput::getPair(point.peek(), &tag, &ownership); + point.next(); + MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY); + if (!point.canPeek()) + return; + + void* content; + SCInput::getPtr(point.peek(), &content); + point.next(); + if (!point.canPeek()) + return; + + uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek()); + point.next(); + + if (ownership < JS::SCTAG_TMO_FIRST_OWNED) + continue; + + if (ownership == JS::SCTAG_TMO_ALLOC_DATA) { + js_free(content); + } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) { + JS_ReleaseMappedArrayBufferContents(content, extraData); + } else if (freeTransfer) { + freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, closure_); + } else { + MOZ_ASSERT(false, "unknown ownership"); + } + } } JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX); @@ -962,9 +952,8 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX); JSStructuredCloneWriter::~JSStructuredCloneWriter() { // Free any transferable data left lying around in the buffer - if (out.count()) { - out.discardTransferables(callbacks, closure); - } + if (out.count()) + out.discardTransferables(); } bool @@ -1038,7 +1027,7 @@ JSStructuredCloneWriter::parseTransferable() bool JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId) { - ReportDataCloneError(context(), callbacks, errorId); + ReportDataCloneError(context(), out.buf.callbacks_, errorId); return false; } @@ -1454,8 +1443,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v) return traverseSavedFrame(obj); } - if (callbacks && callbacks->write) - return callbacks->write(context(), this, obj, closure); + if (out.buf.callbacks_ && out.buf.callbacks_->write) + return out.buf.callbacks_->write(context(), this, obj, out.buf.closure_); /* else fall through */ } @@ -1465,7 +1454,7 @@ JSStructuredCloneWriter::startWrite(HandleValue v) bool JSStructuredCloneWriter::writeHeader() { - return out.writePair(SCTAG_HEADER, (uint32_t)scope); + return out.writePair(SCTAG_HEADER, (uint32_t)output().scope()); } bool @@ -1523,6 +1512,7 @@ JSStructuredCloneWriter::transferOwnership() JSContext* cx = context(); RootedObject obj(cx); + JS::StructuredCloneScope scope = output().scope(); for (auto tr = transferableObjects.all(); !tr.empty(); tr.popFront()) { obj = tr.front(); @@ -1555,7 +1545,9 @@ JSStructuredCloneWriter::transferOwnership() return false; } - if (scope == JS::StructuredCloneScope::DifferentProcess) { + if (scope == JS::StructuredCloneScope::DifferentProcess || + scope == JS::StructuredCloneScope::DifferentProcessForIndexedDB) + { // Write Transferred ArrayBuffers in DifferentProcess scope at // the end of the clone buffer, and store the offset within the // buffer to where the ArrayBuffer was written. Note that this @@ -1592,9 +1584,9 @@ JSStructuredCloneWriter::transferOwnership() extraData = nbytes; } } else { - if (!callbacks || !callbacks->writeTransfer) + if (!out.buf.callbacks_ || !out.buf.callbacks_->writeTransfer) return reportDataCloneError(JS_SCERR_TRANSFERABLE); - if (!callbacks->writeTransfer(cx, obj, closure, &tag, &ownership, &content, &extraData)) + if (!out.buf.callbacks_->writeTransfer(cx, obj, out.buf.closure_, &tag, &ownership, &content, &extraData)) return false; MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY); } @@ -2187,25 +2179,33 @@ JSStructuredCloneReader::readHeader() if (!in.getPair(&tag, &data)) return in.reportTruncated(); - if (tag != SCTAG_HEADER) { + JS::StructuredCloneScope storedScope; + if (tag == SCTAG_HEADER) { + MOZ_ALWAYS_TRUE(in.readPair(&tag, &data)); + storedScope = JS::StructuredCloneScope(data); + } else { // Old structured clone buffer. We must have read it from disk. - storedScope = JS::StructuredCloneScope::DifferentProcess; - return true; + storedScope = JS::StructuredCloneScope::DifferentProcessForIndexedDB; } - MOZ_ALWAYS_TRUE(in.readPair(&tag, &data)); - storedScope = JS::StructuredCloneScope(data); - - if (data != uint32_t(JS::StructuredCloneScope::SameProcessSameThread) && - data != uint32_t(JS::StructuredCloneScope::SameProcessDifferentThread) && - data != uint32_t(JS::StructuredCloneScope::DifferentProcess)) + if (storedScope < JS::StructuredCloneScope::SameProcessSameThread || + storedScope > JS::StructuredCloneScope::DifferentProcessForIndexedDB) { JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid structured clone scope"); return false; } + + if (allowedScope == JS::StructuredCloneScope::DifferentProcessForIndexedDB) { + // Bug 1434308 and bug 1458320 - the scopes stored in old IndexedDB + // clones are incorrect. Treat them as if they were DifferentProcess. + allowedScope = JS::StructuredCloneScope::DifferentProcess; + return true; + } + if (storedScope < allowedScope) { - JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA, + JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, + JSMSG_SC_BAD_SERIALIZED_DATA, "incompatible structured clone scope"); return false; } @@ -2249,10 +2249,14 @@ JSStructuredCloneReader::readTransferMap() return false; if (tag == SCTAG_TRANSFER_MAP_ARRAY_BUFFER) { - if (storedScope == JS::StructuredCloneScope::DifferentProcess) { + if (allowedScope == JS::StructuredCloneScope::DifferentProcess || + allowedScope == JS::StructuredCloneScope::DifferentProcessForIndexedDB) + { // Transferred ArrayBuffers in a DifferentProcess clone buffer - // are treated as if they weren't Transferred at all. - continue; + // are treated as if they weren't Transferred at all. We should + // only see SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER. + ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE); + return false; } size_t nbytes = extraData; @@ -2586,7 +2590,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp, } JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other) - : scope_(other.scope_) + : scope_(other.scope()), data_(other.scope()) { data_.ownTransferables_ = other.data_.ownTransferables_; other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_); @@ -2604,45 +2608,14 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other) } void -JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks, - void* optionalClosure) +JSAutoStructuredCloneBuffer::clear() { - if (!data_.Size()) - return; - - const JSStructuredCloneCallbacks* callbacks = - optionalCallbacks ? optionalCallbacks : data_.callbacks_; - void* closure = optionalClosure ? optionalClosure : data_.closure_; - - if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny) - DiscardTransferables(data_, callbacks, closure); + data_.discardTransferables(); data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables; data_.Clear(); version_ = 0; } -bool -JSAutoStructuredCloneBuffer::copy(const JSStructuredCloneData& srcData, uint32_t version, - const JSStructuredCloneCallbacks* callbacks, - void* closure) -{ - // transferable objects cannot be copied - if (StructuredCloneHasTransferObjects(srcData)) - return false; - - clear(); - - auto iter = srcData.Iter(); - while (!iter.Done()) { - data_.WriteBytes(iter.Data(), iter.RemainingInSegment()); - iter.Advance(srcData, iter.RemainingInSegment()); - } - - version_ = version; - data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); - return true; -} - void JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t version, const JSStructuredCloneCallbacks* callbacks, @@ -2651,7 +2624,7 @@ JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t versio clear(); data_ = Move(data); version_ = version; - data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny); + data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny); } void @@ -2668,7 +2641,7 @@ JSAutoStructuredCloneBuffer::steal(JSStructuredCloneData* data, uint32_t* versio *data = Move(data_); version_ = 0; - data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables); + data_.setCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables); } bool @@ -2782,5 +2755,5 @@ JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj) JS_PUBLIC_API(JS::StructuredCloneScope) JS_GetStructuredCloneScope(JSStructuredCloneWriter* w) { - return w->cloneScope(); + return w->output().scope(); } -- cgit v1.2.3 From 240f52db8e97c9c65592771ddffb6efbdd210c15 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 7 Jun 2018 13:21:06 +0200 Subject: Reinstate string.prototype.contains() This adds a compatibility function aliased to string.prototype.includes(). --- js/src/jsstr.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'js') diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 01b407626..4151d012b 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1534,7 +1534,7 @@ RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match) return true; } -/* ES6 draft rc4 21.1.3.7. */ +/* ES6 2015 ST 21.1.3.7 String.prototype.includes */ bool js::str_includes(JSContext* cx, unsigned argc, Value* vp) { @@ -1591,6 +1591,13 @@ js::str_includes(JSContext* cx, unsigned argc, Value* vp) return true; } +/* ES6 draft Date: Thu, 7 Jun 2018 15:41:21 +0200 Subject: Fix count of compacting update tasks started. --- js/src/jsgc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js') diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 45301dac8..fb10797d5 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2276,7 +2276,7 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s for (size_t i = 0; i < bgTaskCount && !bgArenas.done(); i++) { bgTasks[i].emplace(rt, &bgArenas, lock); startTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS, lock); - tasksStarted = i; + tasksStarted++; } } -- cgit v1.2.3 From c951c985c1738a951a0e851710cf6c355671afd1 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Thu, 10 May 2018 10:09:31 +0100 Subject: Bug 1465108 - Use function pointers rather than virtual run method for GC parallel tasks r=sfink a=abillings a=RyanVM --- js/src/gc/GCRuntime.h | 18 ++++++++-------- js/src/gc/Nursery.cpp | 8 +++---- js/src/gc/Statistics.h | 3 --- js/src/jsgc.cpp | 25 +++++++++++----------- js/src/jsgc.h | 51 ++++++++++++++++++++++++++++++++++++++------- js/src/vm/HelperThreads.cpp | 4 ++-- 6 files changed, 72 insertions(+), 37 deletions(-) (limited to 'js') diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 19737c9ee..5c2576efd 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -73,7 +73,7 @@ class ChunkPool // Performs extra allocation off the main thread so that when memory is // required on the main thread it will already be available and waiting. -class BackgroundAllocTask : public GCParallelTask +class BackgroundAllocTask : public GCParallelTaskHelper { // Guarded by the GC lock. JSRuntime* runtime; @@ -85,12 +85,11 @@ class BackgroundAllocTask : public GCParallelTask BackgroundAllocTask(JSRuntime* rt, ChunkPool& pool); bool enabled() const { return enabled_; } - protected: - void run() override; + void run(); }; -// Search the provided Chunks for free arenas and decommit them. -class BackgroundDecommitTask : public GCParallelTask +// Search the provided Chunks for free arenas and recommit them. +class BackgroundDecommitTask : public GCParallelTaskHelper { public: using ChunkVector = mozilla::Vector; @@ -98,8 +97,7 @@ class BackgroundDecommitTask : public GCParallelTask explicit BackgroundDecommitTask(JSRuntime *rt) : runtime(rt) {} void setChunksToScan(ChunkVector &chunks); - protected: - void run() override; + void run(); private: JSRuntime* runtime; @@ -1171,8 +1169,10 @@ class GCRuntime /* * Concurrent sweep infrastructure. */ - void startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked); - void joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked); + void startTask(GCParallelTask& task, gcstats::Phase phase, + AutoLockHelperThreadState& locked); + void joinTask(GCParallelTask& task, gcstats::Phase phase, + AutoLockHelperThreadState& locked); /* * List head of arenas allocated during the sweep phase. diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index aa50bf29e..55ca5a059 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -43,19 +43,19 @@ using mozilla::PodZero; static const uintptr_t CanaryMagicValue = 0xDEADB15D; -struct js::Nursery::FreeMallocedBuffersTask : public GCParallelTask +struct js::Nursery::FreeMallocedBuffersTask : public GCParallelTaskHelper { explicit FreeMallocedBuffersTask(FreeOp* fop) : fop_(fop) {} bool init() { return buffers_.init(); } void transferBuffersToFree(MallocedBuffersSet& buffersToFree, const AutoLockHelperThreadState& lock); - ~FreeMallocedBuffersTask() override { join(); } + ~FreeMallocedBuffersTask() { join(); } + + void run(); private: FreeOp* fop_; MallocedBuffersSet buffers_; - - virtual void run() override; }; struct js::Nursery::SweepAction diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index c9e5871e3..ca1969b2c 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -22,9 +22,6 @@ using mozilla::Maybe; namespace js { - -class GCParallelTask; - namespace gcstats { enum Phase : uint8_t { diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index fb10797d5..3d4dae9bb 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2156,7 +2156,7 @@ ArenasToUpdate::getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned maxL return { begin, last->next }; } -struct UpdatePointersTask : public GCParallelTask +struct UpdatePointersTask : public GCParallelTaskHelper { // Maximum number of arenas to update in one block. #ifdef DEBUG @@ -2172,14 +2172,13 @@ struct UpdatePointersTask : public GCParallelTask arenas_.end = nullptr; } - ~UpdatePointersTask() override { join(); } + void run(); private: JSRuntime* rt_; ArenasToUpdate* source_; ArenaListSegment arenas_; - virtual void run() override; bool getArenasToUpdate(); void updateArenas(); }; @@ -2985,7 +2984,6 @@ js::gc::BackgroundDecommitTask::run() AutoLockGC lock(runtime); for (Chunk* chunk : toDecommit) { - // The arena list is not doubly-linked, so we have to work in the free // list order and not in the natural order. while (chunk->info.numArenasFreeCommitted) { @@ -4359,7 +4357,8 @@ GCRuntime::endMarkingZoneGroup() marker.setMarkColorBlack(); } -class GCSweepTask : public GCParallelTask +template +class GCSweepTask : public GCParallelTaskHelper { GCSweepTask(const GCSweepTask&) = delete; @@ -4369,13 +4368,13 @@ class GCSweepTask : public GCParallelTask public: explicit GCSweepTask(JSRuntime* rt) : runtime(rt) {} GCSweepTask(GCSweepTask&& other) - : GCParallelTask(mozilla::Move(other)), + : GCParallelTaskHelper(mozilla::Move(other)), runtime(other.runtime) {} }; // Causes the given WeakCache to be swept when run. -class SweepWeakCacheTask : public GCSweepTask +class SweepWeakCacheTask : public GCSweepTask { JS::WeakCache& cache; @@ -4387,15 +4386,15 @@ class SweepWeakCacheTask : public GCSweepTask : GCSweepTask(mozilla::Move(other)), cache(other.cache) {} - void run() override { + void run() { cache.sweep(); } }; #define MAKE_GC_SWEEP_TASK(name) \ - class name : public GCSweepTask { \ - void run() override; \ + class name : public GCSweepTask { \ public: \ + void run(); \ explicit name (JSRuntime* rt) : GCSweepTask(rt) {} \ } MAKE_GC_SWEEP_TASK(SweepAtomsTask); @@ -4447,7 +4446,8 @@ SweepMiscTask::run() } void -GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked) +GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, + AutoLockHelperThreadState& locked) { if (!task.startWithLockHeld(locked)) { AutoUnlockHelperThreadState unlock(locked); @@ -4457,7 +4457,8 @@ GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperT } void -GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked) +GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase, + AutoLockHelperThreadState& locked) { gcstats::AutoPhase ap(stats, task, phase); task.joinWithLockHeld(locked); diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 7ad176d84..d3cf31fe7 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -12,6 +12,7 @@ #include "mozilla/Atomics.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/Move.h" #include "mozilla/TypeTraits.h" #include "js/GCAPI.h" @@ -936,10 +937,19 @@ class GCHelperState }; // A generic task used to dispatch work to the helper thread system. -// Users should derive from GCParallelTask add what data they need and -// override |run|. +// Users supply a function pointer to call. +// +// Note that we don't use virtual functions here because destructors can write +// the vtable pointer on entry, which can causes races if synchronization +// happens there. class GCParallelTask { + public: + using TaskFunc = void (*)(GCParallelTask*); + + private: + TaskFunc func_; + // The state of the parallel computation. enum TaskState { NotStarted, @@ -956,19 +966,24 @@ class GCParallelTask // A flag to signal a request for early completion of the off-thread task. mozilla::Atomic cancel_; - virtual void run() = 0; - public: - GCParallelTask() : state(NotStarted), duration_(0) {} + explicit GCParallelTask(TaskFunc func) + : func_(func), + state(NotStarted), + duration_(0), + cancel_(false) + {} + GCParallelTask(GCParallelTask&& other) - : state(other.state), + : func_(other.func_), + state(other.state), duration_(0), cancel_(false) {} // Derived classes must override this to ensure that join() gets called // before members get destructed. - virtual ~GCParallelTask(); + ~GCParallelTask(); // Time spent in the most recent invocation of this task. int64_t duration() const { return duration_; } @@ -997,12 +1012,34 @@ class GCParallelTask bool isRunningWithLockHeld(const AutoLockHelperThreadState& locked) const; bool isRunning() const; + void runTask() { + func_(this); + } + // This should be friended to HelperThread, but cannot be because it // would introduce several circular dependencies. public: void runFromHelperThread(AutoLockHelperThreadState& locked); }; +// CRTP template to handle cast to derived type when calling run(). +template +class GCParallelTaskHelper : public GCParallelTask +{ + public: + GCParallelTaskHelper() + : GCParallelTask(&runTaskTyped) + {} + GCParallelTaskHelper(GCParallelTaskHelper&& other) + : GCParallelTask(mozilla::Move(other)) + {} + + private: + static void runTaskTyped(GCParallelTask* task) { + static_cast(task)->run(); + } +}; + typedef void (*IterateChunkCallback)(JSRuntime* rt, void* data, gc::Chunk* chunk); typedef void (*IterateZoneCallback)(JSRuntime* rt, void* data, JS::Zone* zone); typedef void (*IterateArenaCallback)(JSRuntime* rt, void* data, gc::Arena* arena, diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 7381a97b5..bd29d0c79 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1144,7 +1144,7 @@ js::GCParallelTask::runFromMainThread(JSRuntime* rt) MOZ_ASSERT(state == NotStarted); MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(rt)); uint64_t timeStart = PRMJ_Now(); - run(); + runTask(); duration_ = PRMJ_Now() - timeStart; } @@ -1155,7 +1155,7 @@ js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked) AutoUnlockHelperThreadState parallelSection(locked); gc::AutoSetThreadIsPerformingGC performingGC; uint64_t timeStart = PRMJ_Now(); - run(); + runTask(); duration_ = PRMJ_Now() - timeStart; } -- cgit v1.2.3 From f3657d6b4d4b30574a43a886bed6945590bf1508 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Thu, 31 May 2018 14:22:14 +0200 Subject: Bug 1464829 - Ensure the recover instruction vector has the expected size. --- js/src/jit/JitFrameIterator.h | 2 -- js/src/jit/JitFrames.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'js') diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h index ba5efef6a..3620badbd 100644 --- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -322,9 +322,7 @@ class RInstructionResults MOZ_MUST_USE bool init(JSContext* cx, uint32_t numResults); bool isInitialized() const; -#ifdef DEBUG size_t length() const; -#endif JitFrameLayout* frame() const; diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index f11f17225..019be46dd 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -1688,13 +1688,11 @@ RInstructionResults::isInitialized() const return initialized_; } -#ifdef DEBUG size_t RInstructionResults::length() const { return results_->length(); } -#endif JitFrameLayout* RInstructionResults::frame() const @@ -2150,7 +2148,7 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback) } MOZ_ASSERT(results->isInitialized()); - MOZ_ASSERT(results->length() == recover_.numInstructions() - 1); + MOZ_RELEASE_ASSERT(results->length() == recover_.numInstructions() - 1); instructionResults_ = results; return true; } -- cgit v1.2.3 From 9ee07e9b8894de3aec81689dba5dbc0fc025bb83 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 2 Jul 2018 09:46:06 +0200 Subject: Issue #578: Applications cannot start without /proc (chroot). UXP uses the current stack frame address and the stack size as a sort of heuristic for various things in the JavaScript engine. The js::GetNativeStackBaseImpl() function is used to get the base stack address (i.e. the address from which the stack grows, so this can be either the first or last memory address of the stack memory space depending on the CPU architecture). On Linux, this function is implemented using the pthreads APIs. For non-main threads, the queried thread info is stored in memory. The main thread does not have this information on hand, so it gets the stack memory range via the /proc/self/maps file (see glibc's pthread_get_attr_np.c). Fortunately (per discussions with the firefox devs in #jsapi) the base address only needs to be approximate. In reality, environment variables, args, and other things are stored in stack space between the end/beginning of the mapped stack memory and the 'top' of the stack space used by stack frames. When using glibc, we can get the top of this usable stack from __libc_stack_end, which is a void* set by glibc during program initialization, avoiding the need to access /proc. Non-main threads still get their stack-base through the usual pthreads APIs. Other libc implementations like musl will fall back to the standard UNIX-like implementation which calls pthread's pthread_attr_getstack() also from the main thread, which may imply /proc access and not work in restricted environments. --- js/src/jsnativestack.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) (limited to 'js') diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp index 05928ea3d..166a5a4f7 100644 --- a/js/src/jsnativestack.cpp +++ b/js/src/jsnativestack.cpp @@ -21,6 +21,18 @@ # include # endif +# if defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__) +# include +# include +# include +# include +static pid_t +gettid() +{ + return syscall(__NR_gettid); +} +# endif + #else # error "Unsupported platform" @@ -88,6 +100,52 @@ js::GetNativeStackBaseImpl() context.uc_stack.ss_size; } +#elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__) +void* +js::GetNativeStackBaseImpl() +{ + // On the main thread, get stack base from glibc's __libc_stack_end rather than pthread APIs + // to avoid filesystem calls /proc/self/maps. Non-main threads spawned with pthreads can read + // this information directly from their pthread struct, but when using the pthreads API, the + // main thread must go parse /proc/self/maps to figure the mapped stack address space ranges. + // We want to avoid reading from /proc/ so that the application can run in restricted + // environments where /proc may not be mounted (e.g. chroot). + if (gettid() == getpid()) { + void** pLibcStackEnd = (void**)dlsym(RTLD_DEFAULT, "__libc_stack_end"); + + // If __libc_stack_end is not found, architecture specific frame pointer hopping will need + // to be implemented. + MOZ_RELEASE_ASSERT(pLibcStackEnd, "__libc_stack_end unavailable, unable to setup stack range for JS."); + void* stackBase = *pLibcStackEnd; + MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS."); + + // We don't need to fix stackBase, as it already roughly points to beginning of the stack. + return stackBase; + } + + // Non-main threads have the required info stored in memory, so no filesystem calls are made. + pthread_t thread = pthread_self(); + pthread_attr_t sattr; + pthread_attr_init(&sattr); + pthread_getattr_np(thread, &sattr); + + // stackBase will be the *lowest* address on all architectures. + void* stackBase = nullptr; + size_t stackSize = 0; + int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); + if (rc) { + MOZ_CRASH("Call to pthread_attr_getstack failed, unable to setup stack range for JS."); + } + MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS."); + pthread_attr_destroy(&sattr); + +# if JS_STACK_GROWTH_DIRECTION > 0 + return stackBase; +# else + return static_cast(stackBase) + stackSize; +# endif +} + #else /* XP_UNIX */ void* @@ -156,11 +214,15 @@ js::GetNativeStackBaseImpl() // the truth. rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); # else + // Use the default pthread_attr_getstack() call. Note that this function + // differs between libc implementations and could imply /proc access etc. + // which may not work in restricted environments. rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); # endif - if (rc) - MOZ_CRASH(); - MOZ_ASSERT(stackBase); + if (rc) { + MOZ_CRASH("Call to pthread_attr_getstack failed, unable to setup stack range for JS."); + } + MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS."); pthread_attr_destroy(&sattr); # if JS_STACK_GROWTH_DIRECTION > 0 -- cgit v1.2.3