Bug 837957 - Implement ICU dependent functions of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat (part 1). r=jwalden
authorNorbert Lindenberg <mozilladev@lindenbergsoftware.com>
Thu, 14 Mar 2013 14:22:24 -0700
changeset 124949 e1cc50bfee41a2d6486e77f2714a1eaa2833a482
parent 124948 9ea11ddff33b37316fab484873f228f36ae3b41a
child 124950 f723856dac075cae03c17ab8c8532a69e37b4732
push id24696
push userjwalden@mit.edu
push dateFri, 15 Mar 2013 17:45:29 +0000
treeherdermozilla-inbound@ba0b144c146f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs837957
milestone22.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 837957 - Implement ICU dependent functions of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat (part 1). r=jwalden
js/src/builtin/Intl.cpp
js/src/js.msg
js/src/vm/CommonPropertyNames.h
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -4,31 +4,49 @@
  * 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/. */
 
 /*
  * The Intl module specified by standard ECMA-402,
  * ECMAScript Internationalization API Specification.
  */
 
+#include <string.h>
+
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsinterp.h"
 #include "jsobj.h"
 
 #include "builtin/Intl.h"
 #include "vm/GlobalObject.h"
 #include "vm/Stack.h"
 
+#if ENABLE_INTL_API
+#include "unicode/locid.h"
+#include "unicode/numsys.h"
+#include "unicode/ucal.h"
+#include "unicode/ucol.h"
+#include "unicode/udat.h"
+#include "unicode/udatpg.h"
+#include "unicode/uenum.h"
+#include "unicode/unum.h"
+#include "unicode/ustring.h"
+#endif
+#include "unicode/utypes.h"
+
 #include "jsobjinlines.h"
 
-#include "unicode/utypes.h"
+using namespace js;
 
