Bug 1328386 - Part 1: Remove boilerplate code and add comments in Intl code. r=Waldo
authorAndré Bargull <andre.bargull@gmail.com>
Mon, 23 Jan 2017 08:33:27 -0800
changeset 331138 862bc2b2553e0a65ac080e49d4279f4faba4bc76
parent 331137 a50557f92553b859df03352edff970a97159aa24
child 331139 36ad679ec7dbdb6923ff0db88d0e9b720296527c
push id31261
push usercbook@mozilla.com
push dateThu, 26 Jan 2017 11:32:02 +0000
treeherdermozilla-central@a338e596b1d9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1328386
milestone54.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 1328386 - Part 1: Remove boilerplate code and add comments in Intl code. r=Waldo
js/src/builtin/Date.js
js/src/builtin/Intl.cpp
js/src/builtin/Intl.h
js/src/builtin/Intl.js
--- a/js/src/builtin/Date.js
+++ b/js/src/builtin/Date.js
@@ -99,17 +99,17 @@ function Date_toLocaleString() {
         // locales and options.
         dateTimeFormat = GetCachedFormat("dateTimeFormat", "any", "all");
     } else {
         options = ToDateTimeOptions(options, "any", "all");
         dateTimeFormat = intl_DateTimeFormat(locales, options);
     }
 
     // Step 7.
-    return intl_FormatDateTime(dateTimeFormat, x, false);
+    return intl_FormatDateTime(dateTimeFormat, x, /* formatToParts = */ false);
 }
 
 
 /**
  * Format this Date object into a date string, using the locale and formatting
  * options provided.
  *
  * Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.6.
@@ -132,17 +132,17 @@ function Date_toLocaleDateString() {
         // locales and options.
         dateTimeFormat = GetCachedFormat("dateFormat", "date", "date");
     } else {
         options = ToDateTimeOptions(options, "date", "date");
         dateTimeFormat = intl_DateTimeFormat(locales, options);
     }
 
     // Step 7.
-    return intl_FormatDateTime(dateTimeFormat, x, false);
+    return intl_FormatDateTime(dateTimeFormat, x, /* formatToParts = */ false);
 }
 
 
 /**
  * Format this Date object into a time string, using the locale and formatting
  * options provided.
  *
  * Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.7.
@@ -165,10 +165,10 @@ function Date_toLocaleTimeString() {
         // locales and options.
         dateTimeFormat = GetCachedFormat("timeFormat", "time", "time");
     } else {
         options = ToDateTimeOptions(options, "time", "time");
         dateTimeFormat = intl_DateTimeFormat(locales, options);
     }
 
     // Step 7.
-    return intl_FormatDateTime(dateTimeFormat, x, false);
+    return intl_FormatDateTime(dateTimeFormat, x, /* formatToParts = */ false);
 }
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -36,16 +36,17 @@
 #include "unicode/unum.h"
 #include "unicode/unumsys.h"
 #include "unicode/upluralrules.h"
 #include "unicode/ustring.h"
 #endif
 #include "vm/DateTime.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
 #include "vm/Stack.h"
 #include "vm/StringBuffer.h"
 #include "vm/Unicode.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/NativeObject-inl.h"
 
@@ -792,31 +793,25 @@ uplrules_select(const UPluralRules *uplr
 
 
 /******************** Common to Intl constructors ********************/
 
 static bool
 IntlInitialize(JSContext* cx, HandleObject obj, Handle<PropertyName*> initializer,
                HandleValue locales, HandleValue options)
 {
-    RootedValue initializerValue(cx);
-    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), initializer, &initializerValue))
-        return false;
-    MOZ_ASSERT(initializerValue.isObject());
-    MOZ_ASSERT(initializerValue.toObject().is<JSFunction>());
-
     FixedInvokeArgs<3> args(cx);
 
     args[0].setObject(*obj);
     args[1].set(locales);
     args[2].set(options);
 
     RootedValue thisv(cx, NullValue());
     RootedValue ignored(cx);
