Bug 1288457 - Part 3: Change Intl.Locale to use ClassSpec. r=mgaudet
authorAndré Bargull <andre.bargull@gmail.com>
Wed, 16 Oct 2019 12:31:14 +0000
changeset 559196 89d7388251d19dd0a339b9476def7e1c79287037
parent 559195 aebd85991cc4c28c4657e156b718534a0454cea8
child 559197 f464ebe632fd7d28ab0ee09461afe4c114235467
push id12175
push userccoroiu@mozilla.com
push dateThu, 17 Oct 2019 19:29:09 +0000
treeherdermozilla-beta@d333b6ef1fd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmgaudet
bugs1288457
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 1288457 - Part 3: Change Intl.Locale to use ClassSpec. r=mgaudet Differential Revision: https://phabricator.services.mozilla.com/D42872
js/public/Class.h
js/public/ProtoKey.h
js/src/builtin/intl/Locale.cpp
js/src/builtin/intl/Locale.h
js/src/jsfriendapi.h
js/src/vm/CommonPropertyNames.h
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
--- 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 + 37;
+    JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 36;
 
 #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/public/ProtoKey.h
+++ b/js/public/ProtoKey.h
@@ -126,17 +126,18 @@
        &js::CountQueuingStrategy::class_)                                    \
   REAL(WebAssembly, InitWebAssemblyClass, CLASP(WebAssembly))                \
   IMAGINARY(WasmModule, dummy, dummy)                                        \
   IMAGINARY(WasmInstance, dummy, dummy)                                      \
   IMAGINARY(WasmMemory, dummy, dummy)                                        \
   IMAGINARY(WasmTable, dummy, dummy)                                         \
   IMAGINARY(WasmGlobal, dummy, dummy)                                        \
   REAL_IF_INTL(Collator, InitViaClassSpec, OCLASP(Collator))                 \
-  REAL_IF_INTL(DateTimeFormat, InitViaClassSpec, OCLASP(DateTimeFormat))
+  REAL_IF_INTL(DateTimeFormat, InitViaClassSpec, OCLASP(DateTimeFormat))     \
+  REAL_IF_INTL(Locale, InitViaClassSpec, OCLASP(Locale))
 
 #define JS_FOR_PROTOTYPES(REAL, IMAGINARY)                      \
   JS_FOR_PROTOTYPES_(REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), \
                      IF_TYPEDOBJ(REAL, IMAGINARY), IF_SAB(REAL, IMAGINARY))
 
 #define JS_FOR_EACH_PROTOTYPE(MACRO) JS_FOR_PROTOTYPES(MACRO, MACRO)
 
 #endif /* js_ProtoKey_h */