-using namespace js;
+#if ENABLE_INTL_API
+using icu::Locale;
+using icu::NumberingSystem;
+#endif
 
 
 /******************** ICU stubs ********************/
 
 #if !ENABLE_INTL_API
 
 /*
  * When the Internationalization API isn't enabled, we also shouldn't link
@@ -419,16 +437,140 @@ IntlInitialize(JSContext *cx, HandleObje
     args.setThis(NullValue());
     args[0] = ObjectValue(*obj);
     args[1] = locales;
     args[2] = options;
 
     return Invoke(cx, args);
 }
 
+// CountAvailable and GetAvailable describe the signatures used for ICU API
+// to determine available locales for various functionality.
+typedef int32_t
+(* CountAvailable)(void);
+
+typedef const char *
+(* GetAvailable)(int32_t localeIndex);
+
+SUPPRESS_UNUSED_WARNING static bool
+intl_availableLocales(JSContext *cx, CountAvailable countAvailable,
+                      GetAvailable getAvailable, MutableHandleValue result)
+{
+    RootedObject locales(cx, NewObjectWithGivenProto(cx, &ObjectClass, NULL, NULL));
+    if (!locales)
+        return false;
+
+#if ENABLE_INTL_API
+    uint32_t count = countAvailable();
+    RootedValue t(cx, BooleanValue(true));
+    for (uint32_t i = 0; i < count; i++) {
+        const char *locale = getAvailable(i);
+        ScopedJSFreePtr<char> lang(JS_strdup(cx, locale));
+        if (!lang)
+            return false;
+        char *p;
+        while ((p = strchr(lang, '_')))
+            *p = '-';
+        RootedAtom a(cx, Atomize(cx, lang, strlen(lang)));
+        if (!a)
+            return false;
+        if (!JSObject::defineProperty(cx, locales, a->asPropertyName(), t,
+                                      JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE))
+        {
+            return false;
+        }
+    }
+#endif
+    result.setObject(*locales);
+    return true;
+}
+
+/**
+ * Returns the object holding the internal properties for obj.
+ */
+SUPPRESS_UNUSED_WARNING static bool
+GetInternals(JSContext *cx, HandleObject obj, MutableHandleObject internals)
+{
+    RootedValue getInternalsValue(cx);
+    if (!cx->global()->getIntrinsicValue(cx, cx->names().getInternals, &getInternalsValue))
+        return false;
+    JS_ASSERT(getInternalsValue.isObject());
+    JS_ASSERT(getInternalsValue.toObject().isFunction());
+
+    InvokeArgsGuard args;
+    if (!cx->stack.pushInvokeArgs(cx, 1, &args))
+        return false;
+
+    args.setCallee(getInternalsValue);
+    args.setThis(NullValue());
+    args[0] = ObjectValue(*obj);
+
+    if (!Invoke(cx, args))
+        return false;
+    internals.set(&args.rval().toObject());
+    return true;
+}
+
+static bool
+equal(const char *s1, const char *s2)
+{
+    return !strcmp(s1, s2);
+}
+
+SUPPRESS_UNUSED_WARNING static bool
+equal(JSAutoByteString &s1, const char *s2)
+{
+    return !strcmp(s1.ptr(), s2);
+}
+
+SUPPRESS_UNUSED_WARNING static const char *
+icuLocale(const char *locale)
+{
+    if (equal(locale, "und"))
+        return ""; // ICU root locale
+    return locale;
+}
+
+// Simple RAII for ICU objects. MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE
+// unfortunately doesn't work because of namespace incompatibilities
+// (TypeSpecificDelete cannot be in icu and mozilla at the same time)
+// and because ICU declares both UNumberFormat and UDateTimePatternGenerator
+// as void*.
+template <typename T>
+class ScopedICUObject
+{
+    T *ptr_;
+    void (* deleter_)(T*);
+
+  public:
+    ScopedICUObject(T *ptr, void (*deleter)(T*))
+      : ptr_(ptr),
+        deleter_(deleter)
+    {}
+
+    ~ScopedICUObject() {
+        if (ptr_)
+            deleter_(ptr_);
+    }
+
+    // In cases where an object should be deleted on abnormal exits,
+    // but returned to the caller if everything goes well, call forget()
+    // to transfer the object just before returning.
+    T *forget() {
+        T *tmp = ptr_;
+        ptr_ = NULL;
+        return tmp;
+    }
+};
+
+static const size_t STACK_STRING_SIZE = 50;
+
+static const uint32_t ICU_OBJECT_SLOT = 0;
+
+
 /******************** Collator ********************/
 
 static Class CollatorClass = {
     js_Object_str,
     0,
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -242,17 +242,17 @@ MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,    18
 MSG_DEF(JSMSG_UNUSED189,              189, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED190,              190, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED191,              191, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED192,              192, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP,      193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
 MSG_DEF(JSMSG_UNUSED194,              194, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED195,              195, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED196,              196, 0, JSEXN_NONE, "")
-MSG_DEF(JSMSG_UNUSED197,              197, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_INTERNAL_INTL_ERROR,    197, 0, JSEXN_ERR, "internal error while computing Intl data")
 MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR,   198, 0, JSEXN_ERR, "internal error getting the default locale")
 MSG_DEF(JSMSG_TOO_MANY_LOCALS,        199, 0, JSEXN_SYNTAXERR, "too many local variables")
 MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG,     200, 0, JSEXN_INTERNALERR, "array initialiser too large")
 MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX,     201, 0, JSEXN_INTERNALERR, "regular expression too complex")
 MSG_DEF(JSMSG_BUFFER_TOO_SMALL,       202, 0, JSEXN_INTERNALERR, "buffer too small")
 MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,     203, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
 MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,    204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
 MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,    205, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -51,16 +51,17 @@
     macro(enumerate, enumerate, "enumerate") \
     macro(escape, escape, "escape") \
     macro(eval, eval, "eval") \
     macro(false, false_, "false") \
     macro(fileName, fileName, "fileName") \
     macro(fix, fix, "fix") \
     macro(format, format, "format") \
     macro(get, get, "get") \
+    macro(getInternals, getInternals, "getInternals") \
     macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
     macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
     macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
     macro(global, global, "global") \
     macro(has, has, "has") \
     macro(hasOwn, hasOwn, "hasOwn") \
     macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
     macro(ignoreCase, ignoreCase, "ignoreCase") \