-    return js::Call(cx, initializerValue, thisv, args, &ignored);
+    return js::CallSelfHostedFunction(cx, initializer, thisv, args, &ignored);
 }
 
 static bool
 CreateDefaultOptions(JSContext* cx, MutableHandleValue defaultOptions)
 {
     RootedObject options(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
     if (!options)
         return false;
@@ -866,31 +861,22 @@ intl_availableLocales(JSContext* cx, Cou
 }
 
 /**
  * Returns the object holding the internal properties for obj.
  */
 static JSObject*
 GetInternals(JSContext* cx, HandleObject obj)
 {
-    RootedValue getInternalsValue(cx);
-    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().getInternals,
-                                         &getInternalsValue))
-    {
-        return nullptr;
-    }
-    MOZ_ASSERT(getInternalsValue.isObject());
-    MOZ_ASSERT(getInternalsValue.toObject().is<JSFunction>());
-
     FixedInvokeArgs<1> args(cx);
 
     args[0].setObject(*obj);
 
     RootedValue v(cx, NullValue());
-    if (!js::Call(cx, getInternalsValue, v, args, &v))
+    if (!js::CallSelfHostedFunction(cx, cx->names().getInternals, v, args, &v))
         return nullptr;
 
     return &v.toObject();
 }
 
 static bool
 equal(const char* s1, const char* s2)
 {
@@ -930,16 +916,17 @@ class ScopedICUObject
         ptr_ = nullptr;
         return tmp;
     }
 };
 
 // The inline capacity we use for the char16_t Vectors.
 static const size_t INITIAL_CHAR_BUFFER_SIZE = 32;
 
+
 /******************** Collator ********************/
 
 static void collator_finalize(FreeOp* fop, JSObject* obj);
 
 static const uint32_t UCOLLATOR_SLOT = 0;
 static const uint32_t COLLATOR_SLOTS_COUNT = 1;
 
 static const ClassOps CollatorClassOps = {
@@ -3571,16 +3558,17 @@ js::intl_FormatDateTime(JSContext* cx, u
     if (!isDateTimeFormatInstance)
         udat_close(df);
     if (!success)
         return false;
     args.rval().set(result);
     return true;
 }
 
+
 /**************** PluralRules *****************/
 
 static void pluralRules_finalize(FreeOp* fop, JSObject* obj);
 
 static const uint32_t UPLURAL_RULES_SLOT = 0;
 static const uint32_t PLURAL_RULES_SLOTS_COUNT = 1;
 
 static const ClassOps PluralRulesClassOps = {
@@ -3687,19 +3675,16 @@ CreatePluralRulesPrototype(JSContext* cx
     ctor = global->createConstructor(cx, &PluralRules, cx->names().PluralRules, 0);
     if (!ctor)
         return nullptr;
 
     RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global,
                                                                     &PluralRulesClass));
     if (!proto)
         return nullptr;
-    MOZ_ASSERT(proto->getReservedSlot(UPLURAL_RULES_SLOT).isUndefined(),
-               "improperly creating PluralRules more than once for a single "
-               "global?");
     proto->setReservedSlot(UPLURAL_RULES_SLOT, PrivateValue(nullptr));
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return nullptr;
 
     if (!JS_DefineFunctions(cx, ctor, pluralRules_static_methods))
         return nullptr;
 
@@ -3955,16 +3940,19 @@ js::intl_GetPluralCategories(JSContext* 
         if (!DefineElement(cx, res, i++, element))
             return false;
     } while (true);
 
     args.rval().setObject(*res);
     return true;
 }
 
+
+/******************** Intl ********************/
+
 bool
 js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
 
     JSAutoByteString locale(cx, args[0].toString());
     if (!locale)
@@ -4388,18 +4376,16 @@ js::intl_ComputeDisplayNames(JSContext* 
             return false;
     }
 
     // 6. Return result.
     args.rval().setObject(*result);
     return true;
 }
 
