author | André Bargull <andre.bargull@gmail.com> |
Fri, 11 Oct 2019 19:24:45 +0000 | |
changeset 497316 | 64993f76caaf72ed630c44da86250d06dda52ccd |
parent 497315 | 4eca32dbe70f9c1d7803c2cb51a266842b4e77ab |
child 497317 | 22ff988b77c6218bd6556702bb926898869b7ecb |
push id | 36682 |
push user | ncsoregi@mozilla.com |
push date | Sat, 12 Oct 2019 09:52:03 +0000 |
treeherder | mozilla-central@06ea2371f897 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jwalden |
bugs | 1570370 |
milestone | 71.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/builtin/intl/CommonFunctions.js +++ b/js/src/builtin/intl/CommonFunctions.js @@ -564,92 +564,16 @@ function parseLanguageTag(locale) { if (hasOwn(ts.localeLowercase, grandfatheredMappings)) updateGrandfatheredMappings(tagObj); // Return if the complete input was successfully parsed. return tagObj; } /** - * Returns the input normalized to lower case if it matches the - * 'unicode_language_subtag' production. Otherwise returns null. - */ -function parseStandaloneLanguage(language) { - // unicode_language_subtag = alpha{2,3} | alpha{5,8} ; - var length = language.length; - if (length < 2 || length === 4 || length > 8 || !IsASCIIAlphaString(language)) { - // Four character language subtags are not allowed in Unicode BCP 47 - // locale identifiers. Also see the comparison to Unicode CLDR locale - // identifiers in <https://unicode.org/reports/tr35/#BCP_47_Conformance>. - return null; - } - - return callFunction(std_String_toLowerCase, language); -} - -/** - * Returns the input normalized to title case if it matches the - * 'unicode_script_subtag' production. Otherwise returns null. - */ -function parseStandaloneScript(script) { - // unicode_script_subtag = alpha{4} ; - if (script.length !== 4 || !IsASCIIAlphaString(script)) { - return null; - } - - // The first character of a script code needs to be capitalized. - // "hans" -> "Hans" - return callFunction(std_String_toUpperCase, script[0]) + - callFunction(std_String_toLowerCase, Substring(script, 1, script.length - 1)); -} - -/** - * Returns the input normalized to upper case if it matches the - * 'unicode_region_subtag' production. Otherwise returns null. - */ -function parseStandaloneRegion(region) { - // unicode_region_subtag = (alpha{2} | digit{3}) ; - var length = region.length; - if ((length !== 2 || !IsASCIIAlphaString(region)) && - (length !== 3 || !IsASCIIDigitString(region))) - { - return null; - } - - // Region codes need to be in upper-case. "bu" -> "BU" - return callFunction(std_String_toUpperCase, region); -} - -/** - * Returns the input normalized to lower case if it can be parsed as a - * '(3*8alphanum) *("-" (3*8alphanum))' subtag sequence. Otherwise returns - * null. - */ -function parseStandaloneUnicodeExtensionType(type) { - // Reuse the BCP 47 parser for Unicode extension types. - var ts = new BCP47TokenStream(type); - NEXT_TOKEN_OR_RETURN_NULL(ts); - - // Unicode extension 'type' subtags must match the following ABNF. - // - // type = (3*8alphanum) *("-" (3*8alphanum)) - // alphanum = (ALPHA / DIGIT) ; letters and numbers - // ALPHA = %x41-5A / %x61-7A ; A-Z / a-z - // DIGIT = %x30-39 ; 0-9 - do { - if (ts.tokenLength < 3 || ts.tokenLength > 8) - return null; - - NEXT_TOKEN_OR_RETURN_NULL(ts); - } while (ts.token !== NONE); - - return ts.localeLowercase; -} - -/** * Return the locale and fields components of the given valid Transform * extension subtag. */ function TransformExtensionComponents(extension) { assert(typeof extension === "string", "extension is a String value"); assert(callFunction(std_String_startsWith, extension, "t-"), "extension starts with 't-'"); @@ -1232,30 +1156,16 @@ function IsASCIIAlphaString(s) { var c = callFunction(std_String_charCodeAt, s, i); if (!((0x41 <= c && c <= 0x5A) || (0x61 <= c && c <= 0x7A))) return false; } return true; } /** - * Returns true if the input contains only ASCII digit characters. - */ -function IsASCIIDigitString(s) { - assert(typeof s === "string", "IsASCIIDigitString"); - - for (var i = 0; i < s.length; i++) { - var c = callFunction(std_String_charCodeAt, s, i); - if (!(0x30 <= c && c <= 0x39)) - return false; - } - return true; -} - -/** * Validates and canonicalizes the given language tag. */ function ValidateAndCanonicalizeLanguageTag(locale) { assert(typeof locale === "string", "ValidateAndCanonicalizeLanguageTag"); // Handle the common case (a standalone language) first. // Only the following Unicode BCP 47 locale identifier subset is accepted: // unicode_locale_id = unicode_language_id @@ -1438,19 +1348,19 @@ function CanonicalizeLocaleList(locales) // Step 1. if (locales === undefined) return []; // Step 3 (and the remaining steps). if (typeof locales === "string") return [ValidateAndCanonicalizeLanguageTag(locales)]; - var unboxedLocale = callFunction(unboxLocaleOrNull, locales); + var unboxedLocale = LocaleToStringOrNull(locales); if (unboxedLocale !== null) - return [StringFromLanguageTagObject(unboxedLocale.locale)] + return [unboxedLocale]; // Step 2. var seen = []; // Step 4. var O = ToObject(locales); // Step 5. @@ -1466,19 +1376,19 @@ function CanonicalizeLocaleList(locales) // Step 7.c.i. var kValue = O[k]; // Step 7.c.ii. if (!(typeof kValue === "string" || IsObject(kValue))) ThrowTypeError(JSMSG_INVALID_LOCALES_ELEMENT); // Steps 7.c.iii-iv. - var unboxedLocale = callFunction(unboxLocaleOrNull, kValue); + var unboxedLocale = LocaleToStringOrNull(kValue); var tag = unboxedLocale !== null - ? StringFromLanguageTagObject(unboxedLocale.locale) + ? unboxedLocale : ValidateAndCanonicalizeLanguageTag(ToString(kValue)); // Step 7.c.v. if (callFunction(ArrayIndexOf, seen, tag) === -1) _DefineDataProperty(seen, seen.length, tag); } // Step 7.d.
--- a/js/src/builtin/intl/Locale.cpp +++ b/js/src/builtin/intl/Locale.cpp @@ -27,618 +27,36 @@ #include "vm/JSContext.h" #include "vm/StringType.h" #include "vm/JSObject-inl.h" #include "vm/NativeObject-inl.h" using namespace js; -const JSClass LocaleObject::class_ = { - js_Object_str, - JSCLASS_HAS_RESERVED_SLOTS(LocaleObject::SLOT_COUNT), -}; - -static bool locale_toSource(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().setString(cx->names().Locale); - return true; -} - -static const JSFunctionSpec locale_methods[] = { - JS_SELF_HOSTED_FN("maximize", "Intl_Locale_maximize", 0, 0), - JS_SELF_HOSTED_FN("minimize", "Intl_Locale_minimize", 0, 0), - JS_SELF_HOSTED_FN("toString", "Intl_Locale_toString", 0, 0), - JS_FN(js_toSource_str, locale_toSource, 0, 0), JS_FS_END}; - -static const JSPropertySpec locale_properties[] = { - JS_SELF_HOSTED_GET("baseName", "$Intl_Locale_baseName_get", 0), - JS_SELF_HOSTED_GET("calendar", "$Intl_Locale_calendar_get", 0), - JS_SELF_HOSTED_GET("collation", "$Intl_Locale_collation_get", 0), - JS_SELF_HOSTED_GET("hourCycle", "$Intl_Locale_hourCycle_get", 0), - JS_SELF_HOSTED_GET("caseFirst", "$Intl_Locale_caseFirst_get", 0), - JS_SELF_HOSTED_GET("numeric", "$Intl_Locale_numeric_get", 0), - JS_SELF_HOSTED_GET("numberingSystem", "$Intl_Locale_numberingSystem_get", - 0), - JS_SELF_HOSTED_GET("language", "$Intl_Locale_language_get", 0), - JS_SELF_HOSTED_GET("script", "$Intl_Locale_script_get", 0), - JS_SELF_HOSTED_GET("region", "$Intl_Locale_region_get", 0), - JS_STRING_SYM_PS(toStringTag, "Intl.Locale", JSPROP_READONLY), - JS_PS_END}; - -static LocaleObject* CreateLocaleObject(JSContext* cx, HandleObject prototype) { - RootedObject proto(cx, prototype); - if (!proto) { - proto = GlobalObject::getOrCreateLocalePrototype(cx, cx->global()); - if (!proto) { - return nullptr; - } - } - - LocaleObject* locale = NewObjectWithGivenProto<LocaleObject>(cx, proto); - if (!locale) { - return nullptr; - } - - locale->setReservedSlot(LocaleObject::INTERNALS_SLOT, NullValue()); - - return locale; -} - -/** - * Intl.Locale( tag[, options] ) - */ -static bool Locale(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - - // Step 1. - if (!ThrowIfNotConstructing(cx, args, "Intl.Locale")) { - return false; - } - - // Steps 2-6 (Inlined 9.1.14, OrdinaryCreateFromConstructor). - RootedObject proto(cx); - if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) { - return false; - } - - Rooted<LocaleObject*> locale(cx, CreateLocaleObject(cx, proto)); - if (!locale) { - return false; - } - - HandleValue tag = args.get(0); - HandleValue options = args.get(1); - - // Steps 7-37. - if (!intl::InitializeObject(cx, locale, cx->names().InitializeLocale, tag, - options)) { - return false; - } - - // Step 38. - args.rval().setObject(*locale); - return true; -} - -JSObject* js::CreateLocalePrototype(JSContext* cx, HandleObject Intl, - Handle<GlobalObject*> global) { - RootedFunction ctor( - cx, GlobalObject::createConstructor(cx, &Locale, cx->names().Locale, 1)); - if (!ctor) { - return nullptr; - } - - RootedObject proto( - cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); - if (!proto) { - return nullptr; - } - - if (!LinkConstructorAndPrototype(cx, ctor, proto)) { - return nullptr; - } - - if (!DefinePropertiesAndFunctions(cx, proto, locale_properties, - locale_methods)) { - return nullptr; - } - - RootedValue ctorValue(cx, ObjectValue(*ctor)); - if (!DefineDataProperty(cx, Intl, cx->names().Locale, ctorValue, 0)) { - return nullptr; - } - - return proto; -} - /* static */ bool js::GlobalObject::addLocaleConstructor(JSContext* cx, HandleObject intl) { Handle<GlobalObject*> global = cx->global(); { - const Value& proto = global->getReservedSlot(LOCALE_PROTO); - if (!proto.isUndefined()) { - MOZ_ASSERT(proto.isObject()); - JS_ReportErrorASCII(cx, - "the Locale constructor can't be added multiple " - "times in the same global"); - return false; - } - } - - JSObject* localeProto = CreateLocalePrototype(cx, intl, global); - if (!localeProto) { - return false; - } - - global->setReservedSlot(LOCALE_PROTO, ObjectValue(*localeProto)); - - { const Value& proto = global->getReservedSlot(NATIVE_LOCALE_PROTO); if (!proto.isUndefined()) { MOZ_ASSERT(proto.isObject()); JS_ReportErrorASCII( cx, "the Locale constructor can't be added multiple times in the" "same global"); return false; } } - localeProto = CreateNativeLocalePrototype(cx, intl, global); + JSObject* localeProto = CreateNativeLocalePrototype(cx, intl, global); if (!localeProto) { return false; } global->setReservedSlot(NATIVE_LOCALE_PROTO, ObjectValue(*localeProto)); return true; } bool js::AddLocaleConstructor(JSContext* cx, JS::Handle<JSObject*> intl) { return GlobalObject::addLocaleConstructor(cx, intl); } - -bool js::intl_CreateUninitializedLocale(JSContext* cx, unsigned argc, - Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 0); - - LocaleObject* locale = CreateLocaleObject(cx, nullptr); - if (!locale) { - return false; - } - - args.rval().setObject(*locale); - return true; -} - -#ifdef DEBUG - -template <typename CharT> -struct LanguageTagValidator { - bool operator()(mozilla::Range<const CharT> language) const { - // Tell the analysis the |std::all_of| function can't GC. - JS::AutoSuppressGCAnalysis nogc; - - // BNF: unicode_language_subtag = alpha{2,3} | alpha{5,8} ; - // Canonical form is lower case. - return ((2 <= language.length() && language.length() <= 3) || - (5 <= language.length() && language.length() <= 8)) && - std::all_of(language.begin().get(), language.end().get(), - mozilla::IsAsciiLowercaseAlpha<CharT>); - } -}; - -template <typename CharT> -struct ScriptTagValidator { - bool operator()(mozilla::Range<const CharT> script) const { - // Tell the analysis the |std::all_of| function can't GC. - JS::AutoSuppressGCAnalysis nogc; - - // BNF: unicode_script_subtag = alpha{4} ; - // Canonical form is title case. - return script.length() == 4 && mozilla::IsAsciiUppercaseAlpha(script[0]) && - std::all_of(std::next(script.begin().get()), script.end().get(), - mozilla::IsAsciiLowercaseAlpha<CharT>); - } -}; - -template <typename CharT> -struct RegionTagValidator { - bool operator()(mozilla::Range<const CharT> region) const { - // Tell the analysis the |std::all_of| function can't GC. - JS::AutoSuppressGCAnalysis nogc; - - // BNF: unicode_region_subtag = (alpha{2} | digit{3}) ; - // Canonical form is upper case. - return (region.length() == 2 && - std::all_of(region.begin().get(), region.end().get(), - mozilla::IsAsciiUppercaseAlpha<CharT>)) || - (region.length() == 3 && - std::all_of(region.begin().get(), region.end().get(), - mozilla::IsAsciiDigit<CharT>)); - } -}; - -template <template <typename> class Validator, typename CharT> -static bool IsStructurallyValidSubtag(mozilla::Range<const CharT> subtag) { - return Validator<CharT>{}(subtag); -} - -template <template <typename> class Validator> -static bool IsStructurallyValidSubtag(JSLinearString* subtag) { - JS::AutoCheckCannotGC nogc; - return subtag->hasLatin1Chars() - ? Validator<JS::Latin1Char>{}(subtag->latin1Range(nogc)) - : Validator<char16_t>{}(subtag->twoByteRange(nogc)); -} - -template <typename T> -static bool IsStructurallyValidLanguageTag(const T& language) { - return IsStructurallyValidSubtag<LanguageTagValidator>(language); -} - -template <typename T> -static bool IsStructurallyValidScriptTag(const T& script) { - return IsStructurallyValidSubtag<ScriptTagValidator>(script); -} - -template <typename T> -static bool IsStructurallyValidRegionTag(const T& region) { - return IsStructurallyValidSubtag<RegionTagValidator>(region); -} - -#endif /* DEBUG */ - -// unicode_language_subtag = alpha{2,3} | alpha{5,8} ; -static constexpr size_t LanguageTagMaxLength = 8; - -// unicode_script_subtag = alpha{4} ; -static constexpr size_t ScriptTagMaxLength = 4; - -// unicode_region_subtag = (alpha{2} | digit{3}) ; -static constexpr size_t RegionTagMaxLength = 3; - -// Zero-terminated ICU Locale ID. -using LocaleId = - js::Vector<char, LanguageTagMaxLength + 1 + ScriptTagMaxLength + 1 + - RegionTagMaxLength + 1>; - -struct LocaleSubtags { - using Subtag = mozilla::Range<const char>; - - Subtag language; - Subtag script; - Subtag region; - - LocaleSubtags(Subtag language, Subtag script, Subtag region) - : language(language), script(script), region(region) {} -}; - -// Split the language, script, and region subtags from the input ICU locale ID. -// -// ICU provides |uloc_getLanguage|, |uloc_getScript|, and |uloc_getCountry| to -// retrieve these subtags, but unfortunately these functions are rather slow, so -// we use our own implementation. -static LocaleSubtags GetLocaleSubtags(const LocaleId& localeId) { - // Locale ID should be zero-terminated for ICU. - MOZ_ASSERT(localeId.back() == '\0'); - - using Subtag = LocaleSubtags::Subtag; - - // mozilla::Range uses 'const' members, so we can't assign to it. Use |Maybe| - // to defer initialization to workaround this. - mozilla::Maybe<Subtag> language, script, region; - - size_t subtagStart = 0; - for (size_t i = 0; i < localeId.length(); i++) { - char c = localeId[i]; - - // Skip over any characters until we hit either separator char or the end. - if (c != '_' && c != '-' && c != '\0') { - continue; - } - - size_t length = i - subtagStart; - const char* start = localeId.begin() + subtagStart; - if (subtagStart == 0) { - // unicode_language_subtag = alpha{2,3} | alpha{5,8} ; - if ((2 <= length && length <= 3) || (5 <= length && length <= 8)) { - language.emplace(start, length); - MOZ_ASSERT(IsStructurallyValidLanguageTag(*language)); - } - } else if (length == 4) { - // unicode_script_subtag = alpha{4} ; - script.emplace(start, length); - MOZ_ASSERT(IsStructurallyValidScriptTag(*script)); - } else if (length == 2 || length == 3) { - // unicode_region_subtag = (alpha{2} | digit{3}) ; - region.emplace(start, length); - MOZ_ASSERT(IsStructurallyValidRegionTag(*region)); - } else { - // Ignore any trailing variant or extension subtags. - break; - } - - subtagStart = i + 1; - } - - return {language.valueOr(Subtag()), script.valueOr(Subtag()), - region.valueOr(Subtag())}; -} - -enum class LikelySubtags : bool { Add, Remove }; - -// Return true iff the input subtags are already maximized resp. minimized. -static bool HasLikelySubtags(LikelySubtags likelySubtags, - JSLinearString* language, JSLinearString* script, - JSLinearString* region) { - // The language tag is already maximized if language, script, and region - // subtags are present and no placeholder subtags ("und", "Zzzz", "ZZ") - // are used. - if (likelySubtags == LikelySubtags::Add) { - return !StringEqualsLiteral(language, "und") && script && - !StringEqualsLiteral(script, "Zzzz") && region && - !StringEqualsLiteral(region, "ZZ"); - } - - // The language tag is already minimized if it only contains a language - // subtag whose value is not the placeholder value "und". - return !StringEqualsLiteral(language, "und") && !script && !region; -} - -// Create an ICU locale ID from the given language, script, and region subtags. -static bool CreateLocaleForLikelySubtags(JSLinearString* language, - JSLinearString* script, - JSLinearString* region, - LocaleId& locale) { - MOZ_ASSERT(locale.length() == 0); - - auto appendSubtag = [&locale](JSLinearString* subtag) { - if (locale.length() > 0 && !locale.append('_')) { - return false; - } - if (!locale.growBy(subtag->length())) { - return false; - } - char* dest = locale.end() - subtag->length(); - CopyChars(reinterpret_cast<Latin1Char*>(dest), *subtag); - return true; - }; - - // Append the language subtag. - if (!appendSubtag(language)) { - return false; - } - - // Append the script subtag if present. - if (script && !appendSubtag(script)) { - return false; - } - - // Append the region subtag if present. - if (region && !appendSubtag(region)) { - return false; - } - - // Zero-terminated for use with ICU. - return locale.append('\0'); -} - -template <decltype(uloc_addLikelySubtags) likelySubtagsFn> -static bool CallLikelySubtags(JSContext* cx, const LocaleId& localeId, - LocaleId& result) { - // Locale ID must be zero-terminated before passing it to ICU. - MOZ_ASSERT(localeId.back() == '\0'); - MOZ_ASSERT(result.length() == 0); - - // Ensure there's enough room for the result. - MOZ_ALWAYS_TRUE(result.resize(LocaleId::InlineLength)); - - int32_t length = intl::CallICU( - cx, - [&localeId](char* chars, int32_t size, UErrorCode* status) { - return likelySubtagsFn(localeId.begin(), chars, size, status); - }, - result); - if (length < 0) { - return false; - } - - MOZ_ASSERT( - size_t(length) <= LocaleId::InlineLength, - "Unexpected extra subtags were added by ICU. If this assertion ever " - "fails, simply remove it and move on like nothing ever happended."); - - // Resize the vector to the actual string length. - result.shrinkTo(length); - - // Zero-terminated for use with ICU. - return result.append('\0'); -} - -// Return the array |[language, script or undefined, region or undefined]|. -static ArrayObject* CreateLikelySubtagsResult(JSContext* cx, - HandleValue language, - HandleValue script, - HandleValue region) { - enum LikelySubtagsResult { - LikelySubtagsResult_Language = 0, - LikelySubtagsResult_Script, - LikelySubtagsResult_Region, - - LikelySubtagsResult_Length - }; - - ArrayObject* result = - NewDenseFullyAllocatedArray(cx, LikelySubtagsResult_Length); - if (!result) { - return nullptr; - } - result->setDenseInitializedLength(LikelySubtagsResult_Length); - - result->initDenseElement(LikelySubtagsResult_Language, language); - result->initDenseElement(LikelySubtagsResult_Script, script); - result->initDenseElement(LikelySubtagsResult_Region, region); - - return result; -} - -// The canonical way to compute the Unicode BCP 47 locale identifier with likely -// subtags is as follows: -// -// 1. Call uloc_forLanguageTag() to transform the input locale identifer into an -// ICU locale ID. -// 2. Call uloc_addLikelySubtags() to add the likely subtags to the locale ID. -// 3. Call uloc_toLanguageTag() to transform the resulting locale ID back into -// a Unicode BCP 47 locale identifier. -// -// Since uloc_forLanguageTag() and uloc_toLanguageTag() are both kind of slow -// and we know, by construction, that the input Unicode BCP 47 locale identifier -// only contains a language, script, and region subtag, we can avoid both calls -// if we implement their guts ourselves, see CreateLocaleForLikelySubtags(). -// (Where "slow" means about 50% of the execution time of Locale.p.maximize.) -static ArrayObject* LikelySubtags(JSContext* cx, LikelySubtags likelySubtags, - const CallArgs& args) { - MOZ_ASSERT(args.length() == 3); - MOZ_ASSERT(args[0].isString()); - MOZ_ASSERT(args[1].isString() || args[1].isUndefined()); - MOZ_ASSERT(args[2].isString() || args[2].isUndefined()); - - RootedLinearString language(cx, args[0].toString()->ensureLinear(cx)); - if (!language) { - return nullptr; - } - MOZ_ASSERT(IsStructurallyValidLanguageTag(language)); - - RootedLinearString script(cx); - if (args[1].isString()) { - script = args[1].toString()->ensureLinear(cx); - if (!script) { - return nullptr; - } - MOZ_ASSERT(IsStructurallyValidScriptTag(script)); - } - - RootedLinearString region(cx); - if (args[2].isString()) { - region = args[2].toString()->ensureLinear(cx); - if (!region) { - return nullptr; - } - MOZ_ASSERT(IsStructurallyValidRegionTag(region)); - } - - // Return early if the input is already maximized/minimized. - if (HasLikelySubtags(likelySubtags, language, script, region)) { - return CreateLikelySubtagsResult(cx, args[0], args[1], args[2]); - } - - // Create the locale ID for the input arguments. - LocaleId locale(cx); - if (!CreateLocaleForLikelySubtags(language, script, region, locale)) { - return nullptr; - } - - // UTS #35 requires that locale ID is maximized before its likely subtags are - // removed, so we need to call uloc_addLikelySubtags() for both cases. - // See <https://ssl.icu-project.org/trac/ticket/10220> and - // <https://ssl.icu-project.org/trac/ticket/12345>. - - LocaleId localeLikelySubtags(cx); - - // Add likely subtags to the locale ID. When minimizing we can skip adding the - // likely subtags for already maximized tags. (When maximizing we've already - // verified above that the tag is missing likely subtags.) - bool addLikelySubtags = - likelySubtags == LikelySubtags::Add || - !HasLikelySubtags(LikelySubtags::Add, language, script, region); - - if (addLikelySubtags) { - if (!CallLikelySubtags<uloc_addLikelySubtags>(cx, locale, - localeLikelySubtags)) { - return nullptr; - } - } - - // Now that we've succesfully maximized the locale, we can minimize it. - if (likelySubtags == LikelySubtags::Remove) { - if (addLikelySubtags) { - // Copy the maximized subtags back into |locale|. - locale = std::move(localeLikelySubtags); - localeLikelySubtags = LocaleId(cx); - } - - // Remove likely subtags from the locale ID. - if (!CallLikelySubtags<uloc_minimizeSubtags>(cx, locale, - localeLikelySubtags)) { - return nullptr; - } - } - - // Retrieve the individual language, script, and region subtags from the - // resulting locale ID. - LocaleSubtags subtags = GetLocaleSubtags(localeLikelySubtags); - - // Convert each subtag back to a JSString. Use |undefined| for absent subtags. - auto toValue = [cx](const auto& subtag, MutableHandleValue result) { - if (subtag.length() > 0) { - JSLinearString* str = - NewStringCopyN<CanGC>(cx, subtag.begin().get(), subtag.length()); - if (!str) { - return false; - } - result.setString(str); - } else { - result.setUndefined(); - } - return true; - }; - - RootedValue languageValue(cx); - if (!toValue(subtags.language, &languageValue)) { - return nullptr; - } - if (languageValue.isUndefined()) { - // ICU replaces "und" with the empty string. Handle this case separately. - JSLinearString* str = NewStringCopyZ<CanGC>(cx, "und"); - if (!str) { - return nullptr; - } - languageValue.setString(str); - } - - RootedValue scriptValue(cx); - if (!toValue(subtags.script, &scriptValue)) { - return nullptr; - } - - RootedValue regionValue(cx); - if (!toValue(subtags.region, ®ionValue)) { - return nullptr; - } - - // Return the language, script, and region subtags in an array. - return CreateLikelySubtagsResult(cx, languageValue, scriptValue, regionValue); -} - -bool js::intl_AddLikelySubtags(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - - ArrayObject* result = LikelySubtags(cx, LikelySubtags::Add, args); - if (!result) { - return false; - } - args.rval().setObject(*result); - return true; -} - -bool js::intl_RemoveLikelySubtags(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - - ArrayObject* result = LikelySubtags(cx, LikelySubtags::Remove, args); - if (!result) { - return false; - } - args.rval().setObject(*result); - return true; -}
--- a/js/src/builtin/intl/Locale.h +++ b/js/src/builtin/intl/Locale.h @@ -12,32 +12,16 @@ #include "builtin/SelfHostingDefines.h" #include "js/Class.h" #include "vm/NativeObject.h" namespace js { class GlobalObject; -class LocaleObject : public NativeObject { - public: - static const JSClass class_; - - static constexpr uint32_t INTERNALS_SLOT = 0; - static constexpr uint32_t SLOT_COUNT = 1; - - static_assert(INTERNALS_SLOT == INTL_INTERNALS_OBJECT_SLOT, - "INTERNALS_SLOT must match self-hosting define for internals " - "object slot"); -}; - -extern JSObject* CreateLocalePrototype(JSContext* cx, - JS::Handle<JSObject*> Intl, - JS::Handle<GlobalObject*> global); - class NativeLocaleObject : public NativeObject { public: static const JSClass class_; static constexpr uint32_t LANGUAGE_TAG_SLOT = 0; static constexpr uint32_t BASENAME_SLOT = 1; static constexpr uint32_t UNICODE_EXTENSION_SLOT = 2; static constexpr uint32_t SLOT_COUNT = 3; @@ -60,36 +44,11 @@ class NativeLocaleObject : public Native return getFixedSlot(UNICODE_EXTENSION_SLOT); } }; extern JSObject* CreateNativeLocalePrototype(JSContext* cx, JS::Handle<JSObject*> Intl, JS::Handle<GlobalObject*> global); -/** - * Creates an uninitialized Intl.Locale object. - */ -extern MOZ_MUST_USE bool intl_CreateUninitializedLocale(JSContext* cx, - unsigned argc, - Value* vp); - -/** - * Adds likely subtags to the given canonicalized language BCP47 subtags per - * the "Add Likely Subtags" algorithm from UTS #35. - * - * Usage: subtags = intl_AddLikelySubtags(language, script, region) - */ -extern MOZ_MUST_USE bool intl_AddLikelySubtags(JSContext* cx, unsigned argc, - Value* vp); - -/** - * Removes likely subtags from the given canonicalized BCP47 subtags per - * the "Remove Likely Subtags" algorithm from UTS #35. - * - * Usage: subtags = intl_RemoveLikelySubtags(language, script, region) - */ -extern MOZ_MUST_USE bool intl_RemoveLikelySubtags(JSContext* cx, unsigned argc, - Value* vp); - } // namespace js #endif /* builtin_intl_Locale_h */
deleted file mode 100644 --- a/js/src/builtin/intl/Locale.js +++ /dev/null @@ -1,690 +0,0 @@ -/* 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/. */ - -/** - * Intl.Locale internal properties. - */ -var localeInternalProperties = { - relevantExtensionKeys: ["ca", "co", "hc", "kf", "kn", "nu"], -}; - -/** - * ApplyOptionsToTag( tag, options ) - */ -function ApplyOptionsToTag(tagObj, options) { - // Steps 1-2 (Already performed in caller). - - // Step 3. - var languageOption = GetOption(options, "language", "string", undefined, undefined); - - // Step 4. - var language; - if (languageOption !== undefined) { - language = parseStandaloneLanguage(languageOption); - if (language === null) - ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "language", languageOption); - } - - // Step 5. - var scriptOption = GetOption(options, "script", "string", undefined, undefined); - - // Step 6. - var script; - if (scriptOption !== undefined) { - script = parseStandaloneScript(scriptOption); - if (script === null) - ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "script", scriptOption); - } - - // Step 7. - var regionOption = GetOption(options, "region", "string", undefined, undefined); - - // Step 8. - var region; - if (regionOption !== undefined) { - region = parseStandaloneRegion(regionOption); - if (region === null) - ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "region", regionOption); - } - - // Step 9 (Already performed in caller). - - // Return early when no subtags were modified. - if (language === undefined && script === undefined && region === undefined) - return; - - // Step 10. - if (language !== undefined) - tagObj.language = language; - - // Step 11. - if (script !== undefined) - tagObj.script = script; - - // Step 12. - if (region !== undefined) - tagObj.region = region; - - // Replacing the "language" subtag may have turned this locale tag - // into a grandfathered language tag. For example consider the - // case `new Intl.Locale("en-hakka", {language: "zh"})`, where - // "zh-hakka" is a regular grandfathered language tag. - if (language !== undefined) - updateGrandfatheredMappings(tagObj); - - // Step 13. - // Optimized to only update the mappings, because all other canonicalization - // steps already happended earlier, so there's no need to repeat them here. - updateLocaleIdMappings(tagObj); -} - -/** - * ApplyUnicodeExtensionToTag( tag, options, relevantExtensionKeys ) - */ -function ApplyUnicodeExtensionToTag(tagObj, options, relevantExtensionKeys) { - // Steps 1-2 (Not applicable). - - // Step 3.a - // Find the Unicode extension subtag index in |tagObj.extensions|. - var extensions = tagObj.extensions; - var extensionIndex = -1; - for (var i = 0; i < extensions.length; i++) { - if (extensions[i][0] === "u") { - extensionIndex = i; - break; - } - } - - // If Unicode extensions are neither present in |tagObj| nor in |options|, - // we can skip everything below and directly return here. - if (extensionIndex < 0) { - var hasUnicodeOptions = false; - for (var i = 0; i < relevantExtensionKeys.length; i++) { - if (options[relevantExtensionKeys[i]] !== undefined) { - hasUnicodeOptions = true; - break; - } - } - if (!hasUnicodeOptions) - return; - } - - var attributes, keywords; - if (extensionIndex >= 0) { - // Step 3.b. - var components = UnicodeExtensionComponents(extensions[extensionIndex]); - - // Step 3.c. - attributes = components.attributes; - - // Step 3.d. - keywords = components.keywords; - } else { - // Step 4.a. - attributes = []; - - // Step 4.b. - keywords = []; - } - - // Step 5 (Not applicable). - - // Step 6. - for (var i = 0; i < relevantExtensionKeys.length; i++) { - var key = relevantExtensionKeys[i]; - - // Step 6.a. - var value = undefined; - - // Steps 6.b-c. - var entry = null; - for (var j = 0; j < keywords.length; j++) { - if (keywords[j].key === key) { - entry = keywords[j]; - value = entry.value; - break; - } - } - - // Step 6.d. - assert(hasOwn(key, options), "option value for each extension key present"); - - // Step 6.e. - var optionsValue = options[key]; - - // Step 6.f. - if (optionsValue !== undefined) { - // Step 6.f.i. - assert(typeof optionsValue === "string", "optionsValue is a string"); - - // Step 6.f.ii. - value = optionsValue; - - // Steps 6.f.iii-iv. - if (entry !== null) - entry.value = value; - else - _DefineDataProperty(keywords, keywords.length, {key, value}); - } - - // Step 6.g (Modify |options| in place). - options[key] = value; - } - - // Step 7 (Not applicable). - - // Step 8. - var newExtension = CanonicalizeUnicodeExtension(attributes, keywords, true); - - // Step 9 (Inlined call to InsertUnicodeExtension). - // If the shortcut below step 3.a wasn't taken, the Unicode extension is - // definitely non-empty; assert this here. - assert(newExtension !== "", "unexpected empty Unicode extension"); - - // Update or add the new Unicode extension sequence. - if (extensionIndex >= 0) { - extensions[extensionIndex] = newExtension; - } else { - _DefineDataProperty(extensions, extensions.length, newExtension); - - // Extension sequences are sorted by their singleton characters. - if (extensions.length > 1) { - callFunction(ArraySort, extensions); - } - } - - // Steps 10-11 (Not applicable). -} - -/** - * Intl.Locale( tag[, options] ) - */ -function InitializeLocale(locale, tag, options) { - // Step 7. - if (!(typeof tag === "string" || IsObject(tag))) - ThrowTypeError(JSMSG_INVALID_LOCALES_ELEMENT); - - // Steps 8-9. - var unboxedLocale = callFunction(unboxLocaleOrNull, tag); - if (unboxedLocale === null) - tag = ToString(tag); - - // Steps 10-11. - var hasOptions = options !== undefined; - if (hasOptions) - options = ToObject(options); - - // Step 12. - var tagObj; - if (unboxedLocale === null) { - tagObj = parseLanguageTag(tag); - if (tagObj === null) - ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, tag); - - // ApplyOptionsToTag, step 9. - CanonicalizeLanguageTagObject(tagObj); - } else { - tagObj = copyLanguageTagObject(unboxedLocale.locale); - - // |tagObj| is already canonicalized for Intl.Locale objects, so we can - // skip ApplyOptionsToTag, step 9. - } - - // Step 13. - var opt = new Record(); - - // Skip rest of step 12 and steps 14-29 if no options were passed to the - // Intl.Locale constructor. - if (hasOptions) { - // Step 12. - ApplyOptionsToTag(tagObj, options); - - // Step 14. - var calendar = GetOption(options, "calendar", "string", undefined, undefined); - - // Step 15. - if (calendar !== undefined) { - var standaloneCalendar = parseStandaloneUnicodeExtensionType(calendar); - if (standaloneCalendar === null) - ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "calendar", calendar); - - calendar = standaloneCalendar; - } - - // Step 16. - opt.ca = calendar; - - // Step 17. - var collation = GetOption(options, "collation", "string", undefined, undefined); - - // Step 18. - if (collation !== undefined) { - var standaloneCollation = parseStandaloneUnicodeExtensionType(collation); - if (standaloneCollation === null) - ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "collation", collation); - - collation = standaloneCollation; - } - - // Step 19. - opt.co = collation; - - // Steps 20-21. - opt.hc = GetOption(options, "hourCycle", "string", ["h11", "h12", "h23", "h24"], - undefined); - - // Steps 22-23. - opt.kf = GetOption(options, "caseFirst", "string", ["upper", "lower", "false"], - undefined); - - // Step 24. - var numeric = GetOption(options, "numeric", "boolean", undefined, undefined); - - // Step 25. - if (numeric !== undefined) - numeric = ToString(numeric); - - // Step 26. - opt.kn = numeric; - - // Step 27. - var numberingSystem = GetOption(options, "numberingSystem", "string", undefined, - undefined); - - // Step 28. - if (numberingSystem !== undefined) { - var standaloneNumberingSystem = parseStandaloneUnicodeExtensionType(numberingSystem); - if (standaloneNumberingSystem === null) - ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "numberingSystem", numberingSystem); - - numberingSystem = standaloneNumberingSystem; - } - - // Step 29. - opt.nu = numberingSystem; - } else { - // Steps 14-29. - opt.ca = undefined; - opt.co = undefined; - opt.hc = undefined; - opt.kf = undefined; - opt.kn = undefined; - opt.nu = undefined; - } - - // Step 2. - var {relevantExtensionKeys} = localeInternalProperties; - - // Step 30. - if (hasOptions || unboxedLocale === null) { - ApplyUnicodeExtensionToTag(tagObj, opt, relevantExtensionKeys); - } else { - // Directly copy the Unicode extension keys from the source object if - // no options were passed to the constructor. - opt.ca = unboxedLocale.calendar; - opt.co = unboxedLocale.collation; - opt.hc = unboxedLocale.hourCycle; - opt.kf = unboxedLocale.caseFirst; - opt.kn = unboxedLocale.numeric; - opt.nu = unboxedLocale.numberingSystem; - } - - // Steps 31-37. - var internals = new Record(); - internals.locale = tagObj; - internals.calendar = opt.ca; - internals.collation = opt.co; - internals.hourCycle = opt.hc; - internals.caseFirst = opt.kf; - internals.numeric = opt.kn === "true" || opt.kn === ""; - internals.numberingSystem = opt.nu; - - assert(UnsafeGetReservedSlot(locale, INTL_INTERNALS_OBJECT_SLOT) === null, - "Internal slot already initialized?"); - UnsafeSetReservedSlot(locale, INTL_INTERNALS_OBJECT_SLOT, internals); -} - -/** - * Creates a new Intl.Locale object using the language tag object |tagObj|. - * The other internal slots are copied over from |otherLocale|. - */ -function CreateLocale(tagObj, otherLocale) { - assert(IsObject(tagObj), "CreateLocale called with non-object"); - assert(GuardToLocale(otherLocale) !== null, "CreateLocale called with non-Locale"); - -#ifdef DEBUG - var localeTag = StringFromLanguageTagObject(tagObj); - assert(localeTag === CanonicalizeLanguageTag(localeTag), - "CreateLocale called with non-canonical language tag"); -#endif - - var locInternals = getLocaleInternals(otherLocale); - - var internals = new Record(); - internals.locale = tagObj; - internals.calendar = locInternals.calendar; - internals.collation = locInternals.collation; - internals.hourCycle = locInternals.hourCycle; - internals.caseFirst = locInternals.caseFirst; - internals.numeric = locInternals.numeric; - internals.numberingSystem = locInternals.numberingSystem; - - var locale = intl_CreateUninitializedLocale(); - assert(UnsafeGetReservedSlot(locale, INTL_INTERNALS_OBJECT_SLOT) === null, - "Internal slot already initialized?"); - UnsafeSetReservedSlot(locale, INTL_INTERNALS_OBJECT_SLOT, internals); - - return locale; -} - -/** - * Unboxes the |this| argument if it is an Intl.Locale object, otherwise - * returns null. - */ -function unboxLocaleOrNull() { - if (!IsObject(this)) - return null; - - var loc = GuardToLocale(this); - if (loc !== null) - return getLocaleInternals(loc); - if (IsWrappedLocale(this)) - return callFunction(CallLocaleMethodIfWrapped, this, "unboxLocaleOrNull"); - return null; -} - -/** - * Creates a copy of the given language tag object. - */ -function copyLanguageTagObject(tagObj) { - assert(IsObject(tagObj), "copyLanguageTagObject called with non-object"); - - var variants = []; - for (var i = 0; i < tagObj.variants.length; i++) - _DefineDataProperty(variants, i, tagObj.variants[i]); - - var extensions = []; - for (var i = 0; i < tagObj.extensions.length; i++) - _DefineDataProperty(extensions, i, tagObj.extensions[i]); - - return { - language: tagObj.language, - script: tagObj.script, - region: tagObj.region, - variants, - extensions, - privateuse: tagObj.privateuse, - }; -} - -function getLocaleInternals(obj) { - assert(IsObject(obj), "getLocaleInternals called with non-object"); - assert(GuardToLocale(obj) !== null, "getLocaleInternals called with non-Locale"); - - var internals = UnsafeGetReservedSlot(obj, INTL_INTERNALS_OBJECT_SLOT); - assert(IsObject(internals), "Internal slot not initialized?"); - - return internals; -} - -/** - * Intl.Locale.prototype.maximize () - */ -function Intl_Locale_maximize() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "Intl_Locale_maximize"); - - // Step 3. - var tagObj = copyLanguageTagObject(getLocaleInternals(loc).locale); - - var maximal = intl_AddLikelySubtags(tagObj.language, tagObj.script, tagObj.region); - tagObj.language = maximal[0]; - tagObj.script = maximal[1]; - tagObj.region = maximal[2]; - - // Update mappings in case ICU returned a non-canonicalized locale. - updateLocaleIdMappings(tagObj); - - // Step 4. - return CreateLocale(tagObj, loc); -} - -/** - * Intl.Locale.prototype.minimize () - */ -function Intl_Locale_minimize() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "Intl_Locale_minimize"); - - // Step 3. - var tagObj = copyLanguageTagObject(getLocaleInternals(loc).locale); - - var minimal = intl_RemoveLikelySubtags(tagObj.language, tagObj.script, tagObj.region); - tagObj.language = minimal[0]; - tagObj.script = minimal[1]; - tagObj.region = minimal[2]; - - // Update mappings in case ICU returned a non-canonicalized locale. - updateLocaleIdMappings(tagObj); - - // Step 4. - return CreateLocale(tagObj, loc); -} - -/** - * Intl.Locale.prototype.toString () - */ -function Intl_Locale_toString() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "Intl_Locale_toString"); - - // Step 3. - var tagObj = getLocaleInternals(loc).locale; - return StringFromLanguageTagObject(tagObj); -} - -/** - * get Intl.Locale.prototype.baseName - */ -function $Intl_Locale_baseName_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_baseName_get"); - - // Step 3. - var tagObj = getLocaleInternals(loc).locale; - - // Step 4. - // FIXME: spec bug - unicode_locale_id is always matched. - - // Step 5. - // FIXME: spec bug - subtag production names not updated. - var baseName = tagObj.language; - - if (tagObj.script !== undefined) - baseName += "-" + tagObj.script; - if (tagObj.region !== undefined) - baseName += "-" + tagObj.region; - if (tagObj.variants.length > 0) - baseName += "-" + callFunction(std_Array_join, tagObj.variants, "-"); - - return baseName; -} -_SetCanonicalName($Intl_Locale_baseName_get, "get baseName"); - -/** - * get Intl.Locale.prototype.calendar - */ -function $Intl_Locale_calendar_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_calendar_get"); - - // Step 3. - return getLocaleInternals(loc).calendar; -} -_SetCanonicalName($Intl_Locale_calendar_get, "get calendar"); - -/** - * get Intl.Locale.prototype.collation - */ -function $Intl_Locale_collation_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_collation_get"); - - // Step 3. - return getLocaleInternals(loc).collation; -} -_SetCanonicalName($Intl_Locale_collation_get, "get collation"); - -/** - * get Intl.Locale.prototype.hourCycle - */ -function $Intl_Locale_hourCycle_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_hourCycle_get"); - - // Step 3. - return getLocaleInternals(loc).hourCycle; -} -_SetCanonicalName($Intl_Locale_hourCycle_get, "get hourCycle"); - -/** - * get Intl.Locale.prototype.caseFirst - */ -function $Intl_Locale_caseFirst_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_caseFirst_get"); - - // Step 3. - return getLocaleInternals(loc).caseFirst; -} -_SetCanonicalName($Intl_Locale_caseFirst_get, "get caseFirst"); - -/** - * get Intl.Locale.prototype.numeric - */ -function $Intl_Locale_numeric_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_numeric_get"); - - // Step 3. - return getLocaleInternals(loc).numeric; -} -_SetCanonicalName($Intl_Locale_numeric_get, "get numeric"); - -/** - * get Intl.Locale.prototype.numberingSystem - */ -function $Intl_Locale_numberingSystem_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_numberingSystem_get"); - - // Step 3. - return getLocaleInternals(loc).numberingSystem; -} -_SetCanonicalName($Intl_Locale_numberingSystem_get, "get numberingSystem"); - -/** - * get Intl.Locale.prototype.language - */ -function $Intl_Locale_language_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_language_get"); - - // Step 3. - var tagObj = getLocaleInternals(loc).locale; - - // Step 4 (Unnecessary assertion). - - // Step 5. - return tagObj.language; -} -_SetCanonicalName($Intl_Locale_language_get, "get language"); - -/** - * get Intl.Locale.prototype.script - */ -function $Intl_Locale_script_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_script_get"); - - // Step 3. - var tagObj = getLocaleInternals(loc).locale; - - // Step 4 (Unnecessary assertion). - - // Steps 5-6. - // FIXME: spec bug - not all production names updated. - return tagObj.script; -} -_SetCanonicalName($Intl_Locale_script_get, "get script"); - -/** - * get Intl.Locale.prototype.region - */ -function $Intl_Locale_region_get() { - // Step 1. - var loc = this; - - // Step 2. - if (!IsObject(loc) || (loc = GuardToLocale(loc)) === null) - return callFunction(CallLocaleMethodIfWrapped, this, "$Intl_Locale_region_get"); - - // Step 3. - var tagObj = getLocaleInternals(loc).locale; - - // Step 4 (Unnecessary assertion). - - // Steps 5-6. - // FIXME: spec bug - not all production names updated. - return tagObj.region; -} -_SetCanonicalName($Intl_Locale_region_get, "get region");
--- a/js/src/builtin/intl/NativeLocale.cpp +++ b/js/src/builtin/intl/NativeLocale.cpp @@ -1248,14 +1248,14 @@ JSObject* js::CreateNativeLocalePrototyp } if (!DefinePropertiesAndFunctions(cx, proto, locale_native_properties, locale_native_methods)) { return nullptr; } RootedValue ctorValue(cx, ObjectValue(*ctor)); - if (!DefineDataProperty(cx, Intl, cx->names().locale, ctorValue, 0)) { + if (!DefineDataProperty(cx, Intl, cx->names().Locale, ctorValue, 0)) { return nullptr; } return proto; }
--- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -26,17 +26,16 @@ _(AtomicsOr) \ _(AtomicsXor) \ _(AtomicsIsLockFree) \ \ _(Boolean) \ \ _(IntlGuardToCollator) \ _(IntlGuardToDateTimeFormat) \ - _(IntlGuardToLocale) \ _(IntlGuardToNumberFormat) \ _(IntlGuardToPluralRules) \ _(IntlGuardToRelativeTimeFormat) \ \ _(MathAbs) \ _(MathFloor) \ _(MathCeil) \ _(MathRound) \
--- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -7,17 +7,16 @@ #include "mozilla/Casting.h" #include "jsmath.h" #include "builtin/AtomicsObject.h" #ifdef ENABLE_INTL_API # include "builtin/intl/Collator.h" # include "builtin/intl/DateTimeFormat.h" -# include "builtin/intl/Locale.h" # include "builtin/intl/NumberFormat.h" # include "builtin/intl/PluralRules.h" # include "builtin/intl/RelativeTimeFormat.h" #endif #include "builtin/MapObject.h" #include "builtin/String.h" #include "builtin/TestingFunctions.h" #include "builtin/TypedObject.h" @@ -106,17 +105,16 @@ static bool CanInlineCrossRealm(Inlinabl return true; case InlinableNative::MathRandom: // RNG state is per-realm. return false; case InlinableNative::IntlGuardToCollator: case InlinableNative::IntlGuardToDateTimeFormat: - case InlinableNative::IntlGuardToLocale: case InlinableNative::IntlGuardToNumberFormat: case InlinableNative::IntlGuardToPluralRules: case InlinableNative::IntlGuardToRelativeTimeFormat: case InlinableNative::IsRegExpObject: case InlinableNative::RegExpMatcher: case InlinableNative::RegExpSearcher: case InlinableNative::RegExpTester: case InlinableNative::RegExpPrototypeOptimizable: @@ -314,28 +312,25 @@ IonBuilder::InliningResult IonBuilder::i return inlineBoolean(callInfo); #ifdef ENABLE_INTL_API // Intl natives. case InlinableNative::IntlGuardToCollator: return inlineGuardToClass(callInfo, &CollatorObject::class_); case InlinableNative::IntlGuardToDateTimeFormat: return inlineGuardToClass(callInfo, &DateTimeFormatObject::class_); - case InlinableNative::IntlGuardToLocale: - return inlineGuardToClass(callInfo, &LocaleObject::class_); case InlinableNative::IntlGuardToNumberFormat: return inlineGuardToClass(callInfo, &NumberFormatObject::class_); case InlinableNative::IntlGuardToPluralRules: return inlineGuardToClass(callInfo, &PluralRulesObject::class_); case InlinableNative::IntlGuardToRelativeTimeFormat: return inlineGuardToClass(callInfo, &RelativeTimeFormatObject::class_); #else case InlinableNative::IntlGuardToCollator: case InlinableNative::IntlGuardToDateTimeFormat: - case InlinableNative::IntlGuardToLocale: case InlinableNative::IntlGuardToNumberFormat: case InlinableNative::IntlGuardToPluralRules: case InlinableNative::IntlGuardToRelativeTimeFormat: MOZ_CRASH("Intl API disabled"); #endif // Math natives. case InlinableNative::MathAbs:
--- a/js/src/moz.build +++ b/js/src/moz.build @@ -478,17 +478,16 @@ selfhosted_inputs = [ 'builtin/WeakSet.js' ] + ([ 'builtin/intl/Collator.js', 'builtin/intl/CommonFunctions.js', 'builtin/intl/CurrencyDataGenerated.js', 'builtin/intl/DateTimeFormat.js', 'builtin/intl/IntlObject.js', 'builtin/intl/LangTagMappingsGenerated.js', - 'builtin/intl/Locale.js', 'builtin/intl/NumberFormat.js', 'builtin/intl/PluralRules.js', 'builtin/intl/RelativeTimeFormat.js', 'builtin/intl/UnicodeExtensionsGenerated.js', ] if CONFIG['ENABLE_INTL_API'] else []) # Prepare self-hosted JS code for embedding GeneratedFile('selfhosted.out.h', 'selfhosted.js',
--- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2075,16 +2075,45 @@ static bool intrinsic_ToNumeric(JSContex MOZ_ASSERT(args.length() == 1); if (!ToNumeric(cx, args[0])) { return false; } args.rval().set(args[0]); return true; } +static bool intrinsic_LocaleToStringOrNull(JSContext* cx, unsigned argc, + Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + + if (!args[0].isObject()) { + args.rval().setNull(); + return true; + } + + JSObject* unwrapped = CheckedUnwrapStatic(&args[0].toObject()); + if (!unwrapped) { + ReportAccessDenied(cx); + return false; + } + + if (!unwrapped->is<NativeLocaleObject>()) { + args.rval().setNull(); + return true; + } + + RootedString str(cx, unwrapped->as<NativeLocaleObject>().languageTag()); + if (!cx->compartment()->wrap(cx, &str)) { + return false; + } + args.rval().setString(str); + return true; +} + // The self-hosting global isn't initialized with the normal set of builtins. // Instead, individual C++-implemented functions that're required by // self-hosted code are defined as global functions. Accessing these // functions via a content compartment's builtins would be unsafe, because // content script might have changed the builtins' prototypes' members. // Installing the whole set of builtins in the self-hosting compartment, OTOH, // would be wasteful: it increases memory usage and initialization time for // self-hosting compartment. @@ -2450,51 +2479,41 @@ static const JSFunctionSpec intrinsic_fu intl_PluralRules_availableLocales, 0, 0), JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 1, 0), JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2, 0), JS_FN("intl_RelativeTimeFormat_availableLocales", intl_RelativeTimeFormat_availableLocales, 0, 0), JS_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 4, 0), JS_FN("intl_toLocaleLowerCase", intl_toLocaleLowerCase, 2, 0), JS_FN("intl_toLocaleUpperCase", intl_toLocaleUpperCase, 2, 0), - JS_FN("intl_CreateUninitializedLocale", intl_CreateUninitializedLocale, 0, - 0), - JS_FN("intl_AddLikelySubtags", intl_AddLikelySubtags, 3, 0), - JS_FN("intl_RemoveLikelySubtags", intl_RemoveLikelySubtags, 3, 0), JS_INLINABLE_FN("GuardToCollator", intrinsic_GuardToBuiltin<CollatorObject>, 1, 0, IntlGuardToCollator), JS_INLINABLE_FN("GuardToDateTimeFormat", intrinsic_GuardToBuiltin<DateTimeFormatObject>, 1, 0, IntlGuardToDateTimeFormat), - JS_INLINABLE_FN("GuardToLocale", intrinsic_GuardToBuiltin<LocaleObject>, 1, - 0, IntlGuardToLocale), JS_INLINABLE_FN("GuardToNumberFormat", intrinsic_GuardToBuiltin<NumberFormatObject>, 1, 0, IntlGuardToNumberFormat), JS_INLINABLE_FN("GuardToPluralRules", intrinsic_GuardToBuiltin<PluralRulesObject>, 1, 0, IntlGuardToPluralRules), JS_INLINABLE_FN("GuardToRelativeTimeFormat", intrinsic_GuardToBuiltin<RelativeTimeFormatObject>, 1, 0, IntlGuardToRelativeTimeFormat), JS_FN("IsWrappedDateTimeFormat", intrinsic_IsWrappedInstanceOfBuiltin<DateTimeFormatObject>, 1, 0), - JS_FN("IsWrappedLocale", intrinsic_IsWrappedInstanceOfBuiltin<LocaleObject>, - 1, 0), JS_FN("IsWrappedNumberFormat", intrinsic_IsWrappedInstanceOfBuiltin<NumberFormatObject>, 1, 0), JS_FN("CallCollatorMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<CollatorObject>>, 2, 0), JS_FN("CallDateTimeFormatMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<DateTimeFormatObject>>, 2, 0), - JS_FN("CallLocaleMethodIfWrapped", - CallNonGenericSelfhostedMethod<Is<LocaleObject>>, 2, 0), JS_FN("CallNumberFormatMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<NumberFormatObject>>, 2, 0), JS_FN("CallPluralRulesMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<PluralRulesObject>>, 2, 0), JS_FN("CallRelativeTimeFormatMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<RelativeTimeFormatObject>>, 2, 0), JS_FN("GetDateTimeFormatConstructor", @@ -2504,16 +2523,18 @@ static const JSFunctionSpec intrinsic_fu JS_FN("GetNumberFormatConstructor", intrinsic_GetBuiltinIntlConstructor< GlobalObject::getOrCreateNumberFormatConstructor>, 0, 0), JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0, 0), JS_FN("IsRuntimeDefaultLocale", intrinsic_IsRuntimeDefaultLocale, 1, 0), #endif // ENABLE_INTL_API + JS_FN("LocaleToStringOrNull", intrinsic_LocaleToStringOrNull, 1, 0), + JS_FN("GetOwnPropertyDescriptorToArray", GetOwnPropertyDescriptorToArray, 2, 0), JS_INLINABLE_FN("IsRegExpObject", intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1, 0, IsRegExpObject), JS_FN("CallRegExpMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2, 0),