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 120946 769777308b198b158e3efae2659347d3305c3798
parent 120945 bd5af10962327f5d114dd30615945c7cc0d6a200
child 120947 cd5b9d2728d0d68364cc6452369ea353d1e58fba
push idunknown
push userunknown
push dateunknown
reviewersjwalden
bugs769872
milestone19.0a1
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.
      */