-/******************** Intl ********************/
-
 const Class js::IntlClass = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Intl)
 };
 
 #if JS_HAS_TOSOURCE
 static bool
 intl_toSource(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -257,17 +257,17 @@ extern MOZ_MUST_USE bool
 intl_numberingSystem(JSContext* cx, unsigned argc, Value* vp);
 
 /**
  * Returns a string representing the number x according to the effective
  * locale and the formatting options of the given NumberFormat.
  *
  * Spec: ECMAScript Internationalization API Specification, 11.3.2.
  *
- * Usage: formatted = intl_FormatNumber(numberFormat, x)
+ * Usage: formatted = intl_FormatNumber(numberFormat, x, formatToParts)
  */
 extern MOZ_MUST_USE bool
 intl_FormatNumber(JSContext* cx, unsigned argc, Value* vp);
 
 
 /******************** DateTimeFormat ********************/
 
 /**
@@ -353,21 +353,22 @@ intl_patternForSkeleton(JSContext* cx, u
 
 /**
  * Returns a String value representing x (which must be a Number value)
  * according to the effective locale and the formatting options of the
  * given DateTimeFormat.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.3.2.
  *
- * Usage: formatted = intl_FormatDateTime(dateTimeFormat, x)
+ * Usage: formatted = intl_FormatDateTime(dateTimeFormat, x, formatToParts)
  */
 extern MOZ_MUST_USE bool
 intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp);
 
+
 /******************** PluralRules ********************/
 
 /**
  * Returns an object indicating the supported locales for plural rules
  * by having a true-valued property for each such locale with the
  * canonicalized language tag as the property name. The object has no
  * prototype.
  *
@@ -396,16 +397,19 @@ intl_SelectPluralRule(JSContext* cx, uns
  *
  * Example:
  *
  * intl_getPluralCategories('pl', 'cardinal'); // ['one', 'few', 'many', 'other']
  */
 extern MOZ_MUST_USE bool
 intl_GetPluralCategories(JSContext* cx, unsigned argc, Value* vp);
 
+
+/******************** Intl ********************/
+
 /**
  * Returns a plain object with calendar information for a single valid locale
  * (callers must perform this validation).  The object will have these
  * properties:
  *
  *   firstDayOfWeek
  *     an integer in the range 1=Sunday to 7=Saturday indicating the day
  *     considered the first day of the week in calendars, e.g. 1 for en-US,
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -1355,31 +1355,31 @@ function getIntlObjectInternals(obj, cla
  * C++ code that knows what it's doing!
  */
 function getInternals(obj)
 {
     assert(isInitializedIntlObject(obj), "for use only on guaranteed Intl objects");
 
     var internals = callFunction(std_WeakMap_get, internalsMap, obj);
 
-    assert(internals.type !== "partial", "must have been successfully initialized");
-    var lazyData = internals.lazyData;
-    if (!lazyData)
-        return internals.internalProps;
-
-    var internalProps;
+    // If internal properties have already been computed, use them.
+    var internalProps = maybeInternalProperties(internals);
+    if (internalProps)
+        return internalProps;
+
+    // Otherwise it's time to fully create them.
     var type = internals.type;
     if (type === "Collator")
-        internalProps = resolveCollatorInternals(lazyData)
+        internalProps = resolveCollatorInternals(internals.lazyData)
     else if (type === "DateTimeFormat")
-        internalProps = resolveDateTimeFormatInternals(lazyData)
-    else if (type === "PluralRules")
-        internalProps = resolvePluralRulesInternals(lazyData)
+        internalProps = resolveDateTimeFormatInternals(internals.lazyData)
+    else if (type === "NumberFormat")
+        internalProps = resolveNumberFormatInternals(internals.lazyData);
     else
-        internalProps = resolveNumberFormatInternals(lazyData);
+        internalProps = resolvePluralRulesInternals(internals.lazyData)
     setInternalProperties(internals, internalProps);
     return internalProps;
 }
 
 
 /********** Intl.Collator **********/
 
 
