Bug 1570370 - Part 4: Rename NativeLocaleObject to LocaleObject. r=jwalden
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 11 Oct 2019 20:06:32 +0000
changeset 497334 22ff988b77c6218bd6556702bb926898869b7ecb
parent 497333 64993f76caaf72ed630c44da86250d06dda52ccd
child 497335 f22fdbd968ed04fedd47c406db2678fa5ae1205e
push id97818
push usercbrindusan@mozilla.com
push dateFri, 11 Oct 2019 21:39:29 +0000
treeherderautoland@614162937d31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1570370
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1570370 - Part 4: Rename NativeLocaleObject to LocaleObject. r=jwalden Differential Revision: https://phabricator.services.mozilla.com/D40070
js/public/Class.h
js/src/builtin/intl/LanguageTag.cpp
js/src/builtin/intl/Locale.cpp
js/src/builtin/intl/Locale.h
js/src/builtin/intl/NativeLocale.cpp
js/src/moz.build
js/src/vm/GlobalObject.h
js/src/vm/SelfHosting.cpp
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -745,17 +745,17 @@ static const uint32_t JSCLASS_FOREGROUND
 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
 // previously allowed, but is now an ES5 violation and thus unsupported.
 //
 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
 // the beginning of every global object's slots for use by the
 // application.
 static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS = 5;
 static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT =
