Bug 769872 - Add C++ core of Intl object and constructors Collator, NumberFormat, DateTimeFormat. However, disable initialization of Intl object and its constructors while functionality is incomplete. r=jwalden
authorNorbert Lindenberg <mozilladev@lindenbergsoftware.com>
Mon, 12 Nov 2012 13:23:01 -0800
changeset 113011 769777308b198b158e3efae2659347d3305c3798
parent 113010 bd5af10962327f5d114dd30615945c7cc0d6a200
child 113012 cd5b9d2728d0d68364cc6452369ea353d1e58fba
push id23847
push userphilringnalda@gmail.com
push dateTue, 13 Nov 2012 05:07:25 +0000
treeherdermozilla-central@1b0226622e94 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs769872
milestone19.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 769872 - Add C++ core of Intl object and constructors Collator, NumberFormat, DateTimeFormat. However, disable initialization of Intl object and its constructors while functionality is incomplete. r=jwalden
js/src/Makefile.in
js/src/builtin/Intl.cpp
js/src/builtin/Intl.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsprototypes.h
js/src/jsversion.h
js/src/vm/CommonPropertyNames.h
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -118,16 +118,17 @@ CPPSRCS		= \
 		Debugger.cpp \
 		GlobalObject.cpp \
 		ObjectImpl.cpp \
 		Stack.cpp \
 		String.cpp \
 		BytecodeCompiler.cpp \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