@@ -2792,17 +2792,17 @@ function dateTimeFormatLocaleData(locale
  * Spec: ECMAScript Internationalization API Specification, 12.3.2.
  */
 function dateTimeFormatFormatToBind() {
     // Steps 1.a.i-ii
     var date = arguments.length > 0 ? arguments[0] : undefined;
     var x = (date === undefined) ? std_Date_now() : ToNumber(date);
 
     // Step 1.a.iii.
-    return intl_FormatDateTime(this, x, false);
+    return intl_FormatDateTime(this, x, /* formatToParts = */ false);
 }
 
 /**
  * Returns a function bound to this DateTimeFormat that returns a String value
  * representing the result of calling ToNumber(date) according to the
  * effective locale and the formatting options of this DateTimeFormat.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.3.2.
@@ -2831,17 +2831,17 @@ function Intl_DateTimeFormat_formatToPar
     // Check "this DateTimeFormat object" per introduction of section 12.3.
     getDateTimeFormatInternals(this, "formatToParts");
 
     // Steps 1.a.i-ii
     var date = arguments.length > 0 ? arguments[0] : undefined;
     var x = (date === undefined) ? std_Date_now() : ToNumber(date);
 
     // Step 1.a.iii.
-    return intl_FormatDateTime(this, x, true);
+    return intl_FormatDateTime(this, x, /* formatToParts = */ true);
 }
 
 
 /**
  * Returns the resolved options for a DateTimeFormat object.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.3.3 and 12.4.
  */
@@ -2955,18 +2955,20 @@ function resolveICUPattern(pattern, resu
             if (c === "h" || c === "K")
                 _DefineDataProperty(result, "hour12", true);
             else if (c === "H" || c === "k")
                 _DefineDataProperty(result, "hour12", false);
         }
     }
 }
 
+
 /********** Intl.PluralRules **********/
 
+
 /**
  * PluralRules internal properties.
  *
  * Spec: ECMAScript 402 API, PluralRules, 1.3.3.
  */
 var pluralRulesInternalProperties = {
     _availableLocales: null,
     availableLocales: function()
@@ -3176,55 +3178,98 @@ function Intl_PluralRules_resolvedOption
         var p = optionalProperties[i];
         if (callFunction(std_Object_hasOwnProperty, internals, p))
             _DefineDataProperty(result, p, internals[p]);
     }
     return result;
 }
 
 