-    JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 41;
+    JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 40;
 
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
   (JSCLASS_IS_GLOBAL |                     \
    JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \
   (((clasp)->flags & JSCLASS_IS_GLOBAL) &&       \
    JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
--- a/js/src/builtin/intl/LanguageTag.cpp
+++ b/js/src/builtin/intl/LanguageTag.cpp
@@ -757,25 +757,25 @@ bool LanguageTag::canonicalizeTransformE
 bool LanguageTag::appendTo(JSContext* cx, StringBuffer& sb) const {
   return LanguageTagToString(cx, *this, sb);
 }
 
 // Zero-terminated ICU Locale ID.
 using LocaleId =
     js::Vector<char, LanguageLength + 1 + ScriptLength + 1 + RegionLength + 1>;
 
-enum class LikelySubtags2 : bool { Add, Remove };
+enum class LikelySubtags : bool { Add, Remove };
 
 // Return true iff the language tag is already maximized resp. minimized.
-static bool HasLikelySubtags(LikelySubtags2 likelySubtags,
+static bool HasLikelySubtags(LikelySubtags likelySubtags,
                              const LanguageTag& tag) {
   // The language tag is already maximized if the language, script, and region
   // subtags are present and no placeholder subtags ("und", "Zzzz", "ZZ") are
   // used.
-  if (likelySubtags == LikelySubtags2::Add) {
+  if (likelySubtags == LikelySubtags::Add) {
     return !tag.language().equalTo("und") &&
            (tag.script().length() > 0 && !tag.script().equalTo("Zzzz")) &&
            (tag.region().length() > 0 && !tag.region().equalTo("ZZ"));
   }
 
   // The language tag is already minimized if it only contains a language
   // subtag whose value is not the placeholder value "und".
   return !tag.language().equalTo("und") && tag.script().length() == 0 &&
@@ -855,18 +855,18 @@ static bool AssignFromLocaleId(JSContext
   tag.setLanguage(localeTag.language());
   tag.setScript(localeTag.script());
   tag.setRegion(localeTag.region());
 
   return true;
 }
 
 template <decltype(uloc_addLikelySubtags) likelySubtagsFn>
-static bool CallLikelySubtags2(JSContext* cx, const LocaleId& localeId,
-                               LocaleId& result) {
+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(
@@ -901,18 +901,18 @@ static bool CallLikelySubtags2(JSContext
 //    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 valid language, script, and region subtags, we can avoid both
 // calls if we implement them ourselves, see CreateLocaleForLikelySubtags() and
 // AssignFromLocaleId(). (Where "slow" means about 50% of the execution time of
 // |Intl.Locale.prototype.maximize|.)
-static bool LikelySubtags2(JSContext* cx, LikelySubtags2 likelySubtags,
-                           LanguageTag& tag) {
+static bool LikelySubtags(JSContext* cx, LikelySubtags likelySubtags,
+                          LanguageTag& tag) {
   // Return early if the input is already maximized/minimized.
   if (HasLikelySubtags(likelySubtags, tag)) {
     return true;
   }
 
   // Create the locale ID for the input argument.
   LocaleId locale(cx);
   if (!CreateLocaleForLikelySubtags(tag, locale)) {
@@ -924,56 +924,56 @@ static bool LikelySubtags2(JSContext* cx
   // 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 == LikelySubtags2::Add ||
-                          !HasLikelySubtags(LikelySubtags2::Add, tag);
+  bool addLikelySubtags = likelySubtags == LikelySubtags::Add ||
+                          !HasLikelySubtags(LikelySubtags::Add, tag);
 
   if (addLikelySubtags) {
-    if (!CallLikelySubtags2<uloc_addLikelySubtags>(cx, locale,
-                                                   localeLikelySubtags)) {
+    if (!CallLikelySubtags<uloc_addLikelySubtags>(cx, locale,
+                                                  localeLikelySubtags)) {
       return false;
     }
   }
 
   // Now that we've succesfully maximized the locale, we can minimize it.
-  if (likelySubtags == LikelySubtags2::Remove) {
+  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 (!CallLikelySubtags2<uloc_minimizeSubtags>(cx, locale,
-                                                  localeLikelySubtags)) {
+    if (!CallLikelySubtags<uloc_minimizeSubtags>(cx, locale,
+                                                 localeLikelySubtags)) {
       return false;
     }
   }
 
   // Assign the language, script, and region subtags from the locale ID.
   if (!AssignFromLocaleId(cx, localeLikelySubtags, tag)) {
     return false;
   }
 
   // Update mappings in case ICU returned a non-canonical locale.
   return tag.canonicalizeBaseName(cx);
 }
 
 bool LanguageTag::addLikelySubtags(JSContext* cx) {
-  return LikelySubtags2(cx, LikelySubtags2::Add, *this);
+  return LikelySubtags(cx, LikelySubtags::Add, *this);
 }
 
 bool LanguageTag::removeLikelySubtags(JSContext* cx) {
-  return LikelySubtags2(cx, LikelySubtags2::Remove, *this);
+  return LikelySubtags(cx, LikelySubtags::Remove, *this);
 }
 
 LanguageTagParser::Token LanguageTagParser::nextToken() {
   MOZ_ASSERT(index_ <= length_ + 1, "called after 'None' token was read");
 
   TokenKind kind = TokenKind::None;
   size_t tokenLength = 0;
   for (size_t i = index_; i < length_; i++) {
deleted file mode 100644
--- a/js/src/builtin/intl/Locale.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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 implementation. */
-
-#include "builtin/intl/Locale.h"
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Maybe.h"
-#include "mozilla/Range.h"
-#include "mozilla/TextUtils.h"
-
-#include <algorithm>
-#include <iterator>
-#include <utility>
-
-#include "jsapi.h"
-
-#include "builtin/intl/CommonFunctions.h"
-#include "js/TypeDecls.h"
-#include "unicode/uloc.h"
-#include "unicode/utypes.h"
-#include "vm/GlobalObject.h"
-#include "vm/JSContext.h"
-#include "vm/StringType.h"
-
-#include "vm/JSObject-inl.h"
-#include "vm/NativeObject-inl.h"
-
-using namespace js;
-
-/* static */ bool js::GlobalObject::addLocaleConstructor(JSContext* cx,
-                                                         HandleObject intl) {
-  Handle<GlobalObject*> global = cx->global();
-
-  {
-    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;
-    }
-  }
-
-  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);
-}
--- a/js/src/builtin/intl/Locale.h
+++ b/js/src/builtin/intl/Locale.h
@@ -12,17 +12,17 @@
 #include "builtin/SelfHostingDefines.h"
 #include "js/Class.h"
 #include "vm/NativeObject.h"
 
 namespace js {
 
 class GlobalObject;
 
-class NativeLocaleObject : public NativeObject {
+class LocaleObject : 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;
 
@@ -40,15 +40,15 @@ class NativeLocaleObject : public Native
    */
   JSString* baseName() const { return getFixedSlot(BASENAME_SLOT).toString(); }
 
   const Value& unicodeExtension() const {
     return getFixedSlot(UNICODE_EXTENSION_SLOT);
   }
 };
 
-extern JSObject* CreateNativeLocalePrototype(JSContext* cx,
-                                             JS::Handle<JSObject*> Intl,
-                                             JS::Handle<GlobalObject*> global);
+extern JSObject* CreateLocalePrototype(JSContext* cx,
+                                       JS::Handle<JSObject*> Intl,
+                                       JS::Handle<GlobalObject*> global);
 
 }  // namespace js
 
 #endif /* builtin_intl_Locale_h */
--- a/js/src/builtin/intl/NativeLocale.cpp
+++ b/js/src/builtin/intl/NativeLocale.cpp
@@ -40,21 +40,21 @@
 using namespace js;
 using namespace js::intl::LanguageTagLimits;
 
 using intl::LanguageTag;
 using intl::LanguageTagParser;
 
 const JSClass NativeLocaleObject::class_ = {
     js_Object_str,
-    JSCLASS_HAS_RESERVED_SLOTS(NativeLocaleObject::SLOT_COUNT),
+    JSCLASS_HAS_RESERVED_SLOTS(LocaleObject::SLOT_COUNT),
 };
 
 static inline bool IsLocale(HandleValue v) {
-  return v.isObject() && v.toObject().is<NativeLocaleObject>();
+  return v.isObject() && v.toObject().is<LocaleObject>();
 }
 
 // Return the length of the base-name subtags.
 static size_t BaseNameLength(const LanguageTag& tag) {
   size_t baseNameLength = tag.language().length();
   if (tag.script().length() > 0) {
     baseNameLength += 1 + tag.script().length();
   }
@@ -90,22 +90,21 @@ static mozilla::Maybe<IndexAndLength> Un
     }
 
     // Add +1 to skip over the preceding separator.
     index += 1 + extensionLength;
   }
   return mozilla::Nothing();
 }
 
-static NativeLocaleObject* CreateLocaleNativeObject(JSContext* cx,
-                                                    HandleObject prototype,
+static LocaleObject* CreateLocaleObject(JSContext* cx, HandleObject prototype,
                                                     const LanguageTag& tag) {
   RootedObject proto(cx, prototype);
   if (!proto) {
-    proto = GlobalObject::getOrCreateLocaleNativePrototype(cx, cx->global());
+    proto = GlobalObject::getOrCreateLocalePrototype(cx, cx->global());
     if (!proto) {
       return nullptr;
     }
   }
 
   JSStringBuilder sb(cx);
   if (!tag.appendTo(cx, sb)) {
     return nullptr;
@@ -129,27 +128,24 @@ static NativeLocaleObject* CreateLocaleN
         cx, tagStr, baseNameLength + 1 + result->index, result->length);
     if (!str) {
       return nullptr;
     }
 
     unicodeExtension.setString(str);
   }
 
-  auto* locale = NewObjectWithGivenProto<NativeLocaleObject>(cx, proto);
+  auto* locale = NewObjectWithGivenProto<LocaleObject>(cx, proto);
   if (!locale) {
     return nullptr;
   }
 
-  locale->setFixedSlot(NativeLocaleObject::LANGUAGE_TAG_SLOT,
-                       StringValue(tagStr));
-  locale->setFixedSlot(NativeLocaleObject::BASENAME_SLOT,
-                       StringValue(baseName));
-  locale->setFixedSlot(NativeLocaleObject::UNICODE_EXTENSION_SLOT,
-                       unicodeExtension);
+  locale->setFixedSlot(LocaleObject::LANGUAGE_TAG_SLOT, StringValue(tagStr));
+  locale->setFixedSlot(LocaleObject::BASENAME_SLOT, StringValue(baseName));
+  locale->setFixedSlot(LocaleObject::UNICODE_EXTENSION_SLOT, unicodeExtension);
 
   return locale;
 }
 
 static inline bool IsValidUnicodeExtensionValue(JSLinearString* linear) {
   return linear->length() > 0 &&
          LanguageTagParser::canParseUnicodeExtensionType(linear);
 }
@@ -488,17 +484,17 @@ static bool ApplyUnicodeExtensionToTag(J
     return false;
   }
   return tag.setUnicodeExtension(std::move(newExtensionChars));
 }
 
 /**
  * Intl.Locale( tag[, options] )
  */
-static bool NativeLocale(JSContext* cx, unsigned argc, Value* vp) {
+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).
@@ -513,27 +509,27 @@ static bool NativeLocale(JSContext* cx, 
                               JSMSG_INVALID_LOCALES_ELEMENT);
     return false;
   }
 
   // Steps 8-9.
   RootedString tagStr(cx);
   if (args[0].isObject()) {
     JSObject* obj = &args[0].toObject();
-    if (obj->is<NativeLocaleObject>()) {
-      tagStr = obj->as<NativeLocaleObject>().languageTag();
+    if (obj->is<LocaleObject>()) {
+      tagStr = obj->as<LocaleObject>().languageTag();
     } else {
       JSObject* unwrapped = CheckedUnwrapStatic(obj);
       if (!unwrapped) {
         ReportAccessDenied(cx);
         return false;
       }
 
-      if (unwrapped->is<NativeLocaleObject>()) {
-        tagStr = unwrapped->as<NativeLocaleObject>().languageTag();
+      if (unwrapped->is<LocaleObject>()) {
+        tagStr = unwrapped->as<LocaleObject>().languageTag();
         if (!cx->compartment()->wrap(cx, &tagStr)) {
           return false;
         }
       } else {
         tagStr = ToString(cx, args[0]);
         if (!tagStr) {
           return false;
         }
@@ -682,17 +678,17 @@ static bool NativeLocale(JSContext* cx, 
   // ApplyOptionsToTag, steps 9 and 13.
   // ApplyUnicodeExtensionToTag, step 8.
   if (!tag.canonicalizeExtensions(
           cx, LanguageTag::UnicodeExtensionCanonicalForm::Yes)) {
     return false;
   }
 
   // Steps 6, 31-37.
-  JSObject* obj = CreateLocaleNativeObject(cx, proto, tag);
+  JSObject* obj = CreateLocaleObject(cx, proto, tag);
   if (!obj) {
     return false;
   }
 
   // Step 38.
   args.rval().setObject(*obj);
   return true;
 }
@@ -758,17 +754,17 @@ static inline auto FindUnicodeExtensionT
              ? FindUnicodeExtensionType(unicodeExtension->latin1Chars(nogc),
                                         unicodeExtension->length(), key)
              : FindUnicodeExtensionType(unicodeExtension->twoByteChars(nogc),
                                         unicodeExtension->length(), key);
 }
 
 // Return the sequence of types for the Unicode extension keyword specified by
 // key or undefined when the keyword isn't present.
-static bool GetUnicodeExtension(JSContext* cx, NativeLocaleObject* locale,
+static bool GetUnicodeExtension(JSContext* cx, LocaleObject* locale,
                                 UnicodeKey key, MutableHandleValue value) {
   // Return undefined when no Unicode extension subtag is present.
   const Value& unicodeExtensionValue = locale->unicodeExtension();
   if (unicodeExtensionValue.isUndefined()) {
     value.setUndefined();
     return true;
   }
 
@@ -871,33 +867,33 @@ static inline auto BaseNameParts(JSLinea
              : BaseNameParts(baseName->twoByteChars(nogc), baseName->length());
 }
 
 // Intl.Locale.prototype.maximize ()
 static bool Locale_maximize(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   RootedLinearString tagStr(cx, locale->languageTag()->ensureLinear(cx));
   if (!tagStr) {
     return false;
   }
 
   LanguageTag tag(cx);
   if (!LanguageTagParser::parse(cx, tagStr, tag)) {
     return false;
   }
 
   if (!tag.addLikelySubtags(cx)) {
     return false;
   }
 
   // Step 4.
-  auto* result = CreateLocaleNativeObject(cx, nullptr, tag);
+  auto* result = CreateLocaleObject(cx, nullptr, tag);
   if (!result) {
     return false;
   }
   args.rval().setObject(*result);
   return true;
 }
 
 // Intl.Locale.prototype.maximize ()
@@ -907,33 +903,33 @@ static bool Locale_maximize(JSContext* c
   return CallNonGenericMethod<IsLocale, Locale_maximize>(cx, args);
 }
 
 // Intl.Locale.prototype.minimize ()
 static bool Locale_minimize(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   RootedLinearString tagStr(cx, locale->languageTag()->ensureLinear(cx));
   if (!tagStr) {
     return false;
   }
 
   LanguageTag tag(cx);
   if (!LanguageTagParser::parse(cx, tagStr, tag)) {
     return false;
   }
 
   if (!tag.removeLikelySubtags(cx)) {
     return false;
   }
 
   // Step 4.
-  auto* result = CreateLocaleNativeObject(cx, nullptr, tag);
+  auto* result = CreateLocaleObject(cx, nullptr, tag);
   if (!result) {
     return false;
   }
   args.rval().setObject(*result);
   return true;
 }
 
 // Intl.Locale.prototype.minimize ()
@@ -943,17 +939,17 @@ static bool Locale_minimize(JSContext* c
   return CallNonGenericMethod<IsLocale, Locale_minimize>(cx, args);
 }
 
 // Intl.Locale.prototype.toString ()
 static bool Locale_toString(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   args.rval().setString(locale->languageTag());
   return true;
 }
 
 // Intl.Locale.prototype.toString ()
 static bool Locale_toString(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
@@ -963,98 +959,98 @@ static bool Locale_toString(JSContext* c
 // get Intl.Locale.prototype.baseName
 static bool Locale_baseName(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // FIXME: spec bug - invalid assertion in step 4.
   // FIXME: spec bug - subtag production names not updated.
 
   // Steps 3, 5.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   args.rval().setString(locale->baseName());
   return true;
 }
 
 // get Intl.Locale.prototype.baseName
 static bool Locale_baseName(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod<IsLocale, Locale_baseName>(cx, args);
 }
 
 // get Intl.Locale.prototype.calendar
 static bool Locale_calendar(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   return GetUnicodeExtension(cx, locale, "ca", args.rval());
 }
 
 // get Intl.Locale.prototype.calendar
 static bool Locale_calendar(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod<IsLocale, Locale_calendar>(cx, args);
 }
 
 // get Intl.Locale.prototype.collation
 static bool Locale_collation(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   return GetUnicodeExtension(cx, locale, "co", args.rval());
 }
 
 // get Intl.Locale.prototype.collation
 static bool Locale_collation(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod<IsLocale, Locale_collation>(cx, args);
 }
 
 // get Intl.Locale.prototype.hourCycle
 static bool Locale_hourCycle(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   return GetUnicodeExtension(cx, locale, "hc", args.rval());
 }
 
 // get Intl.Locale.prototype.hourCycle
 static bool Locale_hourCycle(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod<IsLocale, Locale_hourCycle>(cx, args);
 }
 
 // get Intl.Locale.prototype.caseFirst
 static bool Locale_caseFirst(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   return GetUnicodeExtension(cx, locale, "kf", args.rval());
 }
 
 // get Intl.Locale.prototype.caseFirst
 static bool Locale_caseFirst(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod<IsLocale, Locale_caseFirst>(cx, args);
 }
 
 // get Intl.Locale.prototype.numeric
 static bool Locale_numeric(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   RootedValue value(cx);
   if (!GetUnicodeExtension(cx, locale, "kn", &value)) {
     return false;
   }
 
   // FIXME: spec bug - comparison should be against the empty string, too.
   MOZ_ASSERT(value.isUndefined() || value.isString());
   args.rval().setBoolean(value.isString() && value.toString()->empty());
@@ -1068,33 +1064,33 @@ static bool Locale_numeric(JSContext* cx
   return CallNonGenericMethod<IsLocale, Locale_numeric>(cx, args);
 }
 
 // get Intl.Locale.prototype.numberingSystem
 static bool Intl_Locale_numberingSystem(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   return GetUnicodeExtension(cx, locale, "nu", args.rval());
 }
 
 // get Intl.Locale.prototype.numberingSystem
 static bool Locale_numberingSystem(JSContext* cx, unsigned argc, Value* vp) {
   // Steps 1-2.
   CallArgs args = CallArgsFromVp(argc, vp);
   return CallNonGenericMethod<IsLocale, Intl_Locale_numberingSystem>(cx, args);
 }
 
 // get Intl.Locale.prototype.language
 static bool Locale_language(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   JSLinearString* baseName = locale->baseName()->ensureLinear(cx);
   if (!baseName) {
     return false;
   }
 
   // Step 4 (Unnecessary assertion).
 
   auto language = BaseNameParts(baseName).language;
@@ -1120,17 +1116,17 @@ static bool Locale_language(JSContext* c
   return CallNonGenericMethod<IsLocale, Locale_language>(cx, args);
 }
 
 // get Intl.Locale.prototype.script
 static bool Locale_script(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   JSLinearString* baseName = locale->baseName()->ensureLinear(cx);
   if (!baseName) {
     return false;
   }
 
   // Step 4 (Unnecessary assertion).
 
   auto script = BaseNameParts(baseName).script;
@@ -1162,17 +1158,17 @@ static bool Locale_script(JSContext* cx,
   return CallNonGenericMethod<IsLocale, Locale_script>(cx, args);
 }
 
 // get Intl.Locale.prototype.region
 static bool Locale_region(JSContext* cx, const CallArgs& args) {
   MOZ_ASSERT(IsLocale(args.thisv()));
 
   // Step 3.
-  auto* locale = &args.thisv().toObject().as<NativeLocaleObject>();
+  auto* locale = &args.thisv().toObject().as<LocaleObject>();
   JSLinearString* baseName = locale->baseName()->ensureLinear(cx);
   if (!baseName) {
     return false;
   }
 
   // Step 4 (Unnecessary assertion).
 
   auto region = BaseNameParts(baseName).region;
@@ -1204,58 +1200,87 @@ static bool Locale_region(JSContext* cx,
 }
 
 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_native_methods[] = {
+static const JSFunctionSpec locale_methods[] = {
     JS_FN("maximize", Locale_maximize, 0, 0),
     JS_FN("minimize", Locale_minimize, 0, 0),
     JS_FN(js_toString_str, Locale_toString, 0, 0),
     JS_FN(js_toSource_str, Locale_toSource, 0, 0), JS_FS_END};
 
-static const JSPropertySpec locale_native_properties[] = {
+static const JSPropertySpec locale_properties[] = {
     JS_PSG("baseName", Locale_baseName, 0),
     JS_PSG("calendar", Locale_calendar, 0),
     JS_PSG("collation", Locale_collation, 0),
     JS_PSG("hourCycle", Locale_hourCycle, 0),
     JS_PSG("caseFirst", Locale_caseFirst, 0),
     JS_PSG("numeric", Locale_numeric, 0),
     JS_PSG("numberingSystem", Locale_numberingSystem, 0),
     JS_PSG("language", Locale_language, 0),
     JS_PSG("script", Locale_script, 0),
     JS_PSG("region", Locale_region, 0),
     JS_STRING_SYM_PS(toStringTag, "Intl.Locale", JSPROP_READONLY),
     JS_PS_END};
 
-JSObject* js::CreateNativeLocalePrototype(JSContext* cx, HandleObject Intl,
+JSObject* js::CreateLocalePrototype(JSContext* cx, HandleObject Intl,
                                           Handle<GlobalObject*> global) {
-  RootedFunction ctor(cx, GlobalObject::createConstructor(
-                              cx, &NativeLocale, cx->names().Locale, 1));
+  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_native_properties,
-                                    locale_native_methods)) {
+  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));
+  return true;
+}
+
+bool js::AddLocaleConstructor(JSContext* cx, JS::Handle<JSObject*> intl) {
+  return GlobalObject::addLocaleConstructor(cx, intl);
+}
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -377,17 +377,16 @@ SOURCES += [
 if CONFIG['ENABLE_INTL_API']:
     UNIFIED_SOURCES += [
         'builtin/intl/Collator.cpp',
         'builtin/intl/CommonFunctions.cpp',
         'builtin/intl/DateTimeFormat.cpp',
         'builtin/intl/IntlObject.cpp',
         'builtin/intl/LanguageTag.cpp',
         'builtin/intl/LanguageTagGenerated.cpp',
-        'builtin/intl/Locale.cpp',
         'builtin/intl/NativeLocale.cpp',
         'builtin/intl/NumberFormat.cpp',
         'builtin/intl/PluralRules.cpp',
         'builtin/intl/RelativeTimeFormat.cpp',
         'builtin/intl/SharedIntlData.cpp',
         'builtin/intl/UnicodeExtensionsGenerated.cpp',
     ]
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -91,17 +91,16 @@ class GlobalObject : public NativeObject
     COLLATOR_PROTO,
     NUMBER_FORMAT,
     NUMBER_FORMAT_PROTO,
     DATE_TIME_FORMAT,
     DATE_TIME_FORMAT_PROTO,
     PLURAL_RULES_PROTO,
     RELATIVE_TIME_FORMAT_PROTO,
     LOCALE_PROTO,
-    NATIVE_LOCALE_PROTO,
     MODULE_PROTO,
     IMPORT_ENTRY_PROTO,
     EXPORT_ENTRY_PROTO,
     REQUESTED_MODULE_PROTO,
     REGEXP_STATICS,
     RUNTIME_CODEGEN_ENABLED,
     DEBUGGERS,
     INTRINSICS,
@@ -545,21 +544,16 @@ class GlobalObject : public NativeObject
   }
 
   static JSObject* getOrCreateLocalePrototype(JSContext* cx,
                                               Handle<GlobalObject*> global) {
     return getOrCreateObject(cx, global, LOCALE_PROTO, initIntlObject);
   }
 #endif  // ENABLE_INTL_API
 
-  static JSObject* getOrCreateLocaleNativePrototype(
-      JSContext* cx, Handle<GlobalObject*> global) {
-    return getOrCreateObject(cx, global, NATIVE_LOCALE_PROTO, initIntlObject);
-  }
-
   static bool ensureModulePrototypesCreated(JSContext* cx,
                                             Handle<GlobalObject*> global);
 
   static JSObject* getOrCreateModulePrototype(JSContext* cx,
                                               Handle<GlobalObject*> global) {
     return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto);
   }
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2091,22 +2091,22 @@ static bool intrinsic_LocaleToStringOrNu
   }
 
   JSObject* unwrapped = CheckedUnwrapStatic(&args[0].toObject());
   if (!unwrapped) {
     ReportAccessDenied(cx);
     return false;
   }
 
-  if (!unwrapped->is<NativeLocaleObject>()) {
+  if (!unwrapped->is<LocaleObject>()) {
     args.rval().setNull();
     return true;
   }
 
-  RootedString str(cx, unwrapped->as<NativeLocaleObject>().languageTag());
+  RootedString str(cx, unwrapped->as<LocaleObject>().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.