+		Intl.cpp \
 		NameFunctions.cpp \
 		ParallelArray.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
 		SPSProfiler.cpp \
 		TokenStream.cpp \
 		TestingFunctions.cpp \
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Intl.cpp
@@ -0,0 +1,517 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+/*
+ * The Intl module specified by standard ECMA-402,
+ * ECMAScript Internationalization API Specification.
+ */
+
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsobj.h"
+
+#include "builtin/Intl.h"
+#include "vm/GlobalObject.h"
+
+#include "jsobjinlines.h"
+
+using namespace js;
+
+/******************** Common to Intl constructors ********************/
+
+static bool
+IntlInitialize(JSContext *cx, HandleObject obj, Handle<PropertyName*> initializer,
+               HandleValue locales, HandleValue options)
+{
+    // ??? stub - initializer to be implemented as self-hosted function
+    return true;
+}
+
+/******************** Collator ********************/
+
+static Class CollatorClass = {
+    js_Object_str,
+    0,
+    JS_PropertyStub,         /* addProperty */
+    JS_PropertyStub,         /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
+#if JS_HAS_TOSOURCE
+static JSBool
+collator_toSource(JSContext *cx, unsigned argc, Value *vp)
+{
+    vp->setString(cx->names().Collator);
+    return true;
+}
+#endif
+
+static JSFunctionSpec collator_static_methods[] = {
+    JS_FS_END
+};
+
+static JSFunctionSpec collator_methods[] = {
+#if JS_HAS_TOSOURCE
+    JS_FN(js_toSource_str, collator_toSource, 0, 0),
+#endif
+    JS_FS_END
+};
+
+/**
+ * Collator constructor.
+ * Spec: ECMAScript Internationalization API Specification, 10.1
+ */
+static JSBool
+Collator(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx);
+
+    bool construct = IsConstructing(args);
+    if (!construct) {
+        // 10.1.2.1 step 3
+        JSObject *intl = cx->global()->getOrCreateIntlObject(cx);
+        if (!intl)
+            return false;
+        RootedValue self(cx, args.thisv());
+        if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
+            // 10.1.2.1 step 4
+            obj = ToObject(cx, self);
+            if (!obj)
+                return false;
+            // 10.1.2.1 step 5
+            if (!obj->isExtensible())
+                return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
+        } else {
+            // 10.1.2.1 step 3.a
+            construct = true;
+        }
+    }
+    if (construct) {
+        // 10.1.3.1 paragraph 2
+        RootedObject proto(cx, cx->global()->getOrCreateCollatorPrototype(cx));
+        if (!proto)
+            return false;
+        obj = NewObjectWithGivenProto(cx, &CollatorClass, proto, cx->global());
+        if (!obj)
+            return false;
+    }
+
+    // 10.1.2.1 steps 1 and 2; 10.1.3.1 steps 1 and 2
+    RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
+    RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
+    // 10.1.2.1 step 6; 10.1.3.1 step 3
+    if (!IntlInitialize(cx, obj, cx->names().InitializeCollator, locales, options))
+        return false;
+
+    // 10.1.2.1 steps 3.a and 7
+    args.rval().setObject(*obj);
+    return true;
+}
+
+static JSObject *
+InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
+{
+    RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0));
+    if (!ctor)
+        return NULL;
+
+    RootedObject proto(cx, global->asGlobal().getOrCreateCollatorPrototype(cx));
+    if (!proto)
+        return NULL;
+    if (!LinkConstructorAndPrototype(cx, ctor, proto))
+        return NULL;
+
+    // 10.2.2
+    if (!JS_DefineFunctions(cx, ctor, collator_static_methods))
+        return NULL;
+
+    // 10.3.2 and 10.3.3
+    if (!JS_DefineFunctions(cx, proto, collator_methods))
+        return NULL;
+
+    // 10.2.1 and 10.3
+    RootedValue locales(cx, UndefinedValue());
+    RootedValue options(cx, UndefinedValue());
+    if (!IntlInitialize(cx, proto, cx->names().InitializeCollator, locales, options))
+        return NULL;
+
+    // 8.1
+    RootedValue ctorValue(cx, ObjectValue(*ctor));
+    if (!JSObject::defineProperty(cx, Intl, cx->names().Collator, ctorValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+        return NULL;
+    }
+
+    return ctor;
+}
+
+bool
+GlobalObject::initCollatorProto(JSContext *cx, Handle<GlobalObject*> global)
+{
+    RootedObject proto(cx, global->createBlankPrototype(cx, &CollatorClass));
+    if (!proto)
+        return false;
+    global->setReservedSlot(COLLATOR_PROTO, ObjectValue(*proto));
+    return true;
+}
+
+
+/******************** NumberFormat ********************/
+
+static Class NumberFormatClass = {
+    js_Object_str,
+    0,
+    JS_PropertyStub,         /* addProperty */
+    JS_PropertyStub,         /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
+#if JS_HAS_TOSOURCE
+static JSBool
+numberFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
+{
+    vp->setString(cx->names().NumberFormat);
+    return true;
+}
+#endif
+
+static JSFunctionSpec numberFormat_static_methods[] = {
+    JS_FS_END
+};
+
+static JSFunctionSpec numberFormat_methods[] = {
+#if JS_HAS_TOSOURCE
+    JS_FN(js_toSource_str, numberFormat_toSource, 0, 0),
+#endif
+    JS_FS_END
+};
+
+/**
+ * NumberFormat constructor.
+ * Spec: ECMAScript Internationalization API Specification, 11.1
+ */
+static JSBool
+NumberFormat(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx);
+
+    bool construct = IsConstructing(args);
+    if (!construct) {
+        // 11.1.2.1 step 3
+        JSObject *intl = cx->global()->getOrCreateIntlObject(cx);
+        if (!intl)
+            return false;
+        RootedValue self(cx, args.thisv());
+        if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
+            // 11.1.2.1 step 4
+            obj = ToObject(cx, self);
+            if (!obj)
+                return false;
+            // 11.1.2.1 step 5
+            if (!obj->isExtensible())
+                return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
+        } else {
+            // 11.1.2.1 step 3.a
+            construct = true;
+        }
+    }
+    if (construct) {
+        // 11.1.3.1 paragraph 2
+        RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
+        if (!proto)
+            return false;
+        obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto, cx->global());
+        if (!obj)
+            return false;
+    }
+
+    // 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
+    RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
+    RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
+    // 11.1.2.1 step 6; 11.1.3.1 step 3
+    if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
+        return false;
+
+    // 11.1.2.1 steps 3.a and 7
+    args.rval().setObject(*obj);
+    return true;
+}
+
+static JSObject *
+InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
+{
+    RootedFunction ctor(cx, global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0));
+    if (!ctor)
+        return NULL;
+
+    RootedObject proto(cx, global->asGlobal().getOrCreateNumberFormatPrototype(cx));
+    if (!proto)
+        return NULL;
+    if (!LinkConstructorAndPrototype(cx, ctor, proto))
+        return NULL;
+
+    // 11.2.2
+    if (!JS_DefineFunctions(cx, ctor, numberFormat_static_methods))
+        return NULL;
+
+    // 11.3.2 and 11.3.3
+    if (!JS_DefineFunctions(cx, proto, numberFormat_methods))
+        return NULL;
+
+    // 11.2.1 and 11.3
+    RootedValue locales(cx, UndefinedValue());
+    RootedValue options(cx, UndefinedValue());
+    if (!IntlInitialize(cx, proto, cx->names().InitializeNumberFormat, locales, options))
+        return NULL;
+
+    // 8.1
+    RootedValue ctorValue(cx, ObjectValue(*ctor));
+    if (!JSObject::defineProperty(cx, Intl, cx->names().NumberFormat, ctorValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+        return NULL;
+    }
+
+    return ctor;
+}
+
+bool
+GlobalObject::initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global)
+{
+    RootedObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass));
+    if (!proto)
+        return false;
+    global->setReservedSlot(NUMBER_FORMAT_PROTO, ObjectValue(*proto));
+    return true;
+}
+
+
+/******************** DateTimeFormat ********************/
+
+static Class DateTimeFormatClass = {
+    js_Object_str,
+    0,
+    JS_PropertyStub,         /* addProperty */
+    JS_PropertyStub,         /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
+#if JS_HAS_TOSOURCE
+static JSBool
+dateTimeFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
+{
+    vp->setString(cx->names().DateTimeFormat);
+    return true;
+}
+#endif
+
+static JSFunctionSpec dateTimeFormat_static_methods[] = {
+    JS_FS_END
+};
+
+static JSFunctionSpec dateTimeFormat_methods[] = {
+#if JS_HAS_TOSOURCE
+    JS_FN(js_toSource_str, dateTimeFormat_toSource, 0, 0),
+#endif
+    JS_FS_END
+};
+
+/**
+ * DateTimeFormat constructor.
+ * Spec: ECMAScript Internationalization API Specification, 12.1
+ */
+static JSBool
+DateTimeFormat(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx);
+
+    bool construct = IsConstructing(args);
+    if (!construct) {
+        // 12.1.2.1 step 3
+        JSObject *intl = cx->global()->getOrCreateIntlObject(cx);
+        if (!intl)
+            return false;
+        RootedValue self(cx, args.thisv());
+        if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
+            // 12.1.2.1 step 4
+            obj = ToObject(cx, self);
+            if (!obj)
+                return false;
+            // 12.1.2.1 step 5
+            if (!obj->isExtensible())
+                return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
+        } else {
+            // 12.1.2.1 step 3.a
+            construct = true;
+        }
+    }
+    if (construct) {
+        // 12.1.3.1 paragraph 2
+        RootedObject proto(cx, cx->global()->getOrCreateDateTimeFormatPrototype(cx));
+        if (!proto)
+            return false;
+        obj = NewObjectWithGivenProto(cx, &DateTimeFormatClass, proto, cx->global());
+        if (!obj)
+            return false;
+    }
+
+    // 12.1.2.1 steps 1 and 2; 12.1.3.1 steps 1 and 2
+    RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
+    RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
+    // 12.1.2.1 step 6; 12.1.3.1 step 3
+    if (!IntlInitialize(cx, obj, cx->names().InitializeDateTimeFormat, locales, options))
+        return false;
+
+    // 12.1.2.1 steps 3.a and 7
+    args.rval().setObject(*obj);
+    return true;
+}
+
+static JSObject *
+InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
+{
+    RootedFunction ctor(cx, global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0));
+    if (!ctor)
+        return NULL;
+
+    RootedObject proto(cx, global->asGlobal().getOrCreateDateTimeFormatPrototype(cx));
+    if (!proto)
+        return NULL;
+    if (!LinkConstructorAndPrototype(cx, ctor, proto))
+        return NULL;
+
+    // 12.2.2
+    if (!JS_DefineFunctions(cx, ctor, dateTimeFormat_static_methods))
+        return NULL;
+
+    // 12.3.2 and 12.3.3
+    if (!JS_DefineFunctions(cx, proto, dateTimeFormat_methods))
+        return NULL;
+
+    // 12.2.1 and 12.3
+    RootedValue locales(cx, UndefinedValue());
+    RootedValue options(cx, UndefinedValue());
+    if (!IntlInitialize(cx, proto, cx->names().InitializeDateTimeFormat, locales, options))
+        return NULL;
+
+    // 8.1
+    RootedValue ctorValue(cx, ObjectValue(*ctor));
+    if (!JSObject::defineProperty(cx, Intl, cx->names().DateTimeFormat, ctorValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+        return NULL;
+    }
+
+    return ctor;
+}
+
+bool
+GlobalObject::initDateTimeFormatProto(JSContext *cx, Handle<GlobalObject*> global)
+{
+    RootedObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass));
+    if (!proto)
+        return false;
+    global->setReservedSlot(DATE_TIME_FORMAT_PROTO, ObjectValue(*proto));
+    return true;
+}
+
+
+/******************** Intl ********************/
+
+Class js::IntlClass = {
+    js_Object_str,
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Intl),
+    JS_PropertyStub,         /* addProperty */
+    JS_PropertyStub,         /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
+#if JS_HAS_TOSOURCE
+static JSBool
+intl_toSource(JSContext *cx, unsigned argc, Value *vp)
+{
+    vp->setString(cx->names().Intl);
+    return true;
+}
+#endif
+
+static JSFunctionSpec intl_static_methods[] = {
+#if JS_HAS_TOSOURCE
+    JS_FN(js_toSource_str,  intl_toSource,        0, 0),
+#endif
+    JS_FS_END
+};
+
+/**
+ * Initializes the Intl Object and its standard built-in properties.
+ * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1
+ */
+JSObject *
+js_InitIntlClass(JSContext *cx, HandleObject obj)
+{
+    JS_ASSERT(obj->isGlobal());
+    Rooted<GlobalObject*> global(cx, &obj->asGlobal());
+
+    // The constructors above need to be able to determine whether they've been
+    // called with this being "the standard built-in Intl object". The global
+    // object reserves slots to track standard built-in objects, but doesn't
+    // normally keep references to non-constructors. This makes sure there is one.
+    RootedObject Intl(cx, global->getOrCreateIntlObject(cx));
+    if (!Intl)
+        return NULL;
+
+    RootedValue IntlValue(cx, ObjectValue(*Intl));
+    if (!JSObject::defineProperty(cx, global, cx->names().Intl, IntlValue,
+                                  JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+        return NULL;
+    }
+
+    if (!JS_DefineFunctions(cx, Intl, intl_static_methods))
+        return NULL;
+
+    if (!InitCollatorClass(cx, Intl, global))
+        return NULL;
+    if (!InitNumberFormatClass(cx, Intl, global))
+        return NULL;
+    if (!InitDateTimeFormatClass(cx, Intl, global))
+        return NULL;
+
+    MarkStandardClassInitializedNoProto(global, &IntlClass);
+
+    return Intl;
+}
+
+bool
+GlobalObject::initIntlObject(JSContext *cx, Handle<GlobalObject*> global)
+{
+    RootedObject Intl(cx, NewObjectWithClassProto(cx, &IntlClass, NULL, global));
+    if (!Intl || !JSObject::setSingletonType(cx, Intl))
+        return false;
+
+    global->setReservedSlot(JSProto_Intl, ObjectValue(*Intl));
+    return true;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Intl.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+#ifndef Intl_h___
+#define Intl_h___
+
+#include "gc/Root.h"
+
+struct JSContext;
+struct JSObject;
+
+/*
+ * The Intl module specified by standard ECMA-402,
+ * ECMAScript Internationalization API Specification.
+ */
+
+/**
+ * Initializes the Intl Object and its standard built-in properties.
+ * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1
+ */
+extern JSObject *
+js_InitIntlClass(JSContext *cx, js::HandleObject obj);
+
+#endif /* Intl_h___ */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -50,16 +50,17 @@
 #include "prmjtime.h"
 #include "jsweakmap.h"
 #include "jsworkers.h"
 #include "jswrapper.h"
 #include "jstypedarray.h"
 #include "jsxml.h"
 
 #include "builtin/Eval.h"
+#include "builtin/Intl.h"
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "builtin/ParallelArray.h"
 #include "ds/LifoAlloc.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
@@ -1788,16 +1789,19 @@ static JSStdName standard_class_atoms[] 
 #endif
     {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
     {js_InitTypedArrayClasses,          EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
     {js_InitWeakMapClass,               EAGER_ATOM_AND_CLASP(WeakMap)},
     {js_InitMapClass,                   EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
     {js_InitSetClass,                   EAGER_CLASS_ATOM(Set), &js::SetObject::class_},
     {js_InitParallelArrayClass,         EAGER_CLASS_ATOM(ParallelArray), &js::ParallelArrayObject::class_},
     {js_InitProxyClass,                 EAGER_ATOM_AND_CLASP(Proxy)},
+#if ENABLE_INTL_API
+    {js_InitIntlClass,                  EAGER_ATOM_AND_CLASP(Intl)},
+#endif
     {NULL,                              0, NULL}
 };
 
 /*
  * Table of top-level function and constant names and their init functions.
  * If you add a "standard" global function or property, remember to update
  * this table.
  */
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3989,17 +3989,17 @@ struct JSClass {
  * member initial value.  The "original ... value" verbiage is there because
  * in ECMA-262, global properties naming class objects are read/write and
  * deleteable, for the most part.
  *
  * Implementing this efficiently requires that global objects have classes
  * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
  * prevously allowed, but is now an ES5 violation and thus unsupported.
  */
-#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 23)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 26)
 #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/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -887,17 +887,17 @@ PropDesc::makeObject(JSContext *cx)
     pd_.setObject(*obj);
     return true;
 }
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc)
 {
     // FIXME: Call TrapGetOwnProperty directly once ScriptedIndirectProxies is removed
-    if (obj->isProxy()) 
+    if (obj->isProxy())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id, false, desc);
 
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &shape))
         return false;
     if (!shape) {
         desc->obj = NULL;
@@ -3508,17 +3508,17 @@ JSObject::shrinkElements(JSContext *cx, 
 static JSObject *
 js_InitNullClass(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(0);
     return NULL;
 }
 
 #define DECLARE_PROTOTYPE_CLASS_INIT(name,code,init) \
-    extern JSObject *init(JSContext *cx, JSObject *obj);
+    extern JSObject *init(JSContext *cx, Handle<JSObject*> obj);
 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
 #undef DECLARE_PROTOTYPE_CLASS_INIT
 
 static JSClassInitializerOp lazy_prototype_init[JSProto_LIMIT] = {
 #define LAZY_PROTOTYPE_INIT(name,code,init) init,
     JS_FOR_EACH_PROTOTYPE(LAZY_PROTOTYPE_INIT)
 #undef LAZY_PROTOTYPE_INIT
 };
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -203,16 +203,17 @@ extern Class ArrayBufferClass;
 extern Class BlockClass;
 extern Class BooleanClass;
 extern Class CallableObjectClass;
 extern Class DataViewClass;
 extern Class DateClass;
 extern Class ErrorClass;
 extern Class ElementIteratorClass;
 extern Class GeneratorClass;
+extern Class IntlClass;
 extern Class JSONClass;
 extern Class MapIteratorClass;
 extern Class MathClass;
 extern Class NumberClass;
 extern Class NormalArgumentsObjectClass;
 extern Class ObjectClass;
 extern Class ProxyClass;
 extern Class RegExpClass;
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -55,10 +55,11 @@
     macro(Uint8ClampedArray,     33,     js_InitTypedArrayClasses) \
     macro(Proxy,                 34,     js_InitProxyClass) \
     macro(AnyName,               35,     js_InitNullClass) \
     macro(WeakMap,               36,     js_InitWeakMapClass) \
     macro(Map,                   37,     js_InitMapClass) \
     macro(Set,                   38,     js_InitSetClass) \
     macro(DataView,              39,     js_InitTypedArrayClasses) \
     macro(ParallelArray,         40,     js_InitParallelArrayClass) \
+    macro(Intl,                  41,     js_InitIntlClass) \
 
 #endif /* jsprototypes_h___ */
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -165,9 +165,12 @@
 
 #if USE_NEW_OBJECT_REPRESENTATION
 #  define NEW_OBJECT_REPRESENTATION_ONLY() ((void)0)
 #else
 #  define NEW_OBJECT_REPRESENTATION_ONLY() \
      MOZ_NOT_REACHED("don't call this!  to be used in the new object representation")
 #endif
 
+/* ECMAScript Internationalization API isn't fully implemented yet. */
+#define ENABLE_INTL_API 0
+
 #endif /* jsversion_h___ */
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -39,20 +39,22 @@
     macro(byteLength, byteLength, "byteLength") \
     macro(byteOffset, byteOffset, "byteOffset") \
     macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
     macro(call, call, "call") \
     macro(callee, callee, "callee") \
     macro(caller, caller, "caller") \
     macro(_CallFunction, _CallFunction, "_CallFunction") \
     macro(classPrototype, classPrototype, "prototype") \
+    macro(Collator, Collator, "Collator") \
     macro(columnNumber, columnNumber, "columnNumber") \
     macro(configurable, configurable, "configurable") \
     macro(construct, construct, "construct") \
     macro(constructor, constructor, "constructor") \
+    macro(DateTimeFormat, DateTimeFormat, "DateTimeFormat") \
     macro(decodeURI, decodeURI, "decodeURI") \
     macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
     macro(defineProperty, defineProperty, "defineProperty") \
     macro(defineGetter, defineGetter, "__defineGetter__") \
     macro(defineSetter, defineSetter, "__defineSetter__") \
     macro(delete, delete_, "delete") \
     macro(deleteProperty, deleteProperty, "deleteProperty") \
     macro(each, each, "each") \
@@ -71,16 +73,19 @@
     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") \
     macro(index, index, "index") \
+    macro(InitializeCollator, InitializeCollator, "intl_InitializeCollator") \
+    macro(InitializeDateTimeFormat, InitializeDateTimeFormat, "intl_InitializeDateTimeFormat") \
+    macro(InitializeNumberFormat, InitializeNumberFormat, "intl_InitializeNumberFormat") \
     macro(innermost, innermost, "innermost") \
     macro(input, input, "input") \
     macro(isFinite, isFinite, "isFinite") \
     macro(isNaN, isNaN, "isNaN") \
     macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
     macro(isXMLName, isXMLName, "isXMLName") \
     macro(iterate, iterate, "iterate") \
     macro(Infinity, Infinity, "Infinity") \
@@ -96,16 +101,17 @@
     macro(lookupGetter, lookupGetter, "__lookupGetter__") \
     macro(lookupSetter, lookupSetter, "__lookupSetter__") \
     macro(message, message, "message") \
     macro(multiline, multiline, "multiline") \
     macro(name, name, "name") \
     macro(NaN, NaN, "NaN") \
     macro(next, next, "next") \
     macro(noSuchMethod, noSuchMethod, "__noSuchMethod__") \
+    macro(NumberFormat, NumberFormat, "NumberFormat") \
     macro(objectNull, objectNull, "[object Null]") \
     macro(objectUndefined, objectUndefined, "[object Undefined]") \
     macro(of, of, "of") \
     macro(parseFloat, parseFloat, "parseFloat") \
     macro(parseInt, parseInt, "parseInt") \
     macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \
     macro(proto, proto, "__proto__") \
     macro(return, return_, "return") \
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -11,16 +11,17 @@
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfriendapi.h"
 #include "jsmath.h"
 #include "json.h"
 #include "jsweakmap.h"
 
 #include "builtin/Eval.h"
+#include "builtin/Intl.h"
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeEmitter.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/GlobalObject-inl.h"
 #include "vm/RegExpObject-inl.h"
@@ -465,17 +466,21 @@ GlobalObject::initStandardClasses(JSCont
 #endif
            js_InitIteratorClasses(cx, global) &&
            js_InitDateClass(cx, global) &&
            js_InitWeakMapClass(cx, global) &&
            js_InitProxyClass(cx, global) &&
            js_InitMapClass(cx, global) &&
            GlobalObject::initMapIteratorProto(cx, global) &&
            js_InitSetClass(cx, global) &&
-           GlobalObject::initSetIteratorProto(cx, global);
+           GlobalObject::initSetIteratorProto(cx, global) &&
+#if ENABLE_INTL_API
+           js_InitIntlClass(cx, global) &&
+#endif
+           true;
 }
 
 bool
 GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx)
 {
     HeapSlot &v = getSlotRef(RUNTIME_CODEGEN_ENABLED);
     if (v.isUndefined()) {
         /*
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -90,17 +90,20 @@ class GlobalObject : public JSObject
     static const unsigned FROM_BUFFER_FLOAT64 = FROM_BUFFER_FLOAT32 + 1;
     static const unsigned FROM_BUFFER_UINT8CLAMPED = FROM_BUFFER_FLOAT64 + 1;
 
     /* One-off properties stored after slots for built-ins. */
     static const unsigned ELEMENT_ITERATOR_PROTO  = FROM_BUFFER_UINT8CLAMPED + 1;
     static const unsigned GENERATOR_PROTO         = ELEMENT_ITERATOR_PROTO + 1;
     static const unsigned MAP_ITERATOR_PROTO      = GENERATOR_PROTO + 1;
     static const unsigned SET_ITERATOR_PROTO      = MAP_ITERATOR_PROTO + 1;
-    static const unsigned REGEXP_STATICS          = SET_ITERATOR_PROTO + 1;
+    static const unsigned COLLATOR_PROTO          = SET_ITERATOR_PROTO + 1;
+    static const unsigned NUMBER_FORMAT_PROTO     = COLLATOR_PROTO + 1;
+    static const unsigned DATE_TIME_FORMAT_PROTO  = NUMBER_FORMAT_PROTO + 1;
+    static const unsigned REGEXP_STATICS          = DATE_TIME_FORMAT_PROTO + 1;
     static const unsigned FUNCTION_NS             = REGEXP_STATICS + 1;
     static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
     static const unsigned DEBUGGERS               = RUNTIME_CODEGEN_ENABLED + 1;
     static const unsigned INTRINSICS              = DEBUGGERS + 1;
 
     /* Total reserved-slot count for global objects. */
     static const unsigned RESERVED_SLOTS = INTRINSICS + 1;
 
@@ -305,16 +308,32 @@ class GlobalObject : public JSObject
         if (errorClassesInitialized())
             return &getPrototype(key).toObject();
         Rooted<GlobalObject*> self(cx, this);
         if (!js_InitExceptionClasses(cx, self))
             return NULL;
         return &self->getPrototype(key).toObject();
     }
 
+    JSObject *getOrCreateIntlObject(JSContext *cx) {
+        return getOrCreateObject(cx, JSProto_Intl, initIntlObject);
+    }
+
+    JSObject *getOrCreateCollatorPrototype(JSContext *cx) {
+        return getOrCreateObject(cx, COLLATOR_PROTO, initCollatorProto);
+    }
+
+    JSObject *getOrCreateNumberFormatPrototype(JSContext *cx) {
+        return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initNumberFormatProto);
+    }
+
+    JSObject *getOrCreateDateTimeFormatPrototype(JSContext *cx) {
+        return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto);
+    }
+
     JSObject *getIteratorPrototype() {
         return &getPrototype(JSProto_Iterator).toObject();
     }
 
     JSObject *getIntrinsicsHolder() {
         JS_ASSERT(!getSlotRef(INTRINSICS).isUndefined());
         return &getSlotRef(INTRINSICS).toObject();
     }
@@ -418,16 +437,22 @@ class GlobalObject : public JSObject
 
     // Implemented in jsiter.cpp.
     static bool initIteratorClasses(JSContext *cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/MapObject.cpp.
     static bool initMapIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
     static bool initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
 
+    // Implemented in Intl.cpp.
+    static bool initIntlObject(JSContext *cx, Handle<GlobalObject*> global);
+    static bool initCollatorProto(JSContext *cx, Handle<GlobalObject*> global);
+    static bool initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global);
+    static bool initDateTimeFormatProto(JSContext *cx, Handle<GlobalObject*> global);
+
     static bool initStandardClasses(JSContext *cx, Handle<GlobalObject*> global);
 
     typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector;
 
     /*
      * The collection of Debugger objects debugging this global. If this global
      * is not a debuggee, this returns either NULL or an empty vector.
      */