+/********** Intl **********/
+
+
+/**
+ * 8.2.1 Intl.getCanonicalLocales ( locales )
+ *
+ * ES2017 Intl draft rev 947aa9a0c853422824a0c9510d8f09be3eb416b9
+ */
 function Intl_getCanonicalLocales(locales) {
-  let codes = CanonicalizeLocaleList(locales);
-  let result = [];
-
-  let len = codes.length;
-  let k = 0;
-
-  while (k < len) {
-    _DefineDataProperty(result, k, codes[k]);
-    k++;
-  }
-  return result;
-}
-
-function Intl_getCalendarInfo(locales) {
-  const requestedLocales = CanonicalizeLocaleList(locales);
-
-  const DateTimeFormat = dateTimeFormatInternalProperties;
-  const localeData = DateTimeFormat.localeData;
-
-  const localeOpt = new Record();
-  localeOpt.localeMatcher = "best fit";
-
-  const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
-                          requestedLocales,
-                          localeOpt,
-                          DateTimeFormat.relevantExtensionKeys,
-                          localeData);
-
-  const result = intl_GetCalendarInfo(r.locale);
-  result.calendar = r.ca;
-  result.locale = r.locale;
-
-  return result;
+    // Step 1.
+    var localeList = CanonicalizeLocaleList(locales);
+
+    // Step 2 (Inlined CreateArrayFromList).
+    var array = [];
+
+    for (var n = 0, len = localeList.length; n < len; n++)
+        _DefineDataProperty(array, n, localeList[n]);
+
+    return array;
 }
 
 /**
- * This function is a custom method designed after Intl API, but currently
- * not part of the spec or spec proposal.
+ * This function is a custom function in the style of the standard Intl.*
+ * functions, that isn't part of any spec or proposal yet.
+ *
+ * Returns an object with the following properties:
+ *   locale:
+ *     The actual resolved locale.
+ *
+ *   calendar:
+ *     The default calendar of the resolved locale.
+ *
+ *   firstDayOfWeek:
+ *     The first day of the week for the resolved locale.
+ *
+ *   minDays:
+ *     The minimum number of days in a week for the resolved locale.
+ *
+ *   weekendStart:
+ *     The day considered the beginning of a weekend for the resolved locale.
+ *
+ *   weekendEnd:
+ *     The day considered the end of a weekend for the resolved locale.
+ *
+ * Days are encoded as integers in the range 1=Sunday to 7=Saturday.
+ */
+function Intl_getCalendarInfo(locales) {
+    // 1. Let requestLocales be ? CanonicalizeLocaleList(locales).
+    const requestedLocales = CanonicalizeLocaleList(locales);
+
+    const DateTimeFormat = dateTimeFormatInternalProperties;
+
+    // 2. Let localeData be %DateTimeFormat%.[[localeData]].
+    const localeData = DateTimeFormat.localeData;
+
+    // 3. Let localeOpt be a new Record.
+    const localeOpt = new Record();
+
+    // 4. Set localeOpt.[[localeMatcher]] to "best fit".
+    localeOpt.localeMatcher = "best fit";
+
+    // 5. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]],
+    //    requestedLocales, localeOpt,
+    //    %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
+    const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
+                            requestedLocales,
+                            localeOpt,
+                            DateTimeFormat.relevantExtensionKeys,
+                            localeData);
+
+    // 6. Let result be GetCalendarInfo(r.[[locale]]).
+    const result = intl_GetCalendarInfo(r.locale);
+    _DefineDataProperty(result, "calendar", r.ca);
+    _DefineDataProperty(result, "locale", r.locale);
+
+    // 7. Return result.
+    return result;
+}
+
+/**
+ * This function is a custom function in the style of the standard Intl.*
+ * functions, that isn't part of any spec or proposal yet.
  * We want to use it internally to retrieve translated values from CLDR in
  * order to ensure they're aligned with what Intl API returns.
  *
  * This API may one day be a foundation for an ECMA402 API spec proposal.
  *
  * The function takes two arguments - locales which is a list of locale strings
  * and options which is an object with two optional properties:
  *
@@ -3260,31 +3305,33 @@ function Intl_getDisplayNames(locales, o
         // a. Let options be ? ToObject(options).
         options = ToObject(options);
 
     const DateTimeFormat = dateTimeFormatInternalProperties;
 
     // 4. Let localeData be %DateTimeFormat%.[[localeData]].
     const localeData = DateTimeFormat.localeData;
 
-    // 5. Let opt be a new Record.
+    // 5. Let localeOpt be a new Record.
     const localeOpt = new Record();
+
     // 6. Set localeOpt.[[localeMatcher]] to "best fit".
     localeOpt.localeMatcher = "best fit";
 
     // 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt,
     //    %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
     const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
                           requestedLocales,
                           localeOpt,
                           DateTimeFormat.relevantExtensionKeys,
                           localeData);
 
     // 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
     const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long");
+
     // 9. Let keys be ? Get(options, "keys").
     let keys = options.keys;
 
     // 10. If keys is undefined,
     if (keys === undefined) {
         // a. Let keys be ArrayCreate(0).
         keys = [];
     } else if (!IsObject(keys)) {
@@ -3293,18 +3340,20 @@ function Intl_getDisplayNames(locales, o
         ThrowTypeError(JSMSG_INVALID_KEYS_TYPE);
     }
 
     // 12. Let processedKeys be ArrayCreate(0).
     // (This really should be a List, but we use an Array here in order that
     // |intl_ComputeDisplayNames| may infallibly access the list's length via
     // |ArrayObject::length|.)
     let processedKeys = [];
+
     // 13. Let len be ? ToLength(? Get(keys, "length")).
     let len = ToLength(keys.length);
+
     // 14. Let i be 0.
     // 15. Repeat, while i < len
     for (let i = 0; i < len; i++) {
         // a. Let processedKey be ? ToString(? Get(keys, i)).
         // b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey).
         callFunction(std_Array_push, processedKeys, ToString(keys[i]));
     }