--- a/js/src/builtin/intl/Locale.cpp
+++ b/js/src/builtin/intl/Locale.cpp
@@ -41,19 +41,20 @@
 
 using namespace js;
 using namespace js::intl::LanguageTagLimits;
 
 using intl::LanguageTag;
 using intl::LanguageTagParser;
 
 const JSClass LocaleObject::class_ = {
-    js_Object_str,
-    JSCLASS_HAS_RESERVED_SLOTS(LocaleObject::SLOT_COUNT),
-};
+    js_Object_str, JSCLASS_HAS_RESERVED_SLOTS(LocaleObject::SLOT_COUNT),
+    JS_NULL_CLASS_OPS, &LocaleObject::classSpec_};
+
+const JSClass& LocaleObject::protoClass_ = PlainObject::class_;
 
 static inline bool IsLocale(HandleValue v) {
   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();
@@ -516,17 +517,17 @@ static bool Locale(JSContext* cx, unsign
 
   // 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)) {
+  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Locale, &proto)) {
     return false;
   }
 
   // Steps 7-9.
   HandleValue tagValue = args.get(0);
   JSString* tagStr;
   if (tagValue.isObject()) {
     JS_TRY_VAR_OR_RETURN_FALSE(
@@ -1227,74 +1228,38 @@ static const JSPropertySpec locale_prope
     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::CreateLocalePrototype(JSContext* cx, HandleObject Intl,
-                                    Handle<GlobalObject*> global) {
-  RootedFunction ctor(
-      cx, GlobalObject::createConstructor(cx, &Locale, cx->names().Locale, 1));
-  if (!ctor) {
-    return nullptr;
-  }
+const ClassSpec LocaleObject::classSpec_ = {
+    GenericCreateConstructor<Locale, 1, gc::AllocKind::FUNCTION>,
+    GenericCreatePrototype<LocaleObject>,
+    nullptr,
+    nullptr,
+    locale_methods,
+    locale_properties,
+    nullptr,
+    ClassSpec::DontDefineConstructor};
 
-  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;
+bool js::CreateLocale(JSContext* cx, HandleObject Intl) {
+  JSObject* ctor = GlobalObject::getOrCreateConstructor(cx, JSProto_Locale);
+  if (!ctor) {
+    return false;
   }
 
   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;
+  return DefineDataProperty(cx, Intl, cx->names().Locale, ctorValue, 0);
 }
 
 bool js::AddLocaleConstructor(JSContext* cx, JS::Handle<JSObject*> intl) {
-  return GlobalObject::addLocaleConstructor(cx, intl);
+  return CreateLocale(cx, intl);
 }
 
 bool js::intl_ValidateAndCanonicalizeLanguageTag(JSContext* cx, unsigned argc,
                                                  Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   MOZ_ASSERT(args.length() == 2);
 
   HandleValue tagValue = args[0];
--- a/js/src/builtin/intl/Locale.h
+++ b/js/src/builtin/intl/Locale.h
@@ -10,21 +10,20 @@
 #include <stdint.h>
 
 #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 const JSClass& protoClass_;
 
   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;
 
   /**
    * Returns the complete language tag, including any extensions and privateuse
@@ -38,21 +37,22 @@ class LocaleObject : public NativeObject
    * Returns the basename subtags, i.e. excluding any extensions and privateuse
    * subtags.
    */
   JSString* baseName() const { return getFixedSlot(BASENAME_SLOT).toString(); }
 
   const Value& unicodeExtension() const {
     return getFixedSlot(UNICODE_EXTENSION_SLOT);
   }
+
+ private:
+  static const ClassSpec classSpec_;
 };
 
-extern JSObject* CreateLocalePrototype(JSContext* cx,
-                                       JS::Handle<JSObject*> Intl,
-                                       JS::Handle<GlobalObject*> global);
+extern bool CreateLocale(JSContext* cx, JS::Handle<JSObject*> Intl);
 
 extern MOZ_MUST_USE bool intl_ValidateAndCanonicalizeLanguageTag(JSContext* cx,
                                                                  unsigned argc,
                                                                  Value* vp);
 
 extern MOZ_MUST_USE bool intl_TryValidateAndCanonicalizeLanguageTag(
     JSContext* cx, unsigned argc, Value* vp);
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2602,17 +2602,16 @@ extern JS_FRIEND_API JSObject* ToWindowI
 // and emphatically not shippable on the web, and it *must* be fixed before
 // this functionality can be exposed in the real world. (There are also some
 // questions about whether the format exposed here is the *right* one to
 // standardize, that will also need to be resolved to ship this.)
 extern bool AddMozDateTimeFormatConstructor(JSContext* cx,
                                             JS::Handle<JSObject*> intl);
 
 // Create and add the Intl.Locale constructor function to the provided object.
-// This function throws if called more than once per realm/global object.
 extern bool AddLocaleConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
 #endif  // ENABLE_INTL_API
 
 class MOZ_STACK_CLASS JS_FRIEND_API AutoAssertNoContentJS {
  public:
   explicit AutoAssertNoContentJS(JSContext* cx);
   ~AutoAssertNoContentJS();
 
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -261,17 +261,16 @@
   MACRO(language, language, "language")                                        \
   MACRO(lastIndex, lastIndex, "lastIndex")                                     \
   MACRO(length, length, "length")                                              \
   MACRO(let, let, "let")                                                       \
   MACRO(line, line, "line")                                                    \
   MACRO(lineNumber, lineNumber, "lineNumber")                                  \
   MACRO(literal, literal, "literal")                                           \
   MACRO(loc, loc, "loc")                                                       \
-  MACRO(Locale, Locale, "Locale")                                              \
   MACRO(locale, locale, "locale")                                              \
   MACRO(lookupGetter, lookupGetter, "__lookupGetter__")                        \
   MACRO(lookupSetter, lookupSetter, "__lookupSetter__")                        \
   MACRO(ltr, ltr, "ltr")                                                       \
   MACRO(MapConstructorInit, MapConstructorInit, "MapConstructorInit")          \
   MACRO(MapIterator, MapIterator, "Map Iterator")                              \
   MACRO(maxColumn, maxColumn, "maxColumn")                                     \
   MACRO(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -12,16 +12,17 @@
 
 #include "builtin/AtomicsObject.h"
 #include "builtin/BigInt.h"
 #include "builtin/DataViewObject.h"
 #include "builtin/Eval.h"
 #ifdef ENABLE_INTL_API
 #  include "builtin/intl/Collator.h"
 #  include "builtin/intl/DateTimeFormat.h"
+#  include "builtin/intl/Locale.h"
 #endif
 #include "builtin/MapObject.h"
 #include "builtin/ModuleObject.h"
 #include "builtin/Object.h"
 #include "builtin/Promise.h"
 #include "builtin/RegExp.h"
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/Stream.h"
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -87,17 +87,16 @@ class GlobalObject : public NativeObject
     ASYNC_GENERATOR_FUNCTION,
     ASYNC_GENERATOR_PROTO,
     MAP_ITERATOR_PROTO,
     SET_ITERATOR_PROTO,
     NUMBER_FORMAT,
     NUMBER_FORMAT_PROTO,
     PLURAL_RULES_PROTO,
     RELATIVE_TIME_FORMAT_PROTO,
-    LOCALE_PROTO,
     MODULE_PROTO,
     IMPORT_ENTRY_PROTO,
     EXPORT_ENTRY_PROTO,
     REQUESTED_MODULE_PROTO,
     REGEXP_STATICS,
     RUNTIME_CODEGEN_ENABLED,
     DEBUGGERS,
     INTRINSICS,
@@ -545,17 +544,20 @@ class GlobalObject : public NativeObject
   static JSObject* getOrCreateRelativeTimeFormatPrototype(
       JSContext* cx, Handle<GlobalObject*> global) {
     return getOrCreateObject(cx, global, RELATIVE_TIME_FORMAT_PROTO,
                              initIntlObject);
   }
 
   static JSObject* getOrCreateLocalePrototype(JSContext* cx,
                                               Handle<GlobalObject*> global) {
-    return getOrCreateObject(cx, global, LOCALE_PROTO, initIntlObject);
+    if (!ensureConstructor(cx, global, JSProto_Locale)) {
+      return nullptr;
+    }
+    return &global->getPrototype(JSProto_Locale).toObject();
   }
 #endif  // ENABLE_INTL_API
 
   static bool ensureModulePrototypesCreated(JSContext* cx,
                                             Handle<GlobalObject*> global);
 
   static JSObject* getOrCreateModulePrototype(JSContext* cx,
                                               Handle<GlobalObject*> global) {
@@ -851,19 +853,16 @@ class GlobalObject : public NativeObject
 
   // Implemented in builtin/MapObject.cpp.
   static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
   static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
 
 #ifdef ENABLE_INTL_API
   // Implemented in builtin/intl/IntlObject.cpp.
   static bool initIntlObject(JSContext* cx, Handle<GlobalObject*> global);
-
-  // Implemented in builtin/intl/Locale.cpp.
-  static bool addLocaleConstructor(JSContext* cx, HandleObject intl);
 #endif
 
   // Implemented in builtin/ModuleObject.cpp
   static bool initModuleProto(JSContext* cx, Handle<GlobalObject*> global);
   static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
   static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
   static bool initRequestedModuleProto(JSContext* cx,
                                        Handle<GlobalObject*> global);