Bug 898356 Part 9 -- Move array buffers into their own file r=sfink
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Wed, 19 Feb 2014 14:10:43 -0500
changeset 186932 5c4cec0ab08af499f37190f0f225e725209a9bf2
parent 186931 1fd48bfe7f702f780a087bf6e501c12a6687b10f
child 186933 cc73b1f7a47d82829a30cbb78810ad9a434c2fcd
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs898356
milestone30.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 898356 Part 9 -- Move array buffers into their own file r=sfink
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObjectSimple.cpp
js/src/builtin/TypedObjectSimple.h
js/src/moz.build
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -171,16 +171,222 @@ GetPrototype(JSContext *cx, HandleObject
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_INVALID_PROTOTYPE);
         return nullptr;
     }
     return &prototypeVal.toObject();
 }
 
 /***************************************************************************
+ * Type descriptors
+ */
+
+TypeRepresentation *
+TypeDescr::typeRepresentation() const {
+    return TypeRepresentation::fromOwnerObject(typeRepresentationOwnerObj());
+}
+
+TypeDescr::Kind
+TypeDescr::kind() const {
+    return typeRepresentation()->kind();
+}
+
+bool
+TypeDescr::opaque() const {
+    return typeRepresentation()->opaque();
+}
+
+/***************************************************************************
+ * Scalar type objects
+ *
+ * Scalar type objects like `uint8`, `uint16`, are all instances of
+ * the ScalarTypeDescr class. Like all type objects, they have a reserved
+ * slot pointing to a TypeRepresentation object, which is used to
+ * distinguish which scalar type object this actually is.
+ */
+
+const Class js::ScalarTypeDescr::class_ = {
+    "Scalar",
+    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
+    JS_PropertyStub,       /* addProperty */
+    JS_DeletePropertyStub, /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,
+    ScalarTypeDescr::call,
+    nullptr,
+    nullptr,
+    nullptr
+};
+
+const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
+    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
+    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
+    JS_FS_END
+};
+
+static size_t ScalarSizes[] = {
+#define SCALAR_SIZE(_kind, _type, _name)                        \
+    sizeof(_type),
+    JS_FOR_EACH_SCALAR_TYPE_REPR(SCALAR_SIZE) 0
+#undef SCALAR_SIZE
+};
+
+size_t
+ScalarTypeDescr::size(Type t)
+{
+    return ScalarSizes[t];
+}
+
+size_t
+ScalarTypeDescr::alignment(Type t)
+{
+    return ScalarSizes[t];
+}
+
+/*static*/ const char *
+ScalarTypeDescr::typeName(Type type)
+{
+    switch (type) {
+#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
+        case constant_: return #name_;
+        JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+    }
+    MOZ_ASSUME_UNREACHABLE("Invalid type");
+}
+
+bool
+ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() < 1) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
+                             args.callee().getClass()->name, "0", "s");
+        return false;
+    }
+
+    ScalarTypeRepresentation *typeRepr =
+        args.callee().as<ScalarTypeDescr>().typeRepresentation()->asScalar();
+    ScalarTypeDescr::Type type = typeRepr->type();
+
+    double number;
+    if (!ToNumber(cx, args[0], &number))
+        return false;
+
+    if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED)
+        number = ClampDoubleToUint8(number);
+
+    switch (type) {
+#define SCALARTYPE_CALL(constant_, type_, name_)                             \
+      case constant_: {                                                       \
+          type_ converted = ConvertScalar<type_>(number);                     \
+          args.rval().setNumber((double) converted);                          \
+          return true;                                                        \
+      }
+
+        JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL)
+#undef SCALARTYPE_CALL
+
+    }
+    return true;
+}
+
+/***************************************************************************
+ * Reference type objects
+ *
+ * Reference type objects like `Any` or `Object` basically work the
+ * same way that the scalar type objects do. There is one class with
+ * many instances, and each instance has a reserved slot with a
+ * TypeRepresentation object, which is used to distinguish which
+ * reference type object this actually is.
+ */
+
+const Class js::ReferenceTypeDescr::class_ = {
+    "Reference",
+    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
+    JS_PropertyStub,       /* addProperty */
+    JS_DeletePropertyStub, /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,
+    ReferenceTypeDescr::call,
+    nullptr,
+    nullptr,
+    nullptr
+};
+
+const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
+    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
+    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
+    JS_FS_END
+};
+
+/*static*/ const char *
+ReferenceTypeDescr::typeName(Type type)
+{
+    switch (type) {
+#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
+        case constant_: return #name_;
+        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+    }
+    MOZ_ASSUME_UNREACHABLE("Invalid type");
+}
+
+bool
+js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    JS_ASSERT(args.callee().is<ReferenceTypeDescr>());
+    ReferenceTypeRepresentation *typeRepr =
+        args.callee().as<ReferenceTypeDescr>().typeRepresentation()->asReference();
+
+    if (args.length() < 1) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
+                             JSMSG_MORE_ARGS_NEEDED,
+                             typeRepr->typeName(), "0", "s");
+        return false;
+    }
+
+    switch (typeRepr->type()) {
+      case ReferenceTypeDescr::TYPE_ANY:
+        args.rval().set(args[0]);
+        return true;
+
+      case ReferenceTypeDescr::TYPE_OBJECT:
+      {
+        RootedObject obj(cx, ToObject(cx, args[0]));
+        if (!obj)
+            return false;
+        args.rval().setObject(*obj);
+        return true;
+      }
+
+      case ReferenceTypeDescr::TYPE_STRING:
+      {
+        RootedString obj(cx, ToString<CanGC>(cx, args[0]));
+        if (!obj)
+            return false;
+        args.rval().setString(&*obj);
+        return true;
+      }
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Unhandled Reference type");
+}
+
+/***************************************************************************
  * ArrayMetaTypeDescr class
  */
 
 /*
  * For code like:
  *
  *   var A = new TypedObject.ArrayType(uint8, 10);
  *   var S = new TypedObject.StructType({...});
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -5,18 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_TypedObject_h
 #define builtin_TypedObject_h
 
 #include "jsobj.h"
 
 #include "builtin/TypedObjectConstants.h"
-#include "builtin/TypedObjectSimple.h"
-#include "vm/TypedArrayObject.h"
+#include "vm/ArrayBufferObject.h"
 
 /*
  * -------------
  * Typed Objects
  * -------------
  *
  * Typed objects are a special kind of JS object where the data is
  * given well-structured form. To use a typed object, users first
@@ -102,37 +101,207 @@
  * the derived object is alive. We always maintain the invariant that
  * JS_TYPEDOBJ_SLOT_OWNER is the true owner of the memory, meaning
  * that there is a shallow tree. This prevents an access pattern like
  * `a.b.c.d` from keeping all the intermediate objects alive.
  */
 
 namespace js {
 
+class TypeRepresentation;
+class ScalarTypeRepresentation;
+class ReferenceTypeRepresentation;
+class X4TypeRepresentation;
+class StructTypeDescr;
+
 /*
- * This object exists in order to encapsulate the typed object types
- * somewhat, rather than sticking them all into the global object.
- * Eventually it will go away and become a module.
+ * Helper method for converting a double into other scalar
+ * types in the same way that JavaScript would. In particular,
+ * simple C casting from double to int32_t gets things wrong
+ * for values like 0xF0000000.
  */
-class TypedObjectModuleObject : public JSObject {
+template <typename T>
+static T ConvertScalar(double d)
+{
+    if (TypeIsFloatingPoint<T>()) {
+        return T(d);
+    } else if (TypeIsUnsigned<T>()) {
+        uint32_t n = ToUint32(d);
+        return T(n);
+    } else {
+        int32_t n = ToInt32(d);
+        return T(n);
+    }
+}
+
+class TypeDescr : public JSObject
+{
+  public:
+    enum Kind {
+        Scalar = JS_TYPEREPR_SCALAR_KIND,
+        Reference = JS_TYPEREPR_REFERENCE_KIND,
+        X4 = JS_TYPEREPR_X4_KIND,
+        Struct = JS_TYPEREPR_STRUCT_KIND,
+        SizedArray = JS_TYPEREPR_SIZED_ARRAY_KIND,
+        UnsizedArray = JS_TYPEREPR_UNSIZED_ARRAY_KIND,
+    };
+
+    static bool isSized(Kind kind) {
+        return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
+    }
+
+    JSObject &typeRepresentationOwnerObj() const {
+        return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
+    }
+
+    TypeRepresentation *typeRepresentation() const;
+
+    TypeDescr::Kind kind() const;
+
+    bool opaque() const;
+
+    size_t alignment() {
+        return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
+    }
+};
+
+typedef Handle<TypeDescr*> HandleTypeDescr;
+
+class SizedTypeDescr : public TypeDescr
+{
+  public:
+    size_t size() {
+        return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
+    }
+};
+
+typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
+
+class SimpleTypeDescr : public SizedTypeDescr
+{
+};
+
+// Type for scalar type constructors like `uint8`. All such type
+// constructors share a common js::Class and JSFunctionSpec. Scalar
+// types are non-opaque (their storage is visible unless combined with
+// an opaque reference type.)
+class ScalarTypeDescr : public SimpleTypeDescr
+{
   public:
-    enum Slot {
-        ArrayTypePrototype,
-        StructTypePrototype,
-        SlotCount
+    // Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
+    enum Type {
+        TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
+        TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
+        TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
+        TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
+        TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
+        TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
+        TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
+        TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
+
+        /*
+         * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
+         * Treat the raw data type as a uint8_t.
+         */
+        TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
+    };
+    static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
+
+    static size_t size(Type t);
+    static size_t alignment(Type t);
+    static const char *typeName(Type type);
+
+    static const Class class_;
+    static const JSFunctionSpec typeObjectMethods[];
+    typedef ScalarTypeRepresentation TypeRepr;
+
+    ScalarTypeDescr::Type type() const {
+        return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
+    }
+
+    static bool call(JSContext *cx, unsigned argc, Value *vp);
+};
+
+// Enumerates the cases of ScalarTypeDescr::Type which have
+// unique C representation. In particular, omits Uint8Clamped since it
+// is just a Uint8.
+#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                     \
+    macro_(ScalarTypeDescr::TYPE_INT8,    int8_t,   int8)            \
+    macro_(ScalarTypeDescr::TYPE_UINT8,   uint8_t,  uint8)           \
+    macro_(ScalarTypeDescr::TYPE_INT16,   int16_t,  int16)           \
+    macro_(ScalarTypeDescr::TYPE_UINT16,  uint16_t, uint16)          \
+    macro_(ScalarTypeDescr::TYPE_INT32,   int32_t,  int32)           \
+    macro_(ScalarTypeDescr::TYPE_UINT32,  uint32_t, uint32)          \
+    macro_(ScalarTypeDescr::TYPE_FLOAT32, float,    float32)         \
+    macro_(ScalarTypeDescr::TYPE_FLOAT64, double,   float64)
+
+// Must be in same order as the enum ScalarTypeDescr::Type:
+#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
+    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
+    macro_(ScalarTypeDescr::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
+
+// Type for reference type constructors like `Any`, `String`, and
+// `Object`. All such type constructors share a common js::Class and
+// JSFunctionSpec. All these types are opaque.
+class ReferenceTypeDescr : public SimpleTypeDescr
+{
+  public:
+    // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
+    enum Type {
+        TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
+        TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
+        TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
+    };
+    static const int32_t TYPE_MAX = TYPE_STRING + 1;
+    static const char *typeName(Type type);
+
+    static const Class class_;
+    static const JSFunctionSpec typeObjectMethods[];
+    typedef ReferenceTypeRepresentation TypeRepr;
+
+    ReferenceTypeDescr::Type type() const {
+        return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
+    }
+
+    static bool call(JSContext *cx, unsigned argc, Value *vp);
+};
+
+#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_)                    \
+    macro_(ReferenceTypeDescr::TYPE_ANY,    HeapValue, Any)        \
+    macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
+    macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
+
+/*
+ * Type descriptors `float32x4` and `int32x4`
+ */
+class X4TypeDescr : public SizedTypeDescr
+{
+  public:
+    enum Type {
+        TYPE_INT32 = JS_X4TYPEREPR_INT32,
+        TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
     };
 
     static const Class class_;
+    typedef X4TypeRepresentation TypeRepr;
 
-    static bool getSuitableClaspAndProto(JSContext *cx,
-                                         TypeDescr::Kind kind,
-                                         const Class **clasp,
-                                         MutableHandleObject proto);
+    X4TypeDescr::Type type() const {
+        return (X4TypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
+    }
+
+    static bool call(JSContext *cx, unsigned argc, Value *vp);
+    static bool is(const Value &v);
 };
 
+#define JS_FOR_EACH_X4_TYPE_REPR(macro_)                             \
+    macro_(X4TypeDescr::TYPE_INT32, int32_t, int32)                  \
+    macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
+
+bool IsTypedObjectClass(const Class *clasp); // Defined in TypedArrayObject.h
+
 bool InitializeCommonTypeDescriptorProperties(JSContext *cx,
                                               HandleTypeDescr obj,
                                               HandleObject typeReprOwnerObj);
 
 /*
  * Properties and methods of the `ArrayType` meta type object. There
  * is no `class_` field because `ArrayType` is just a native
  * constructor function.
@@ -256,16 +425,37 @@ class StructTypeDescr : public SizedType
 
     // Return the offset of the field at index `index`.
     size_t fieldOffset(size_t index);
 };
 
 typedef Handle<StructTypeDescr*> HandleStructTypeDescr;
 
 /*
+ * This object exists in order to encapsulate the typed object types
+ * somewhat, rather than sticking them all into the global object.
+ * Eventually it will go away and become a module.
+ */
+class TypedObjectModuleObject : public JSObject {
+  public:
+    enum Slot {
+        ArrayTypePrototype,
+        StructTypePrototype,
+        SlotCount
+    };
+
+    static const Class class_;
+
+    static bool getSuitableClaspAndProto(JSContext *cx,
+                                         TypeDescr::Kind kind,
+                                         const Class **clasp,
+                                         MutableHandleObject proto);
+};
+
+/*
  * Base type for typed objects and handles. Basically any type whose
  * contents consist of typed memory.
  */
 class TypedObject : public ArrayBufferViewObject
 {
   private:
     static const bool IsTypedObjectClass = true;
 
deleted file mode 100644
--- a/js/src/builtin/TypedObjectSimple.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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/. */
-
-#include "builtin/TypedObjectSimple.h"
-
-using mozilla::DebugOnly;
-
-using namespace js;
-
-/***************************************************************************
- * Type descriptors
- */
-
-TypeRepresentation *
-TypeDescr::typeRepresentation() const {
-    return TypeRepresentation::fromOwnerObject(typeRepresentationOwnerObj());
-}
-
-TypeDescr::Kind
-TypeDescr::kind() const {
-    return typeRepresentation()->kind();
-}
-
-bool
-TypeDescr::opaque() const {
-    return typeRepresentation()->opaque();
-}
-
-/***************************************************************************
- * Scalar type objects
- *
- * Scalar type objects like `uint8`, `uint16`, are all instances of
- * the ScalarTypeDescr class. Like all type objects, they have a reserved
- * slot pointing to a TypeRepresentation object, which is used to
- * distinguish which scalar type object this actually is.
- */
-
-const Class js::ScalarTypeDescr::class_ = {
-    "Scalar",
-    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
-    JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    ScalarTypeDescr::call,
-    nullptr,
-    nullptr,
-    nullptr
-};
-
-const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
-    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
-    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
-    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
-    JS_FS_END
-};
-
-static size_t ScalarSizes[] = {
-#define SCALAR_SIZE(_kind, _type, _name)                        \
-    sizeof(_type),
-    JS_FOR_EACH_SCALAR_TYPE_REPR(SCALAR_SIZE) 0
-#undef SCALAR_SIZE
-};
-
-size_t
-ScalarTypeDescr::size(Type t)
-{
-    return ScalarSizes[t];
-}
-
-size_t
-ScalarTypeDescr::alignment(Type t)
-{
-    return ScalarSizes[t];
-}
-
-/*static*/ const char *
-ScalarTypeDescr::typeName(Type type)
-{
-    switch (type) {
-#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
-        case constant_: return #name_;
-        JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
-bool
-ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() < 1) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
-                             args.callee().getClass()->name, "0", "s");
-        return false;
-    }
-
-    ScalarTypeRepresentation *typeRepr =
-        args.callee().as<ScalarTypeDescr>().typeRepresentation()->asScalar();
-    ScalarTypeDescr::Type type = typeRepr->type();
-
-    double number;
-    if (!ToNumber(cx, args[0], &number))
-        return false;
-
-    if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED)
-        number = ClampDoubleToUint8(number);
-
-    switch (type) {
-#define SCALARTYPE_CALL(constant_, type_, name_)                             \
-      case constant_: {                                                       \
-          type_ converted = ConvertScalar<type_>(number);                     \
-          args.rval().setNumber((double) converted);                          \
-          return true;                                                        \
-      }
-
-        JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL)
-#undef SCALARTYPE_CALL
-
-    }
-    return true;
-}
-
-/***************************************************************************
- * Reference type objects
- *
- * Reference type objects like `Any` or `Object` basically work the
- * same way that the scalar type objects do. There is one class with
- * many instances, and each instance has a reserved slot with a
- * TypeRepresentation object, which is used to distinguish which
- * reference type object this actually is.
- */
-
-const Class js::ReferenceTypeDescr::class_ = {
-    "Reference",
-    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
-    JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    ReferenceTypeDescr::call,
-    nullptr,
-    nullptr,
-    nullptr
-};
-
-const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
-    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
-    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
-    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
-    JS_FS_END
-};
-
-/*static*/ const char *
-ReferenceTypeDescr::typeName(Type type)
-{
-    switch (type) {
-#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
-        case constant_: return #name_;
-        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
-bool
-js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    JS_ASSERT(args.callee().is<ReferenceTypeDescr>());
-    ReferenceTypeRepresentation *typeRepr =
-        args.callee().as<ReferenceTypeDescr>().typeRepresentation()->asReference();
-
-    if (args.length() < 1) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
-                             JSMSG_MORE_ARGS_NEEDED,
-                             typeRepr->typeName(), "0", "s");
-        return false;
-    }
-
-    switch (typeRepr->type()) {
-      case ReferenceTypeDescr::TYPE_ANY:
-        args.rval().set(args[0]);
-        return true;
-
-      case ReferenceTypeDescr::TYPE_OBJECT:
-      {
-        RootedObject obj(cx, ToObject(cx, args[0]));
-        if (!obj)
-            return false;
-        args.rval().setObject(*obj);
-        return true;
-      }
-
-      case ReferenceTypeDescr::TYPE_STRING:
-      {
-        RootedString obj(cx, ToString<CanGC>(cx, args[0]));
-        if (!obj)
-            return false;
-        args.rval().setString(&*obj);
-        return true;
-      }
-    }
-
-    MOZ_ASSUME_UNREACHABLE("Unhandled Reference type");
-}
deleted file mode 100644
--- a/js/src/builtin/TypedObjectSimple.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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 builtin_TypedObjectSimple_h
-#define builtin_TypedObjectSimple_h
-
-#include "jsobj.h"
-
-#include "builtin/TypedObjectConstants.h"
-
-/*
- * Simple Typed Objects
- * --------------------
- *
- * Contains definitions for the "simple" type descriptors like scalar
- * and reference types. These are pulled apart from the rest of the
- * typed object primarily so that this file can be included from
- * TypedArrayObject.h, but it also helps to reduce the monolithic
- * nature of TypedObject.h.
- */
-
-namespace js {
-
-class TypeRepresentation;
-class ScalarTypeRepresentation;
-class ReferenceTypeRepresentation;
-class X4TypeRepresentation;
-class StructTypeDescr;
-
-/*
- * Helper method for converting a double into other scalar
- * types in the same way that JavaScript would. In particular,
- * simple C casting from double to int32_t gets things wrong
- * for values like 0xF0000000.
- */
-template <typename T>
-static T ConvertScalar(double d)
-{
-    if (TypeIsFloatingPoint<T>()) {
-        return T(d);
-    } else if (TypeIsUnsigned<T>()) {
-        uint32_t n = ToUint32(d);
-        return T(n);
-    } else {
-        int32_t n = ToInt32(d);
-        return T(n);
-    }
-}
-
-class TypeDescr : public JSObject
-{
-  public:
-    enum Kind {
-        Scalar = JS_TYPEREPR_SCALAR_KIND,
-        Reference = JS_TYPEREPR_REFERENCE_KIND,
-        X4 = JS_TYPEREPR_X4_KIND,
-        Struct = JS_TYPEREPR_STRUCT_KIND,
-        SizedArray = JS_TYPEREPR_SIZED_ARRAY_KIND,
-        UnsizedArray = JS_TYPEREPR_UNSIZED_ARRAY_KIND,
-    };
-
-    static bool isSized(Kind kind) {
-        return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
-    }
-
-    JSObject &typeRepresentationOwnerObj() const {
-        return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
-    }
-
-    TypeRepresentation *typeRepresentation() const;
-
-    TypeDescr::Kind kind() const;
-
-    bool opaque() const;
-
-    size_t alignment() {
-        return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
-    }
-};
-
-typedef Handle<TypeDescr*> HandleTypeDescr;
-
-class SizedTypeDescr : public TypeDescr
-{
-  public:
-    size_t size() {
-        return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
-    }
-};
-
-typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
-
-class SimpleTypeDescr : public SizedTypeDescr
-{
-};
-
-// Type for scalar type constructors like `uint8`. All such type
-// constructors share a common js::Class and JSFunctionSpec. Scalar
-// types are non-opaque (their storage is visible unless combined with
-// an opaque reference type.)
-class ScalarTypeDescr : public SimpleTypeDescr
-{
-  public:
-    // Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
-    enum Type {
-        TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
-        TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
-        TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
-        TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
-        TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
-        TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
-        TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
-        TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
-
-        /*
-         * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
-         * Treat the raw data type as a uint8_t.
-         */
-        TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
-    };
-    static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
-
-    static size_t size(Type t);
-    static size_t alignment(Type t);
-    static const char *typeName(Type type);
-
-    static const Class class_;
-    static const JSFunctionSpec typeObjectMethods[];
-    typedef ScalarTypeRepresentation TypeRepr;
-
-    ScalarTypeDescr::Type type() const {
-        return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
-    }
-
-    static bool call(JSContext *cx, unsigned argc, Value *vp);
-};
-
-// Enumerates the cases of ScalarTypeDescr::Type which have
-// unique C representation. In particular, omits Uint8Clamped since it
-// is just a Uint8.
-#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                     \
-    macro_(ScalarTypeDescr::TYPE_INT8,    int8_t,   int8)            \
-    macro_(ScalarTypeDescr::TYPE_UINT8,   uint8_t,  uint8)           \
-    macro_(ScalarTypeDescr::TYPE_INT16,   int16_t,  int16)           \
-    macro_(ScalarTypeDescr::TYPE_UINT16,  uint16_t, uint16)          \
-    macro_(ScalarTypeDescr::TYPE_INT32,   int32_t,  int32)           \
-    macro_(ScalarTypeDescr::TYPE_UINT32,  uint32_t, uint32)          \
-    macro_(ScalarTypeDescr::TYPE_FLOAT32, float,    float32)         \
-    macro_(ScalarTypeDescr::TYPE_FLOAT64, double,   float64)
-
-// Must be in same order as the enum ScalarTypeDescr::Type:
-#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
-    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
-    macro_(ScalarTypeDescr::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
-
-// Type for reference type constructors like `Any`, `String`, and
-// `Object`. All such type constructors share a common js::Class and
-// JSFunctionSpec. All these types are opaque.
-class ReferenceTypeDescr : public SimpleTypeDescr
-{
-  public:
-    // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
-    enum Type {
-        TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
-        TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
-        TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
-    };
-    static const int32_t TYPE_MAX = TYPE_STRING + 1;
-    static const char *typeName(Type type);
-
-    static const Class class_;
-    static const JSFunctionSpec typeObjectMethods[];
-    typedef ReferenceTypeRepresentation TypeRepr;
-
-    ReferenceTypeDescr::Type type() const {
-        return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
-    }
-
-    static bool call(JSContext *cx, unsigned argc, Value *vp);
-};
-
-#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_)                    \
-    macro_(ReferenceTypeDescr::TYPE_ANY,    HeapValue, Any)        \
-    macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
-    macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
-
-/*
- * Type descriptors `float32x4` and `int32x4`
- */
-class X4TypeDescr : public SizedTypeDescr
-{
-  public:
-    enum Type {
-        TYPE_INT32 = JS_X4TYPEREPR_INT32,
-        TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
-    };
-
-    static const Class class_;
-    typedef X4TypeRepresentation TypeRepr;
-
-    X4TypeDescr::Type type() const {
-        return (X4TypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
-    }
-
-    static bool call(JSContext *cx, unsigned argc, Value *vp);
-    static bool is(const Value &v);
-};
-
-#define JS_FOR_EACH_X4_TYPE_REPR(macro_)                             \
-    macro_(X4TypeDescr::TYPE_INT32, int32_t, int32)                  \
-    macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
-
-bool IsTypedObjectClass(const Class *clasp); // Defined in TypedArrayObject.h
-
-} // namespace js
-
-#endif
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -95,17 +95,16 @@ UNIFIED_SOURCES += [
     'builtin/Eval.cpp',
     'builtin/Intl.cpp',
     'builtin/MapObject.cpp',
     'builtin/Object.cpp',
     'builtin/Profilers.cpp',
     'builtin/SIMD.cpp',
     'builtin/TestingFunctions.cpp',
     'builtin/TypedObject.cpp',
-    'builtin/TypedObjectSimple.cpp',
     'builtin/TypeRepresentation.cpp',
     'devtools/sharkctl.cpp',
     'ds/LifoAlloc.cpp',
     'frontend/BytecodeCompiler.cpp',
     'frontend/BytecodeEmitter.cpp',
     'frontend/FoldConstants.cpp',
     'frontend/NameFunctions.cpp',
     'frontend/ParseMaps.cpp',
@@ -151,16 +150,17 @@ UNIFIED_SOURCES += [
     'jsstr.cpp',
     'jswatchpoint.cpp',
     'jsweakmap.cpp',
     'jsworkers.cpp',
     'jswrapper.cpp',
     'perf/jsperf.cpp',
     'prmjtime.cpp',
     'vm/ArgumentsObject.cpp',
+    'vm/ArrayBufferObject.cpp',
     'vm/CallNonGenericMethod.cpp',
     'vm/CharacterEncoding.cpp',
     'vm/Compression.cpp',
     'vm/DateTime.cpp',
     'vm/Debugger.cpp',
     'vm/ErrorObject.cpp',
     'vm/ForkJoin.cpp',
     'vm/GlobalObject.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -0,0 +1,1427 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+#include "vm/ArrayBufferObject.h"
+
+#include "mozilla/Alignment.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/PodOperations.h"
+
+#include <string.h>
+#ifndef XP_WIN
+# include <sys/mman.h>
+#endif
+
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jscntxt.h"
+#include "jscpucfg.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jstypes.h"
+#include "jsutil.h"
+#ifdef XP_WIN
+# include "jswin.h"
+#endif
+#include "jswrapper.h"
+
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "jit/AsmJS.h"
+#include "jit/AsmJSModule.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/NumericConversions.h"
+#include "vm/WrapperObject.h"
+
+#include "jsatominlines.h"
+#include "jsinferinlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/Shape-inl.h"
+
+#if JS_USE_NEW_OBJECT_REPRESENTATION
+// See the comment above OldObjectRepresentationHack.
+#  error "TypedArray support for new object representation unimplemented."
+#endif
+
+using namespace js;
+using namespace js::gc;
+using namespace js::types;
+
+/*
+ * Allocate array buffers with the maximum number of fixed slots marked as
+ * reserved, so that the fixed slots may be used for the buffer's contents.
+ * The last fixed slot is kept for the object's private data.
+ */
+static const uint8_t ARRAYBUFFER_RESERVED_SLOTS = JSObject::MAX_FIXED_SLOTS - 1;
+
+// Sentinel value used to initialize ArrayBufferViewObjects' NEXT_BUFFER_SLOTs
+// to show that they have not yet been added to any ArrayBufferObject list.
+js::ArrayBufferObject * const js::UNSET_BUFFER_LINK = reinterpret_cast<js::ArrayBufferObject*>(0x2);
+
+/*
+ * Convert |v| to an array index for an array of length |length| per
+ * the Typed Array Specification section 7.0, |subarray|. If successful,
+ * the output value is in the range [0, length].
+ */
+bool
+js::ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out)
+{
+    int32_t result;
+    if (!ToInt32(cx, v, &result))
+        return false;
+    if (result < 0) {
+        result += length;
+        if (result < 0)
+            result = 0;
+    } else if (uint32_t(result) > length) {
+        result = length;
+    }
+    *out = uint32_t(result);
+    return true;
+}
+
+/*
+ * ArrayBufferObject
+ *
+ * This class holds the underlying raw buffer that the TypedArrayObject classes
+ * access.  It can be created explicitly and passed to a TypedArrayObject, or
+ * can be created implicitly by constructing a TypedArrayObject with a size.
+ */
+
+/*
+ * ArrayBufferObject (base)
+ */
+
+const Class ArrayBufferObject::protoClass = {
+    "ArrayBufferPrototype",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
+    JS_PropertyStub,         /* addProperty */
+    JS_DeletePropertyStub,   /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
+const Class ArrayBufferObject::class_ = {
+    "ArrayBuffer",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_IMPLEMENTS_BARRIERS |
+    Class::NON_NATIVE |
+    JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
+    JS_PropertyStub,         /* addProperty */
+    JS_DeletePropertyStub,   /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,        /* finalize    */
+    nullptr,        /* call        */
+    nullptr,        /* hasInstance */
+    nullptr,        /* construct   */
+    ArrayBufferObject::obj_trace,
+    JS_NULL_CLASS_SPEC,
+    JS_NULL_CLASS_EXT,
+    {
+        ArrayBufferObject::obj_lookupGeneric,
+        ArrayBufferObject::obj_lookupProperty,
+        ArrayBufferObject::obj_lookupElement,
+        ArrayBufferObject::obj_lookupSpecial,
+        ArrayBufferObject::obj_defineGeneric,
+        ArrayBufferObject::obj_defineProperty,
+        ArrayBufferObject::obj_defineElement,
+        ArrayBufferObject::obj_defineSpecial,
+        ArrayBufferObject::obj_getGeneric,
+        ArrayBufferObject::obj_getProperty,
+        ArrayBufferObject::obj_getElement,
+        ArrayBufferObject::obj_getSpecial,
+        ArrayBufferObject::obj_setGeneric,
+        ArrayBufferObject::obj_setProperty,
+        ArrayBufferObject::obj_setElement,
+        ArrayBufferObject::obj_setSpecial,
+        ArrayBufferObject::obj_getGenericAttributes,
+        ArrayBufferObject::obj_setGenericAttributes,
+        ArrayBufferObject::obj_deleteProperty,
+        ArrayBufferObject::obj_deleteElement,
+        ArrayBufferObject::obj_deleteSpecial,
+        nullptr, nullptr, /* watch/unwatch */
+        nullptr,          /* slice */
+        ArrayBufferObject::obj_enumerate,
+        nullptr,          /* thisObject      */
+    }
+};
+
+const JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
+    JS_FN("slice", ArrayBufferObject::fun_slice, 2, JSFUN_GENERIC_NATIVE),
+    JS_FS_END
+};
+
+const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
+    JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
+    JS_FS_END
+};
+
+MOZ_ALWAYS_INLINE bool
+ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
+{
+    JS_ASSERT(IsArrayBuffer(args.thisv()));
+    args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
+    return true;
+}
+
+bool
+ArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
+}
+
+bool
+ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
+{
+    JS_ASSERT(IsArrayBuffer(args.thisv()));
+
+    Rooted<ArrayBufferObject*> thisObj(cx, &args.thisv().toObject().as<ArrayBufferObject>());
+
+    // these are the default values
+    uint32_t length = thisObj->byteLength();
+    uint32_t begin = 0, end = length;
+
+    if (args.length() > 0) {
+        if (!ToClampedIndex(cx, args[0], length, &begin))
+            return false;
+
+        if (args.length() > 1) {
+            if (!ToClampedIndex(cx, args[1], length, &end))
+                return false;
+        }
+    }
+
+    if (begin > end)
+        begin = end;
+
+    JSObject *nobj = createSlice(cx, thisObj, begin, end);
+    if (!nobj)
+        return false;
+    args.rval().setObject(*nobj);
+    return true;
+}
+
+bool
+ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsArrayBuffer, fun_slice_impl>(cx, args);
+}
+
+/*
+ * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
+ */
+bool
+ArrayBufferObject::fun_isView(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    args.rval().setBoolean(args.get(0).isObject() &&
+                           JS_IsArrayBufferViewObject(&args.get(0).toObject()));
+    return true;
+}
+
+/*
+ * new ArrayBuffer(byteLength)
+ */
+bool
+ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
+{
+    int32_t nbytes = 0;
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
+        return false;
+
+    if (nbytes < 0) {
+        /*
+         * We're just not going to support arrays that are bigger than what will fit
+         * as an integer value; if someone actually ever complains (validly), then we
+         * can fix.
+         */
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+        return false;
+    }
+
+    JSObject *bufobj = create(cx, uint32_t(nbytes));
+    if (!bufobj)
+        return false;
+    args.rval().setObject(*bufobj);
+    return true;
+}
+
+/*
+ * Note that some callers are allowed to pass in a nullptr cx, so we allocate
+ * with the cx if available and fall back to the runtime.  If oldptr is given,
+ * it's expected to be a previously-allocated ObjectElements* pointer that we
+ * then realloc.
+ */
+static ObjectElements *
+AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr)
+{
+    uint32_t size = nbytes + sizeof(ObjectElements);
+    ObjectElements *newheader;
+
+    // if oldptr is given, then we need to do a realloc
+    if (oldptr) {
+        ObjectElements *oldheader = static_cast<ObjectElements *>(oldptr);
+        uint32_t oldnbytes = ArrayBufferObject::headerInitializedLength(oldheader);
+
+        void *p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, size) : js_realloc(oldptr, size);
+        newheader = static_cast<ObjectElements *>(p);
+
+        // if we grew the array, we need to set the new bytes to 0
+        if (newheader && nbytes > oldnbytes)
+            memset(reinterpret_cast<uint8_t*>(newheader->elements()) + oldnbytes, 0, nbytes - oldnbytes);
+    } else {
+        void *p = maybecx ? maybecx->runtime()->callocCanGC(size) : js_calloc(size);
+        newheader = static_cast<ObjectElements *>(p);
+    }
+    if (!newheader) {
+        if (maybecx)
+            js_ReportOutOfMemory(maybecx);
+        return nullptr;
+    }
+
+    ArrayBufferObject::updateElementsHeader(newheader, nbytes);
+
+    return newheader;
+}
+
+// The list of views must be stored somewhere in the ArrayBufferObject, but
+// the slots are already being used for the element storage and the private
+// field is used for a delegate object. The ObjectElements header has space
+// for it, but I don't want to mess around with adding unions to it with
+// JS_USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much
+// more cleanly.
+struct OldObjectRepresentationHack {
+    uint32_t flags;
+    uint32_t initializedLength;
+    EncapsulatedPtr<ArrayBufferViewObject> views;
+};
+
+static ArrayBufferViewObject *
+GetViewList(ArrayBufferObject *obj)
+{
+    return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
+}
+
+static void
+SetViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
+{
+    reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views = viewsHead;
+    PostBarrierTypedArrayObject(obj);
+}
+
+static void
+InitViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
+{
+    reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views.init(viewsHead);
+    PostBarrierTypedArrayObject(obj);
+}
+
+static EncapsulatedPtr<ArrayBufferViewObject> &
+GetViewListRef(ArrayBufferObject *obj)
+{
+    JS_ASSERT(obj->runtimeFromMainThread()->isHeapBusy());
+    return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
+}
+
+/* static */ bool
+ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+    ArrayBufferViewObject *view;
+    size_t numViews = 0;
+    for (view = GetViewList(buffer); view; view = view->nextView()) {
+        numViews++;
+        view->neuter(cx);
+
+        // Notify compiled jit code that the base pointer has moved.
+        MarkObjectStateChange(cx, view);
+    }
+
+    // neuterAsmJSArrayBuffer adjusts state specific to the ArrayBuffer data
+    // itself, but it only affects the behavior of views
+    if (buffer->isAsmJSArrayBuffer()) {
+        if (!ArrayBufferObject::neuterAsmJSArrayBuffer(cx, *buffer))
+            return false;
+    }
+
+    // Remove buffer from the list of buffers with > 1 view.
+    if (numViews > 1 && GetViewList(buffer)->bufferLink() != UNSET_BUFFER_LINK) {
+        ArrayBufferObject *prev = buffer->compartment()->gcLiveArrayBuffers;
+        if (prev == buffer) {
+            buffer->compartment()->gcLiveArrayBuffers = GetViewList(prev)->bufferLink();
+        } else {
+            for (ArrayBufferObject *b = GetViewList(prev)->bufferLink();
+                 b;
+                 b = GetViewList(b)->bufferLink())
+            {
+                if (b == buffer) {
+                    GetViewList(prev)->setBufferLink(GetViewList(b)->bufferLink());
+                    break;
+                }
+                prev = b;
+            }
+        }
+    }
+
+    return true;
+}
+
+void
+ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
+{
+    JS_ASSERT(!isAsmJSArrayBuffer());
+
+    // Grab out data before invalidating it.
+    uint32_t byteLengthCopy = byteLength();
+    uintptr_t oldDataPointer = uintptr_t(dataPointer());
+    ArrayBufferViewObject *viewListHead = GetViewList(this);
+
+    // Update all views.
+    uintptr_t newDataPointer = uintptr_t(newHeader->elements());
+    for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
+        uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer;
+        view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
+
+        // Notify compiled jit code that the base pointer has moved.
+        MarkObjectStateChange(cx, view);
+    }
+
+    // The list of views in the old header is reachable if the contents are
+    // being transferred, so null it out
+    SetViewList(this, nullptr);
+
+#ifdef JSGC_GENERATIONAL
+    ObjectElements *oldHeader = ObjectElements::fromElements(elements);
+    JS_ASSERT(oldHeader != newHeader);
+    JSRuntime *rt = runtimeFromMainThread();
+    if (hasDynamicElements())
+        rt->gcNursery.notifyRemovedElements(this, oldHeader);
+#endif
+
+    elements = newHeader->elements();
+
+#ifdef JSGC_GENERATIONAL
+    if (hasDynamicElements())
+        rt->gcNursery.notifyNewElements(this, newHeader);
+#endif
+
+    initElementsHeader(newHeader, byteLengthCopy);
+    InitViewList(this, viewListHead);
+}
+
+void
+ArrayBufferObject::neuter(JSContext *cx)
+{
+    JS_ASSERT(cx);
+    if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
+        ObjectElements *oldHeader = getElementsHeader();
+        changeContents(cx, ObjectElements::fromElements(fixedElements()));
+
+        FreeOp fop(cx->runtime(), false);
+        fop.free_(oldHeader);
+    }
+
+    uint32_t byteLen = 0;
+    updateElementsHeader(getElementsHeader(), byteLen);
+
+    getElementsHeader()->setIsNeuteredBuffer();
+}
+
+/* static */ bool
+ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+    if (buffer->hasDynamicElements())
+        return true;
+
+    ObjectElements *newHeader = AllocateArrayBufferContents(cx, buffer->byteLength());
+    if (!newHeader)
+        return false;
+
+    void *newHeaderDataPointer = reinterpret_cast<void*>(newHeader->elements());
+    memcpy(newHeaderDataPointer, buffer->dataPointer(), buffer->byteLength());
+
+    buffer->changeContents(cx, newHeader);
+    return true;
+}
+
+#if defined(JS_ION) && defined(JS_CPU_X64)
+// To avoid dynamically checking bounds on each load/store, asm.js code relies
+// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
+// if we can guarantee that *any* out-of-bounds access generates a fault. This
+// isn't generally true since an out-of-bounds access could land on other
+// Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
+// making only the range [0, byteLength) accessible, and use a 32-bit unsigned
+// index into this space. (x86 and ARM require different tricks.)
+//
+// One complication is that we need to put an ObjectElements struct immediately
+// before the data array (as required by the general JSObject data structure).
+// Thus, we must stick a page before the elements to hold ObjectElements.
+//
+//   |<------------------------------ 4GB + 1 pages --------------------->|
+//           |<--- sizeof --->|<------------------- 4GB ----------------->|
+//
+//   | waste | ObjectElements | data array | inaccessible reserved memory |
+//                            ^            ^                              ^
+//                            |            \                             /
+//                      obj->elements       required to be page boundaries
+//
+JS_STATIC_ASSERT(sizeof(ObjectElements) < AsmJSPageSize);
+JS_STATIC_ASSERT(AsmJSAllocationGranularity == AsmJSPageSize);
+static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
+
+bool
+ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+    if (buffer->isAsmJSArrayBuffer())
+        return true;
+
+    // Get the entire reserved region (with all pages inaccessible).
+    void *p;
+# ifdef XP_WIN
+    p = VirtualAlloc(nullptr, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);
+    if (!p)
+        return false;
+# else
+    p = mmap(nullptr, AsmJSMappedSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (p == MAP_FAILED)
+        return false;
+# endif
+
+    // Enable access to the valid region.
+    JS_ASSERT(buffer->byteLength() % AsmJSAllocationGranularity == 0);
+# ifdef XP_WIN
+    if (!VirtualAlloc(p, AsmJSPageSize + buffer->byteLength(), MEM_COMMIT, PAGE_READWRITE)) {
+        VirtualFree(p, 0, MEM_RELEASE);
+        return false;
+    }
+# else
+    if (mprotect(p, AsmJSPageSize + buffer->byteLength(), PROT_READ | PROT_WRITE)) {
+        munmap(p, AsmJSMappedSize);
+        return false;
+    }
+# endif
+
+    // Copy over the current contents of the typed array.
+    uint8_t *data = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
+    memcpy(data, buffer->dataPointer(), buffer->byteLength());
+
+    // Swap the new elements into the ArrayBufferObject.
+    ObjectElements *newHeader = reinterpret_cast<ObjectElements*>(data - sizeof(ObjectElements));
+    ObjectElements *oldHeader = buffer->hasDynamicElements() ? buffer->getElementsHeader()
+                                                             : nullptr;
+    buffer->changeContents(cx, newHeader);
+    js_free(oldHeader);
+
+    // Mark the ArrayBufferObject so (1) we don't do this again, (2) we know not
+    // to js_free the header in the normal way.
+    newHeader->setIsAsmJSArrayBuffer();
+    JS_ASSERT(data == buffer->dataPointer());
+    return true;
+}
+
+void
+ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
+{
+    ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
+    JS_ASSERT(buffer.isAsmJSArrayBuffer());
+
+    uint8_t *p = buffer.dataPointer() - AsmJSPageSize ;
+    JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
+# ifdef XP_WIN
+    VirtualFree(p, 0, MEM_RELEASE);
+# else
+    munmap(p, AsmJSMappedSize);
+# endif
+}
+#else  /* defined(JS_ION) && defined(JS_CPU_X64) */
+bool
+ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+    if (buffer->isAsmJSArrayBuffer())
+        return true;
+
+    if (!ensureNonInline(cx, buffer))
+        return false;
+
+    JS_ASSERT(buffer->hasDynamicElements());
+    buffer->getElementsHeader()->setIsAsmJSArrayBuffer();
+    return true;
+}
+
+void
+ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
+{
+    fop->free_(obj->as<ArrayBufferObject>().getElementsHeader());
+}
+#endif
+
+bool
+ArrayBufferObject::neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
+{
+#ifdef JS_ION
+    AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
+    for (; act; act = act->prev()) {
+        if (act->module().maybeHeapBufferObject() == &buffer)
+            break;
+    }
+    if (!act)
+        return true;
+
+    js_ReportOverRecursed(cx);
+    return false;
+#else
+    return true;
+#endif
+}
+
+void
+ArrayBufferObject::addView(ArrayBufferViewObject *view)
+{
+    // This view should never have been associated with a buffer before
+    JS_ASSERT(view->bufferLink() == UNSET_BUFFER_LINK);
+
+    // Note that pre-barriers are not needed here because either the list was
+    // previously empty, in which case no pointer is being overwritten, or the
+    // list was nonempty and will be made weak during this call (and weak
+    // pointers cannot violate the snapshot-at-the-beginning invariant.)
+
+    ArrayBufferViewObject *viewsHead = GetViewList(this);
+    if (viewsHead == nullptr) {
+        // This ArrayBufferObject will have a single view at this point, so it
+        // is a strong pointer (it will be marked during tracing.)
+        JS_ASSERT(view->nextView() == nullptr);
+    } else {
+        view->prependToViews(viewsHead);
+    }
+
+    SetViewList(this, view);
+}
+
+ArrayBufferObject *
+ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, bool clear /* = true */)
+{
+    Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(cx));
+    if (!obj)
+        return nullptr;
+    JS_ASSERT_IF(obj->isTenured(), obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT16_BACKGROUND);
+    JS_ASSERT(obj->getClass() == &class_);
+
+    js::Shape *empty = EmptyShape::getInitialShape(cx, &class_,
+                                                   obj->getProto(), obj->getParent(), obj->getMetadata(),
+                                                   gc::FINALIZE_OBJECT16_BACKGROUND);
+    if (!empty)
+        return nullptr;
+    obj->setLastPropertyInfallible(empty);
+
+    // ArrayBufferObjects delegate added properties to another JSObject, so
+    // their internal layout can use the object's fixed slots for storage.
+    // Set up the object to look like an array with an elements header.
+    JS_ASSERT(!obj->hasDynamicSlots());
+    JS_ASSERT(!obj->hasDynamicElements());
+
+    // The beginning stores an ObjectElements header structure holding the
+    // length. The rest of it is a flat data store for the array buffer.
+    size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
+
+    if (nbytes > sizeof(Value) * usableSlots) {
+        ObjectElements *header = AllocateArrayBufferContents(cx, nbytes);
+        if (!header)
+            return nullptr;
+        obj->elements = header->elements();
+
+#ifdef JSGC_GENERATIONAL
+        JSRuntime *rt = obj->runtimeFromMainThread();
+        rt->gcNursery.notifyNewElements(obj, header);
+#endif
+    } else {
+        obj->setFixedElements();
+        if (clear)
+            memset(obj->dataPointer(), 0, nbytes);
+    }
+
+    obj->initElementsHeader(obj->getElementsHeader(), nbytes);
+
+    return obj;
+}
+
+JSObject *
+ArrayBufferObject::createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
+                               uint32_t begin, uint32_t end)
+{
+    JS_ASSERT(begin <= arrayBuffer->byteLength());
+    JS_ASSERT(end <= arrayBuffer->byteLength());
+    JS_ASSERT(begin <= end);
+    uint32_t length = end - begin;
+
+    if (!arrayBuffer->hasData())
+        return create(cx, 0);
+
+    JSObject *slice = create(cx, length, false);
+    if (!slice)
+        return nullptr;
+    memcpy(slice->as<ArrayBufferObject>().dataPointer(), arrayBuffer->dataPointer() + begin, length);
+    return slice;
+}
+
+bool
+ArrayBufferObject::createDataViewForThisImpl(JSContext *cx, CallArgs args)
+{
+    JS_ASSERT(IsArrayBuffer(args.thisv()));
+
+    /*
+     * This method is only called for |DataView(alienBuf, ...)| which calls
+     * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|,
+     * ergo there must be at least two arguments.
+     */
+    JS_ASSERT(args.length() >= 2);
+
+    Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
+
+    Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
+
+    /*
+     * Pop off the passed-along prototype and delegate to normal DataViewObject
+     * construction.
+     */
+    CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base());
+    return DataViewObject::construct(cx, buffer, frobbedArgs, proto);
+}
+
+bool
+ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
+}
+
+/* static */ bool
+ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
+                                 uint8_t **data)
+{
+    // If the ArrayBuffer's elements are dynamically allocated and nothing else
+    // prevents us from stealing them, transfer ownership directly.  Otherwise,
+    // the elements are small and allocated inside the ArrayBuffer object's GC
+    // header so we must make a copy.
+    ObjectElements *transferableHeader;
+    bool stolen;
+    if (buffer->hasDynamicElements() && !buffer->isAsmJSArrayBuffer()) {
+        stolen = true;
+        transferableHeader = buffer->getElementsHeader();
+    } else {
+        stolen = false;
+
+        uint32_t byteLen = buffer->byteLength();
+        transferableHeader = AllocateArrayBufferContents(cx, byteLen);
+        if (!transferableHeader)
+            return false;
+
+        initElementsHeader(transferableHeader, byteLen);
+        void *headerDataPointer = reinterpret_cast<void*>(transferableHeader->elements());
+        memcpy(headerDataPointer, buffer->dataPointer(), byteLen);
+    }
+
+    JS_ASSERT(!IsInsideNursery(cx->runtime(), transferableHeader));
+    *contents = transferableHeader;
+    *data = reinterpret_cast<uint8_t *>(transferableHeader + 1);
+
+    // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do
+    // it after copying out the data.
+    if (!ArrayBufferObject::neuterViews(cx, buffer))
+        return false;
+
+    // If the elements were taken from the neutered buffer, revert it back to
+    // using inline storage so it doesn't attempt to free the stolen elements
+    // when finalized.
+    if (stolen)
+        buffer->changeContents(cx, ObjectElements::fromElements(buffer->fixedElements()));
+
+    buffer->neuter(cx);
+    return true;
+}
+
+void
+ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
+{
+    /*
+     * If this object changes, it will get marked via the private data barrier,
+     * so it's safe to leave it Unbarriered.
+     */
+    JSObject *delegate = static_cast<JSObject*>(obj->getPrivate());
+    if (delegate) {
+        JS_SET_TRACING_LOCATION(trc, &obj->privateRef(obj->numFixedSlots()));
+        MarkObjectUnbarriered(trc, &delegate, "arraybuffer.delegate");
+        obj->setPrivateUnbarriered(delegate);
+    }
+
+    // ArrayBufferObjects need to maintain a list of possibly-weak pointers to
+    // their views. The straightforward way to update the weak pointers would
+    // be in the views' finalizers, but giving views finalizers means they
+    // cannot be swept in the background. This results in a very high
+    // performance cost.  Instead, ArrayBufferObjects with a single view hold a
+    // strong pointer to the view. This can entrain garbage when the single
+    // view becomes otherwise unreachable while the buffer is still live, but
+    // this is expected to be rare. ArrayBufferObjects with 0-1 views are
+    // expected to be by far the most common cases. ArrayBufferObjects with
+    // multiple views are collected into a linked list during collection, and
+    // then swept to prune out their dead views.
+
+    ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
+    ArrayBufferViewObject *viewsHead = GetViewList(&buffer);
+    if (!viewsHead)
+        return;
+
+    // During minor collections, mark weak pointers on the buffer strongly.
+    if (trc->runtime->isHeapMinorCollecting()) {
+        MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.viewlist");
+        ArrayBufferViewObject *prior = GetViewList(&buffer);
+        for (ArrayBufferViewObject *view = prior->nextView();
+             view;
+             prior = view, view = view->nextView())
+        {
+            MarkObjectUnbarriered(trc, &view, "arraybuffer.views");
+            prior->setNextView(view);
+        }
+        return;
+    }
+
+    ArrayBufferViewObject *firstView = viewsHead;
+    if (firstView->nextView() == nullptr) {
+        // Single view: mark it, but only if we're actually doing a GC pass
+        // right now. Otherwise, the tracing pass for barrier verification will
+        // fail if we add another view and the pointer becomes weak.
+        if (IS_GC_MARKING_TRACER(trc))
+            MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.singleview");
+    } else {
+        // Multiple views: do not mark, but append buffer to list.
+        if (IS_GC_MARKING_TRACER(trc)) {
+            // obj_trace may be called multiple times before sweep(), so avoid
+            // adding this buffer to the list multiple times.
+            if (firstView->bufferLink() == UNSET_BUFFER_LINK) {
+                JS_ASSERT(obj->compartment() == firstView->compartment());
+                ArrayBufferObject **bufList = &obj->compartment()->gcLiveArrayBuffers;
+                firstView->setBufferLink(*bufList);
+                *bufList = &obj->as<ArrayBufferObject>();
+            } else {
+#ifdef DEBUG
+                bool found = false;
+                for (ArrayBufferObject *p = obj->compartment()->gcLiveArrayBuffers;
+                     p;
+                     p = GetViewList(p)->bufferLink())
+                {
+                    if (p == obj)
+                    {
+                        JS_ASSERT(!found);
+                        found = true;
+                    }
+                }
+#endif
+            }
+        }
+    }
+}
+
+void
+ArrayBufferObject::sweep(JSCompartment *compartment)
+{
+    ArrayBufferObject *buffer = compartment->gcLiveArrayBuffers;
+    JS_ASSERT(buffer != UNSET_BUFFER_LINK);
+    compartment->gcLiveArrayBuffers = nullptr;
+
+    while (buffer) {
+        ArrayBufferViewObject *viewsHead = GetViewList(buffer);
+        JS_ASSERT(viewsHead);
+
+        ArrayBufferObject *nextBuffer = viewsHead->bufferLink();
+        JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
+        viewsHead->setBufferLink(UNSET_BUFFER_LINK);
+
+        // Rebuild the list of views of the ArrayBufferObject, discarding dead
+        // views.  If there is only one view, it will have already been marked.
+        ArrayBufferViewObject *prevLiveView = nullptr;
+        ArrayBufferViewObject *view = viewsHead;
+        while (view) {
+            JS_ASSERT(buffer->compartment() == view->compartment());
+            ArrayBufferViewObject *nextView = view->nextView();
+            if (!IsObjectAboutToBeFinalized(&view)) {
+                view->setNextView(prevLiveView);
+                prevLiveView = view;
+            }
+            view = nextView;
+        }
+        SetViewList(buffer, prevLiveView);
+
+        buffer = nextBuffer;
+    }
+}
+
+void
+ArrayBufferObject::resetArrayBufferList(JSCompartment *comp)
+{
+    ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
+    JS_ASSERT(buffer != UNSET_BUFFER_LINK);
+    comp->gcLiveArrayBuffers = nullptr;
+
+    while (buffer) {
+        ArrayBufferViewObject *view = GetViewList(buffer);
+        JS_ASSERT(view);
+
+        ArrayBufferObject *nextBuffer = view->bufferLink();
+        JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
+
+        view->setBufferLink(UNSET_BUFFER_LINK);
+        buffer = nextBuffer;
+    }
+}
+
+/* static */ bool
+ArrayBufferObject::saveArrayBufferList(JSCompartment *comp, ArrayBufferVector &vector)
+{
+    ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
+    while (buffer) {
+        JS_ASSERT(buffer != UNSET_BUFFER_LINK);
+        if (!vector.append(buffer))
+            return false;
+
+        ArrayBufferViewObject *view = GetViewList(buffer);
+        JS_ASSERT(view);
+        buffer = view->bufferLink();
+    }
+    return true;
+}
+
+/* static */ void
+ArrayBufferObject::restoreArrayBufferLists(ArrayBufferVector &vector)
+{
+    for (ArrayBufferObject **p = vector.begin(); p != vector.end(); p++) {
+        ArrayBufferObject *buffer = *p;
+        JSCompartment *comp = buffer->compartment();
+        ArrayBufferViewObject *firstView = GetViewList(buffer);
+        JS_ASSERT(firstView);
+        JS_ASSERT(firstView->compartment() == comp);
+        JS_ASSERT(firstView->bufferLink() == UNSET_BUFFER_LINK);
+        firstView->setBufferLink(comp->gcLiveArrayBuffers);
+        comp->gcLiveArrayBuffers = buffer;
+    }
+}
+
+bool
+ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                                     MutableHandleObject objp, MutableHandleShape propp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+
+    bool delegateResult = JSObject::lookupGeneric(cx, delegate, id, objp, propp);
+
+    /* If false, there was an error, so propagate it.
+     * Otherwise, if propp is non-null, the property
+     * was found. Otherwise it was not
+     * found so look in the prototype chain.
+     */
+    if (!delegateResult)
+        return false;
+
+    if (propp) {
+        if (objp == delegate)
+            objp.set(obj);
+        return true;
+    }
+
+    RootedObject proto(cx, obj->getProto());
+    if (!proto) {
+        objp.set(nullptr);
+        propp.set(nullptr);
+        return true;
+    }
+
+    return JSObject::lookupGeneric(cx, proto, id, objp, propp);
+}
+
+bool
+ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                                      MutableHandleObject objp, MutableHandleShape propp)
+{
+    Rooted<jsid> id(cx, NameToId(name));
+    return obj_lookupGeneric(cx, obj, id, objp, propp);
+}
+
+bool
+ArrayBufferObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                                     MutableHandleObject objp, MutableHandleShape propp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+
+    /*
+     * If false, there was an error, so propagate it.
+     * Otherwise, if propp is non-null, the property
+     * was found. Otherwise it was not
+     * found so look in the prototype chain.
+     */
+    if (!JSObject::lookupElement(cx, delegate, index, objp, propp))
+        return false;
+
+    if (propp) {
+        if (objp == delegate)
+            objp.set(obj);
+        return true;
+    }
+
+    RootedObject proto(cx, obj->getProto());
+    if (proto)
+        return JSObject::lookupElement(cx, proto, index, objp, propp);
+
+    objp.set(nullptr);
+    propp.set(nullptr);
+    return true;
+}
+
+bool
+ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                                     MutableHandleObject objp, MutableHandleShape propp)
+{
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return obj_lookupGeneric(cx, obj, id, objp, propp);
+}
+
+bool
+ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+    AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::DefineGeneric(cx, delegate, id, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_defineProperty(JSContext *cx, HandleObject obj,
+                                      HandlePropertyName name, HandleValue v,
+                                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+    Rooted<jsid> id(cx, NameToId(name));
+    return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
+                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+    AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
+                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                  HandleId id, MutableHandleValue vp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::GetProperty(cx, delegate, receiver, id, vp);
+}
+
+bool
+ArrayBufferObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                   HandlePropertyName name, MutableHandleValue vp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    Rooted<jsid> id(cx, NameToId(name));
+    return baseops::GetProperty(cx, delegate, receiver, id, vp);
+}
+
+bool
+ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
+                                  HandleObject receiver, uint32_t index, MutableHandleValue vp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::GetElement(cx, delegate, receiver, index, vp);
+}
+
+bool
+ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
+                                  HandleObject receiver, HandleSpecialId sid,
+                                  MutableHandleValue vp)
+{
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return obj_getGeneric(cx, obj, receiver, id, vp);
+}
+
+bool
+ArrayBufferObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                                  MutableHandleValue vp, bool strict)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+
+    return baseops::SetPropertyHelper<SequentialExecution>(cx, delegate, obj, id, 0, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_setProperty(JSContext *cx, HandleObject obj,
+                                   HandlePropertyName name, MutableHandleValue vp, bool strict)
+{
+    Rooted<jsid> id(cx, NameToId(name));
+    return obj_setGeneric(cx, obj, id, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_setElement(JSContext *cx, HandleObject obj,
+                                  uint32_t index, MutableHandleValue vp, bool strict)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+
+    return baseops::SetElementHelper(cx, delegate, obj, index, 0, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_setSpecial(JSContext *cx, HandleObject obj,
+                                  HandleSpecialId sid, MutableHandleValue vp, bool strict)
+{
+    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+    return obj_setGeneric(cx, obj, id, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
+                                            HandleId id, unsigned *attrsp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::GetAttributes(cx, delegate, id, attrsp);
+}
+
+bool
+ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
+                                            HandleId id, unsigned *attrsp)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::SetAttributes(cx, delegate, id, attrsp);
+}
+
+bool
+ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                                      bool *succeeded)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::DeleteProperty(cx, delegate, name, succeeded);
+}
+
+bool
+ArrayBufferObject::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
+                                     bool *succeeded)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::DeleteElement(cx, delegate, index, succeeded);
+}
+
+bool
+ArrayBufferObject::obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                                     bool *succeeded)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return baseops::DeleteSpecial(cx, delegate, sid, succeeded);
+}
+
+bool
+ArrayBufferObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
+                                 MutableHandleValue statep, MutableHandleId idp)
+{
+    statep.setNull();
+    return true;
+}
+
+/*
+ * ArrayBufferViewObject
+ */
+
+/*
+ * This method is used to trace TypedArrayObjects and DataViewObjects. We need
+ * a custom tracer because some of an ArrayBufferViewObject's reserved slots
+ * are weak references, and some need to be updated specially during moving
+ * GCs.
+ */
+/* static */ void
+ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
+{
+    HeapSlot &bufSlot = obj->getReservedSlotRef(BUFFER_SLOT);
+    MarkSlot(trc, &bufSlot, "typedarray.buffer");
+
+    /* Update obj's data slot if the array buffer moved. Note that during
+     * initialization, bufSlot may still be JSVAL_VOID. */
+    if (bufSlot.isObject()) {
+        ArrayBufferObject &buf = bufSlot.toObject().as<ArrayBufferObject>();
+        int32_t offset = obj->getReservedSlot(BYTEOFFSET_SLOT).toInt32();
+        obj->initPrivate(buf.dataPointer() + offset);
+    }
+
+    /* Update NEXT_VIEW_SLOT, if the view moved. */
+    IsSlotMarked(&obj->getReservedSlotRef(NEXT_VIEW_SLOT));
+}
+
+void
+ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead)
+{
+    setNextView(viewsHead);
+
+    // Move the multiview buffer list link into this view since we're
+    // prepending it to the list.
+    setBufferLink(viewsHead->bufferLink());
+    viewsHead->setBufferLink(UNSET_BUFFER_LINK);
+}
+
+void
+ArrayBufferViewObject::neuter(JSContext *cx)
+{
+    if (is<DataViewObject>())
+        as<DataViewObject>().neuter();
+    else if (is<TypedArrayObject>())
+        as<TypedArrayObject>().neuter(cx);
+    else
+        as<TypedObject>().neuter(cx);
+}
+
+/* JS Friend API */
+
+JS_FRIEND_API(bool)
+JS_IsArrayBufferViewObject(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    return obj ? obj->is<ArrayBufferViewObject>() : false;
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetArrayBufferByteLength(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
+}
+
+JS_FRIEND_API(uint8_t *)
+JS_GetArrayBufferData(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    if (!obj)
+        return nullptr;
+    return obj->as<ArrayBufferObject>().dataPointer();
+}
+
+JS_FRIEND_API(uint8_t *)
+JS_GetStableArrayBufferData(JSContext *cx, JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    if (!obj)
+        return nullptr;
+
+    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+    if (!ArrayBufferObject::ensureNonInline(cx, buffer))
+        return nullptr;
+
+    return buffer->dataPointer();
+}
+
+JS_FRIEND_API(bool)
+JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj)
+{
+    if (!obj->is<ArrayBufferObject>()) {
+        JS_ReportError(cx, "ArrayBuffer object required");
+        return false;
+    }
+
+    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+    if (!ArrayBufferObject::neuterViews(cx, buffer))
+        return false;
+    buffer->neuter(cx);
+    return true;
+}
+
+JS_FRIEND_API(JSObject *)
+JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
+{
+    JS_ASSERT(nbytes <= INT32_MAX);
+    return ArrayBufferObject::create(cx, nbytes);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_NewArrayBufferWithContents(JSContext *cx, void *contents)
+{
+    JS_ASSERT(contents);
+    JSObject *obj = ArrayBufferObject::create(cx, 0);
+    if (!obj)
+        return nullptr;
+    js::ObjectElements *elements = reinterpret_cast<js::ObjectElements *>(contents);
+    obj->setDynamicElements(elements);
+    JS_ASSERT(GetViewList(&obj->as<ArrayBufferObject>()) == nullptr);
+
+#ifdef JSGC_GENERATIONAL
+    cx->runtime()->gcNursery.notifyNewElements(obj, elements);
+#endif
+    return obj;
+}
+
+JS_PUBLIC_API(bool)
+JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes,
+                               void **contents, uint8_t **data)
+{
+    js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes);
+    if (!header)
+        return false;
+
+    ArrayBufferObject::updateElementsHeader(header, nbytes);
+
+    *contents = header;
+    *data = reinterpret_cast<uint8_t*>(header->elements());
+    return true;
+}
+
+JS_PUBLIC_API(bool)
+JS_ReallocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void **contents, uint8_t **data)
+{
+    js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes, *contents);
+    if (!header)
+        return false;
+
+    ArrayBufferObject::initElementsHeader(header, nbytes);
+
+    *contents = header;
+    *data = reinterpret_cast<uint8_t*>(header->elements());
+    return true;
+}
+
+JS_FRIEND_API(bool)
+JS_IsArrayBufferObject(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    return obj ? obj->is<ArrayBufferObject>() : false;
+}
+
+JS_PUBLIC_API(bool)
+JS_StealArrayBufferContents(JSContext *cx, HandleObject objArg, void **contents, uint8_t **data)
+{
+    JSObject *obj = CheckedUnwrap(objArg);
+    if (!obj)
+        return false;
+
+    if (!obj->is<ArrayBufferObject>()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+        return false;
+    }
+
+    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+    if (!ArrayBufferObject::stealContents(cx, buffer, contents, data))
+        return false;
+
+    return true;
+}
+
+JS_FRIEND_API(void *)
+JS_GetArrayBufferViewData(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    if (!obj)
+        return nullptr;
+    return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
+                                     : obj->as<TypedArrayObject>().viewData();
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetArrayBufferViewBuffer(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    if (!obj)
+        return nullptr;
+    return obj->as<ArrayBufferViewObject>().bufferObject();
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetArrayBufferViewByteLength(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    if (!obj)
+        return 0;
+    return obj->is<DataViewObject>()
+           ? obj->as<DataViewObject>().byteLength()
+           : obj->as<TypedArrayObject>().byteLength();
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
+{
+    if (!(obj = CheckedUnwrap(obj)))
+        return nullptr;
+    if (!(obj->is<ArrayBufferViewObject>()))
+        return nullptr;
+
+    *length = obj->is<DataViewObject>()
+              ? obj->as<DataViewObject>().byteLength()
+              : obj->as<TypedArrayObject>().byteLength();
+
+    *data = static_cast<uint8_t*>(obj->is<DataViewObject>()
+                                  ? obj->as<DataViewObject>().dataPointer()
+                                  : obj->as<TypedArrayObject>().viewData());
+    return obj;
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
+{
+    if (!(obj = CheckedUnwrap(obj)))
+        return nullptr;
+    if (!obj->is<ArrayBufferObject>())
+        return nullptr;
+
+    *length = obj->as<ArrayBufferObject>().byteLength();
+    *data = obj->as<ArrayBufferObject>().dataPointer();
+
+    return obj;
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject.h
@@ -0,0 +1,317 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 vm_ArrayBufferObject_h
+#define vm_ArrayBufferObject_h
+
+#include "jsobj.h"
+
+#include "builtin/TypedObjectConstants.h"
+#include "vm/Runtime.h"
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+class ArrayBufferViewObject;
+
+// The inheritance hierarchy for the various classes relating to typed arrays
+// is as follows.
+//
+// - JSObject
+//   - ArrayBufferObject
+//   - ArrayBufferViewObject
+//     - DataViewObject
+//     - TypedArrayObject (declared in vm/TypedArrayObject.h)
+//       - TypedArrayObjectTemplate
+//         - Int8ArrayObject
+//         - Uint8ArrayObject
+//         - ...
+//     - TypedObject (declared in builtin/TypedObject.h)
+//
+// Note that |TypedArrayObjectTemplate| is just an implementation
+// detail that makes implementing its various subclasses easier.
+
+typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector;
+
+/*
+ * ArrayBufferObject
+ *
+ * This class holds the underlying raw buffer that the various
+ * ArrayBufferViewObject subclasses (DataViewObject and the TypedArrays)
+ * access. It can be created explicitly and passed to an ArrayBufferViewObject
+ * subclass, or can be created implicitly by constructing a TypedArrayObject
+ * with a size.
+ */
+class ArrayBufferObject : public JSObject
+{
+    static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
+    static bool fun_slice_impl(JSContext *cx, CallArgs args);
+
+  public:
+    static const Class class_;
+
+    static const Class protoClass;
+    static const JSFunctionSpec jsfuncs[];
+    static const JSFunctionSpec jsstaticfuncs[];
+
+    static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);
+
+    static bool fun_slice(JSContext *cx, unsigned argc, Value *vp);
+
+    static bool fun_isView(JSContext *cx, unsigned argc, Value *vp);
+
+    static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
+
+    static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, bool clear = true);
+
+    static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
+                                 uint32_t begin, uint32_t end);
+
+    static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
+    static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
+
+    template<typename T>
+    static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);
+
+    template<typename T>
+    static bool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);
+
+    static void obj_trace(JSTracer *trc, JSObject *obj);
+
+    static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                                  MutableHandleObject objp, MutableHandleShape propp);
+    static bool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                                   MutableHandleObject objp, MutableHandleShape propp);
+    static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                                  MutableHandleObject objp, MutableHandleShape propp);
+    static bool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                                  MutableHandleObject objp, MutableHandleShape propp);
+
+    static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+    static bool obj_defineProperty(JSContext *cx, HandleObject obj,
+                                   HandlePropertyName name, HandleValue v,
+                                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+    static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
+                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+    static bool obj_defineSpecial(JSContext *cx, HandleObject obj,
+                                  HandleSpecialId sid, HandleValue v,
+                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+
+    static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
+                               HandleId id, MutableHandleValue vp);
+
+    static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                HandlePropertyName name, MutableHandleValue vp);
+
+    static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
+                               uint32_t index, MutableHandleValue vp);
+
+    static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
+                               HandleSpecialId sid, MutableHandleValue vp);
+
+    static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                               MutableHandleValue vp, bool strict);
+    static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                                MutableHandleValue vp, bool strict);
+    static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
+                               MutableHandleValue vp, bool strict);
+    static bool obj_setSpecial(JSContext *cx, HandleObject obj,
+                               HandleSpecialId sid, MutableHandleValue vp, bool strict);
+
+    static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
+                                         HandleId id, unsigned *attrsp);
+    static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
+                                         HandleId id, unsigned *attrsp);
+
+    static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                                   bool *succeeded);
+    static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
+                                  bool *succeeded);
+    static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                                  bool *succeeded);
+
+    static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
+                              MutableHandleValue statep, MutableHandleId idp);
+
+    static void sweep(JSCompartment *rt);
+
+    static void resetArrayBufferList(JSCompartment *rt);
+    static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
+    static void restoreArrayBufferLists(ArrayBufferVector &vector);
+
+    static bool stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
+                              uint8_t **data);
+
+    static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) {
+        header->initializedLength = bytes;
+
+        // NB: one or both of these fields is clobbered by GetViewList to store
+        // the 'views' link. Set them to 0 to effectively initialize 'views'
+        // to nullptr.
+        header->length = 0;
+        header->capacity = 0;
+    }
+
+    static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) {
+        header->flags = 0;
+        updateElementsHeader(header, bytes);
+    }
+
+    static uint32_t headerInitializedLength(const js::ObjectElements *header) {
+        return header->initializedLength;
+    }
+
+    void addView(ArrayBufferViewObject *view);
+
+    void changeContents(JSContext *cx, ObjectElements *newHeader);
+
+    /*
+     * Ensure data is not stored inline in the object. Used when handing back a
+     * GC-safe pointer.
+     */
+    static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+
+    uint32_t byteLength() const {
+        return getElementsHeader()->initializedLength;
+    }
+
+    /*
+     * Neuter all views of an ArrayBuffer.
+     */
+    static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+
+    inline uint8_t * dataPointer() const {
+        return (uint8_t *) elements;
+    }
+
+    /*
+     * Discard the ArrayBuffer contents. For asm.js buffers, at least, should
+     * be called after neuterViews().
+     */
+    void neuter(JSContext *cx);
+
+    /*
+     * Check if the arrayBuffer contains any data. This will return false for
+     * ArrayBuffer.prototype and neutered ArrayBuffers.
+     */
+    bool hasData() const {
+        return getClass() == &class_;
+    }
+
+    bool isAsmJSArrayBuffer() const {
+        return getElementsHeader()->isAsmJSArrayBuffer();
+    }
+    bool isNeutered() const {
+        return getElementsHeader()->isNeuteredBuffer();
+    }
+    static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+    static bool neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
+    static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
+};
+
+/*
+ * ArrayBufferViewObject
+ *
+ * Common definitions shared by all ArrayBufferViews.
+ */
+
+class ArrayBufferViewObject : public JSObject
+{
+  protected:
+    /* Offset of view in underlying ArrayBufferObject */
+    static const size_t BYTEOFFSET_SLOT  = JS_TYPEDOBJ_SLOT_BYTEOFFSET;
+
+    /* Byte length of view */
+    static const size_t BYTELENGTH_SLOT  = JS_TYPEDOBJ_SLOT_BYTELENGTH;
+
+    /* Underlying ArrayBufferObject */
+    static const size_t BUFFER_SLOT      = JS_TYPEDOBJ_SLOT_OWNER;
+
+    /* ArrayBufferObjects point to a linked list of views, chained through this slot */
+    static const size_t NEXT_VIEW_SLOT   = JS_TYPEDOBJ_SLOT_NEXT_VIEW;
+
+    /*
+     * When ArrayBufferObjects are traced during GC, they construct a linked
+     * list of ArrayBufferObjects with more than one view, chained through this
+     * slot of the first view of each ArrayBufferObject.
+     */
+    static const size_t NEXT_BUFFER_SLOT = JS_TYPEDOBJ_SLOT_NEXT_BUFFER;
+
+  public:
+    JSObject *bufferObject() const {
+        return &getFixedSlot(BUFFER_SLOT).toObject();
+    }
+
+    ArrayBufferObject *bufferLink() {
+        return static_cast<ArrayBufferObject*>(getFixedSlot(NEXT_BUFFER_SLOT).toPrivate());
+    }
+
+    inline void setBufferLink(ArrayBufferObject *buffer);
+
+    ArrayBufferViewObject *nextView() const {
+        return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
+    }
+
+    inline void setNextView(ArrayBufferViewObject *view);
+
+    void prependToViews(ArrayBufferViewObject *viewsHead);
+
+    void neuter(JSContext *cx);
+
+    static void trace(JSTracer *trc, JSObject *obj);
+};
+
+bool
+ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out);
+
+inline void
+PostBarrierTypedArrayObject(JSObject *obj)
+{
+#ifdef JSGC_GENERATIONAL
+    JS_ASSERT(obj);
+    JSRuntime *rt = obj->runtimeFromMainThread();
+    if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj))
+        rt->gcStoreBuffer.putWholeCell(obj);
+#endif
+}
+
+inline void
+InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
+{
+    /*
+     * N.B. The base of the array's data is stored in the object's
+     * private data rather than a slot to avoid alignment restrictions
+     * on private Values.
+     */
+    obj->initPrivate(buffer->dataPointer() + byteOffset);
+    PostBarrierTypedArrayObject(obj);
+}
+
+MOZ_ALWAYS_INLINE bool
+IsArrayBuffer(HandleValue v)
+{
+    return v.isObject() && v.toObject().is<ArrayBufferObject>();
+}
+
+inline void
+ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
+{
+    setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(buffer));
+    PostBarrierTypedArrayObject(this);
+}
+
+inline void
+ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view)
+{
+    setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(view));
+    PostBarrierTypedArrayObject(this);
+}
+
+} // namespace js
+
+#endif // vm_ArrayBufferObject_h
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -38,41 +38,25 @@
 #include "vm/WrapperObject.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/Shape-inl.h"
 
-#if JS_USE_NEW_OBJECT_REPRESENTATION
-// See the comment above OldObjectRepresentationHack.
-#  error "TypedArray support for new object representation unimplemented."
-#endif
-
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 using mozilla::IsNaN;
 using mozilla::PodCopy;
 using JS::CanonicalizeNaN;
 using JS::GenericNaN;
 
-/*
- * Allocate array buffers with the maximum number of fixed slots marked as
- * reserved, so that the fixed slots may be used for the buffer's contents.
- * The last fixed slot is kept for the object's private data.
- */
-static const uint8_t ARRAYBUFFER_RESERVED_SLOTS = JSObject::MAX_FIXED_SLOTS - 1;
-
-// Sentinel value used to initialize ArrayBufferViewObjects' NEXT_BUFFER_SLOTs
-// to show that they have not yet been added to any ArrayBufferObject list.
-js::ArrayBufferObject * const js::UNSET_BUFFER_LINK = reinterpret_cast<js::ArrayBufferObject*>(0x2);
-
 static bool
 ValueIsLength(const Value &v, uint32_t *len)
 {
     if (v.isInt32()) {
         int32_t i = v.toInt32();
         if (i < 0)
             return false;
         *len = i;
@@ -91,1090 +75,16 @@ ValueIsLength(const Value &v, uint32_t *
         *len = length;
         return true;
     }
 
     return false;
 }
 
 /*
- * Convert |v| to an array index for an array of length |length| per
- * the Typed Array Specification section 7.0, |subarray|. If successful,
- * the output value is in the range [0, length].
- */
-static bool
-ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out)
-{
-    int32_t result;
-    if (!ToInt32(cx, v, &result))
-        return false;
-    if (result < 0) {
-        result += length;
-        if (result < 0)
-            result = 0;
-    } else if (uint32_t(result) > length) {
-        result = length;
-    }
-    *out = uint32_t(result);
-    return true;
-}
-
-/*
- * ArrayBufferObject
- *
- * This class holds the underlying raw buffer that the TypedArrayObject classes
- * access.  It can be created explicitly and passed to a TypedArrayObject, or
- * can be created implicitly by constructing a TypedArrayObject with a size.
- */
-
-MOZ_ALWAYS_INLINE bool
-IsArrayBuffer(HandleValue v)
-{
-    return v.isObject() && v.toObject().hasClass(&ArrayBufferObject::class_);
-}
-
-MOZ_ALWAYS_INLINE bool
-ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
-{
-    JS_ASSERT(IsArrayBuffer(args.thisv()));
-    args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
-    return true;
-}
-
-bool
-ArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
-}
-
-bool
-ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
-{
-    JS_ASSERT(IsArrayBuffer(args.thisv()));
-
-    Rooted<ArrayBufferObject*> thisObj(cx, &args.thisv().toObject().as<ArrayBufferObject>());
-
-    // these are the default values
-    uint32_t length = thisObj->byteLength();
-    uint32_t begin = 0, end = length;
-
-    if (args.length() > 0) {
-        if (!ToClampedIndex(cx, args[0], length, &begin))
-            return false;
-
-        if (args.length() > 1) {
-            if (!ToClampedIndex(cx, args[1], length, &end))
-                return false;
-        }
-    }
-
-    if (begin > end)
-        begin = end;
-
-    JSObject *nobj = createSlice(cx, thisObj, begin, end);
-    if (!nobj)
-        return false;
-    args.rval().setObject(*nobj);
-    return true;
-}
-
-bool
-ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsArrayBuffer, fun_slice_impl>(cx, args);
-}
-
-/*
- * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
- */
-bool
-ArrayBufferObject::fun_isView(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(args.get(0).isObject() &&
-                           JS_IsArrayBufferViewObject(&args.get(0).toObject()));
-    return true;
-}
-
-/*
- * new ArrayBuffer(byteLength)
- */
-bool
-ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
-{
-    int32_t nbytes = 0;
-    CallArgs args = CallArgsFromVp(argc, vp);
-    if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
-        return false;
-
-    if (nbytes < 0) {
-        /*
-         * We're just not going to support arrays that are bigger than what will fit
-         * as an integer value; if someone actually ever complains (validly), then we
-         * can fix.
-         */
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
-        return false;
-    }
-
-    JSObject *bufobj = create(cx, uint32_t(nbytes));
-    if (!bufobj)
-        return false;
-    args.rval().setObject(*bufobj);
-    return true;
-}
-
-/*
- * Note that some callers are allowed to pass in a nullptr cx, so we allocate
- * with the cx if available and fall back to the runtime.  If oldptr is given,
- * it's expected to be a previously-allocated ObjectElements* pointer that we
- * then realloc.
- */
-static ObjectElements *
-AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr)
-{
-    uint32_t size = nbytes + sizeof(ObjectElements);
-    ObjectElements *newheader;
-
-    // if oldptr is given, then we need to do a realloc
-    if (oldptr) {
-        ObjectElements *oldheader = static_cast<ObjectElements *>(oldptr);
-        uint32_t oldnbytes = ArrayBufferObject::headerInitializedLength(oldheader);
-
-        void *p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, size) : js_realloc(oldptr, size);
-        newheader = static_cast<ObjectElements *>(p);
-
-        // if we grew the array, we need to set the new bytes to 0
-        if (newheader && nbytes > oldnbytes)
-            memset(reinterpret_cast<uint8_t*>(newheader->elements()) + oldnbytes, 0, nbytes - oldnbytes);
-    } else {
-        void *p = maybecx ? maybecx->runtime()->callocCanGC(size) : js_calloc(size);
-        newheader = static_cast<ObjectElements *>(p);
-    }
-    if (!newheader) {
-        if (maybecx)
-            js_ReportOutOfMemory(maybecx);
-        return nullptr;
-    }
-
-    ArrayBufferObject::updateElementsHeader(newheader, nbytes);
-
-    return newheader;
-}
-
-static inline void
-PostBarrierTypedArrayObject(JSObject *obj)
-{
-#ifdef JSGC_GENERATIONAL
-    JS_ASSERT(obj);
-    JSRuntime *rt = obj->runtimeFromMainThread();
-    if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj))
-        rt->gcStoreBuffer.putWholeCell(obj);
-#endif
-}
-
-// The list of views must be stored somewhere in the ArrayBufferObject, but
-// the slots are already being used for the element storage and the private
-// field is used for a delegate object. The ObjectElements header has space
-// for it, but I don't want to mess around with adding unions to it with
-// JS_USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much
-// more cleanly.
-struct OldObjectRepresentationHack {
-    uint32_t flags;
-    uint32_t initializedLength;
-    EncapsulatedPtr<ArrayBufferViewObject> views;
-};
-
-static ArrayBufferViewObject *
-GetViewList(ArrayBufferObject *obj)
-{
-    return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
-}
-
-static void
-SetViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
-{
-    reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views = viewsHead;
-    PostBarrierTypedArrayObject(obj);
-}
-
-static void
-InitViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
-{
-    reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views.init(viewsHead);
-    PostBarrierTypedArrayObject(obj);
-}
-
-static EncapsulatedPtr<ArrayBufferViewObject> &
-GetViewListRef(ArrayBufferObject *obj)
-{
-    JS_ASSERT(obj->runtimeFromMainThread()->isHeapBusy());
-    return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
-}
-
-/* static */ bool
-ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
-    ArrayBufferViewObject *view;
-    size_t numViews = 0;
-    for (view = GetViewList(buffer); view; view = view->nextView()) {
-        numViews++;
-        view->neuter(cx);
-
-        // Notify compiled jit code that the base pointer has moved.
-        MarkObjectStateChange(cx, view);
-    }
-
-    // neuterAsmJSArrayBuffer adjusts state specific to the ArrayBuffer data
-    // itself, but it only affects the behavior of views
-    if (buffer->isAsmJSArrayBuffer()) {
-        if (!ArrayBufferObject::neuterAsmJSArrayBuffer(cx, *buffer))
-            return false;
-    }
-
-    // Remove buffer from the list of buffers with > 1 view.
-    if (numViews > 1 && GetViewList(buffer)->bufferLink() != UNSET_BUFFER_LINK) {
-        ArrayBufferObject *prev = buffer->compartment()->gcLiveArrayBuffers;
-        if (prev == buffer) {
-            buffer->compartment()->gcLiveArrayBuffers = GetViewList(prev)->bufferLink();
-        } else {
-            for (ArrayBufferObject *b = GetViewList(prev)->bufferLink();
-                 b;
-                 b = GetViewList(b)->bufferLink())
-            {
-                if (b == buffer) {
-                    GetViewList(prev)->setBufferLink(GetViewList(b)->bufferLink());
-                    break;
-                }
-                prev = b;
-            }
-        }
-    }
-
-    return true;
-}
-
-void
-ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
-{
-    JS_ASSERT(!isAsmJSArrayBuffer());
-
-    // Grab out data before invalidating it.
-    uint32_t byteLengthCopy = byteLength();
-    uintptr_t oldDataPointer = uintptr_t(dataPointer());
-    ArrayBufferViewObject *viewListHead = GetViewList(this);
-
-    // Update all views.
-    uintptr_t newDataPointer = uintptr_t(newHeader->elements());
-    for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
-        uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer;
-        view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
-
-        // Notify compiled jit code that the base pointer has moved.
-        MarkObjectStateChange(cx, view);
-    }
-
-    // The list of views in the old header is reachable if the contents are
-    // being transferred, so null it out
-    SetViewList(this, nullptr);
-
-#ifdef JSGC_GENERATIONAL
-    ObjectElements *oldHeader = ObjectElements::fromElements(elements);
-    JS_ASSERT(oldHeader != newHeader);
-    JSRuntime *rt = runtimeFromMainThread();
-    if (hasDynamicElements())
-        rt->gcNursery.notifyRemovedElements(this, oldHeader);
-#endif
-
-    elements = newHeader->elements();
-
-#ifdef JSGC_GENERATIONAL
-    if (hasDynamicElements())
-        rt->gcNursery.notifyNewElements(this, newHeader);
-#endif
-
-    initElementsHeader(newHeader, byteLengthCopy);
-    InitViewList(this, viewListHead);
-}
-
-void
-ArrayBufferObject::neuter(JSContext *cx)
-{
-    JS_ASSERT(cx);
-    if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
-        ObjectElements *oldHeader = getElementsHeader();
-        changeContents(cx, ObjectElements::fromElements(fixedElements()));
-
-        FreeOp fop(cx->runtime(), false);
-        fop.free_(oldHeader);
-    }
-
-    uint32_t byteLen = 0;
-    updateElementsHeader(getElementsHeader(), byteLen);
-
-    getElementsHeader()->setIsNeuteredBuffer();
-}
-
-/* static */ bool
-ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
-    if (buffer->hasDynamicElements())
-        return true;
-
-    ObjectElements *newHeader = AllocateArrayBufferContents(cx, buffer->byteLength());
-    if (!newHeader)
-        return false;
-
-    void *newHeaderDataPointer = reinterpret_cast<void*>(newHeader->elements());
-    memcpy(newHeaderDataPointer, buffer->dataPointer(), buffer->byteLength());
-
-    buffer->changeContents(cx, newHeader);
-    return true;
-}
-
-#if defined(JS_ION) && defined(JS_CPU_X64)
-// To avoid dynamically checking bounds on each load/store, asm.js code relies
-// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
-// if we can guarantee that *any* out-of-bounds access generates a fault. This
-// isn't generally true since an out-of-bounds access could land on other
-// Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
-// making only the range [0, byteLength) accessible, and use a 32-bit unsigned
-// index into this space. (x86 and ARM require different tricks.)
-//
-// One complication is that we need to put an ObjectElements struct immediately
-// before the data array (as required by the general JSObject data structure).
-// Thus, we must stick a page before the elements to hold ObjectElements.
-//
-//   |<------------------------------ 4GB + 1 pages --------------------->|
-//           |<--- sizeof --->|<------------------- 4GB ----------------->|
-//
-//   | waste | ObjectElements | data array | inaccessible reserved memory |
-//                            ^            ^                              ^
-//                            |            \                             /
-//                      obj->elements       required to be page boundaries
-//
-JS_STATIC_ASSERT(sizeof(ObjectElements) < AsmJSPageSize);
-JS_STATIC_ASSERT(AsmJSAllocationGranularity == AsmJSPageSize);
-static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
-
-bool
-ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
-    if (buffer->isAsmJSArrayBuffer())
-        return true;
-
-    // Get the entire reserved region (with all pages inaccessible).
-    void *p;
-# ifdef XP_WIN
-    p = VirtualAlloc(nullptr, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);
-    if (!p)
-        return false;
-# else
-    p = mmap(nullptr, AsmJSMappedSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
-    if (p == MAP_FAILED)
-        return false;
-# endif
-
-    // Enable access to the valid region.
-    JS_ASSERT(buffer->byteLength() % AsmJSAllocationGranularity == 0);
-# ifdef XP_WIN
-    if (!VirtualAlloc(p, AsmJSPageSize + buffer->byteLength(), MEM_COMMIT, PAGE_READWRITE)) {
-        VirtualFree(p, 0, MEM_RELEASE);
-        return false;
-    }
-# else
-    if (mprotect(p, AsmJSPageSize + buffer->byteLength(), PROT_READ | PROT_WRITE)) {
-        munmap(p, AsmJSMappedSize);
-        return false;
-    }
-# endif
-
-    // Copy over the current contents of the typed array.
-    uint8_t *data = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
-    memcpy(data, buffer->dataPointer(), buffer->byteLength());
-
-    // Swap the new elements into the ArrayBufferObject.
-    ObjectElements *newHeader = reinterpret_cast<ObjectElements*>(data - sizeof(ObjectElements));
-    ObjectElements *oldHeader = buffer->hasDynamicElements() ? buffer->getElementsHeader()
-                                                             : nullptr;
-    buffer->changeContents(cx, newHeader);
-    js_free(oldHeader);
-
-    // Mark the ArrayBufferObject so (1) we don't do this again, (2) we know not
-    // to js_free the header in the normal way.
-    newHeader->setIsAsmJSArrayBuffer();
-    JS_ASSERT(data == buffer->dataPointer());
-    return true;
-}
-
-void
-ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
-{
-    ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
-    JS_ASSERT(buffer.isAsmJSArrayBuffer());
-
-    uint8_t *p = buffer.dataPointer() - AsmJSPageSize ;
-    JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
-# ifdef XP_WIN
-    VirtualFree(p, 0, MEM_RELEASE);
-# else
-    munmap(p, AsmJSMappedSize);
-# endif
-}
-#else  /* defined(JS_ION) && defined(JS_CPU_X64) */
-bool
-ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
-    if (buffer->isAsmJSArrayBuffer())
-        return true;
-
-    if (!ensureNonInline(cx, buffer))
-        return false;
-
-    JS_ASSERT(buffer->hasDynamicElements());
-    buffer->getElementsHeader()->setIsAsmJSArrayBuffer();
-    return true;
-}
-
-void
-ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
-{
-    fop->free_(obj->as<ArrayBufferObject>().getElementsHeader());
-}
-#endif
-
-bool
-ArrayBufferObject::neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
-{
-#ifdef JS_ION
-    AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
-    for (; act; act = act->prev()) {
-        if (act->module().maybeHeapBufferObject() == &buffer)
-            break;
-    }
-    if (!act)
-        return true;
-
-    js_ReportOverRecursed(cx);
-    return false;
-#else
-    return true;
-#endif
-}
-
-void
-ArrayBufferObject::addView(ArrayBufferViewObject *view)
-{
-    // This view should never have been associated with a buffer before
-    JS_ASSERT(view->bufferLink() == UNSET_BUFFER_LINK);
-
-    // Note that pre-barriers are not needed here because either the list was
-    // previously empty, in which case no pointer is being overwritten, or the
-    // list was nonempty and will be made weak during this call (and weak
-    // pointers cannot violate the snapshot-at-the-beginning invariant.)
-
-    ArrayBufferViewObject *viewsHead = GetViewList(this);
-    if (viewsHead == nullptr) {
-        // This ArrayBufferObject will have a single view at this point, so it
-        // is a strong pointer (it will be marked during tracing.)
-        JS_ASSERT(view->nextView() == nullptr);
-    } else {
-        view->prependToViews(viewsHead);
-    }
-
-    SetViewList(this, view);
-}
-
-ArrayBufferObject *
-ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, bool clear /* = true */)
-{
-    Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(cx));
-    if (!obj)
-        return nullptr;
-    JS_ASSERT_IF(obj->isTenured(), obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT16_BACKGROUND);
-    JS_ASSERT(obj->getClass() == &class_);
-
-    js::Shape *empty = EmptyShape::getInitialShape(cx, &class_,
-                                                   obj->getProto(), obj->getParent(), obj->getMetadata(),
-                                                   gc::FINALIZE_OBJECT16_BACKGROUND);
-    if (!empty)
-        return nullptr;
-    obj->setLastPropertyInfallible(empty);
-
-    // ArrayBufferObjects delegate added properties to another JSObject, so
-    // their internal layout can use the object's fixed slots for storage.
-    // Set up the object to look like an array with an elements header.
-    JS_ASSERT(!obj->hasDynamicSlots());
-    JS_ASSERT(!obj->hasDynamicElements());
-
-    // The beginning stores an ObjectElements header structure holding the
-    // length. The rest of it is a flat data store for the array buffer.
-    size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
-
-    if (nbytes > sizeof(Value) * usableSlots) {
-        ObjectElements *header = AllocateArrayBufferContents(cx, nbytes);
-        if (!header)
-            return nullptr;
-        obj->elements = header->elements();
-
-#ifdef JSGC_GENERATIONAL
-        JSRuntime *rt = obj->runtimeFromMainThread();
-        rt->gcNursery.notifyNewElements(obj, header);
-#endif
-    } else {
-        obj->setFixedElements();
-        if (clear)
-            memset(obj->dataPointer(), 0, nbytes);
-    }
-
-    obj->initElementsHeader(obj->getElementsHeader(), nbytes);
-
-    return obj;
-}
-
-JSObject *
-ArrayBufferObject::createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
-                               uint32_t begin, uint32_t end)
-{
-    JS_ASSERT(begin <= arrayBuffer->byteLength());
-    JS_ASSERT(end <= arrayBuffer->byteLength());
-    JS_ASSERT(begin <= end);
-    uint32_t length = end - begin;
-
-    if (!arrayBuffer->hasData())
-        return create(cx, 0);
-
-    JSObject *slice = create(cx, length, false);
-    if (!slice)
-        return nullptr;
-    memcpy(slice->as<ArrayBufferObject>().dataPointer(), arrayBuffer->dataPointer() + begin, length);
-    return slice;
-}
-
-bool
-ArrayBufferObject::createDataViewForThisImpl(JSContext *cx, CallArgs args)
-{
-    JS_ASSERT(IsArrayBuffer(args.thisv()));
-
-    /*
-     * This method is only called for |DataView(alienBuf, ...)| which calls
-     * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|,
-     * ergo there must be at least two arguments.
-     */
-    JS_ASSERT(args.length() >= 2);
-
-    Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
-
-    Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
-
-    /*
-     * Pop off the passed-along prototype and delegate to normal DataViewObject
-     * construction.
-     */
-    CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base());
-    return DataViewObject::construct(cx, buffer, frobbedArgs, proto);
-}
-
-bool
-ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
-}
-
-/* static */ bool
-ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
-                                 uint8_t **data)
-{
-    // If the ArrayBuffer's elements are dynamically allocated and nothing else
-    // prevents us from stealing them, transfer ownership directly.  Otherwise,
-    // the elements are small and allocated inside the ArrayBuffer object's GC
-    // header so we must make a copy.
-    ObjectElements *transferableHeader;
-    bool stolen;
-    if (buffer->hasDynamicElements() && !buffer->isAsmJSArrayBuffer()) {
-        stolen = true;
-        transferableHeader = buffer->getElementsHeader();
-    } else {
-        stolen = false;
-
-        uint32_t byteLen = buffer->byteLength();
-        transferableHeader = AllocateArrayBufferContents(cx, byteLen);
-        if (!transferableHeader)
-            return false;
-
-        initElementsHeader(transferableHeader, byteLen);
-        void *headerDataPointer = reinterpret_cast<void*>(transferableHeader->elements());
-        memcpy(headerDataPointer, buffer->dataPointer(), byteLen);
-    }
-
-    JS_ASSERT(!IsInsideNursery(cx->runtime(), transferableHeader));
-    *contents = transferableHeader;
-    *data = reinterpret_cast<uint8_t *>(transferableHeader + 1);
-
-    // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do
-    // it after copying out the data.
-    if (!ArrayBufferObject::neuterViews(cx, buffer))
-        return false;
-
-    // If the elements were taken from the neutered buffer, revert it back to
-    // using inline storage so it doesn't attempt to free the stolen elements
-    // when finalized.
-    if (stolen)
-        buffer->changeContents(cx, ObjectElements::fromElements(buffer->fixedElements()));
-
-    buffer->neuter(cx);
-    return true;
-}
-
-void
-ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
-{
-    /*
-     * If this object changes, it will get marked via the private data barrier,
-     * so it's safe to leave it Unbarriered.
-     */
-    JSObject *delegate = static_cast<JSObject*>(obj->getPrivate());
-    if (delegate) {
-        JS_SET_TRACING_LOCATION(trc, &obj->privateRef(obj->numFixedSlots()));
-        MarkObjectUnbarriered(trc, &delegate, "arraybuffer.delegate");
-        obj->setPrivateUnbarriered(delegate);
-    }
-
-    // ArrayBufferObjects need to maintain a list of possibly-weak pointers to
-    // their views. The straightforward way to update the weak pointers would
-    // be in the views' finalizers, but giving views finalizers means they
-    // cannot be swept in the background. This results in a very high
-    // performance cost.  Instead, ArrayBufferObjects with a single view hold a
-    // strong pointer to the view. This can entrain garbage when the single
-    // view becomes otherwise unreachable while the buffer is still live, but
-    // this is expected to be rare. ArrayBufferObjects with 0-1 views are
-    // expected to be by far the most common cases. ArrayBufferObjects with
-    // multiple views are collected into a linked list during collection, and
-    // then swept to prune out their dead views.
-
-    ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
-    ArrayBufferViewObject *viewsHead = GetViewList(&buffer);
-    if (!viewsHead)
-        return;
-
-    // During minor collections, mark weak pointers on the buffer strongly.
-    if (trc->runtime->isHeapMinorCollecting()) {
-        MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.viewlist");
-        ArrayBufferViewObject *prior = GetViewList(&buffer);
-        for (ArrayBufferViewObject *view = prior->nextView();
-             view;
-             prior = view, view = view->nextView())
-        {
-            MarkObjectUnbarriered(trc, &view, "arraybuffer.views");
-            prior->setNextView(view);
-        }
-        return;
-    }
-
-    ArrayBufferViewObject *firstView = viewsHead;
-    if (firstView->nextView() == nullptr) {
-        // Single view: mark it, but only if we're actually doing a GC pass
-        // right now. Otherwise, the tracing pass for barrier verification will
-        // fail if we add another view and the pointer becomes weak.
-        if (IS_GC_MARKING_TRACER(trc))
-            MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.singleview");
-    } else {
-        // Multiple views: do not mark, but append buffer to list.
-        if (IS_GC_MARKING_TRACER(trc)) {
-            // obj_trace may be called multiple times before sweep(), so avoid
-            // adding this buffer to the list multiple times.
-            if (firstView->bufferLink() == UNSET_BUFFER_LINK) {
-                JS_ASSERT(obj->compartment() == firstView->compartment());
-                ArrayBufferObject **bufList = &obj->compartment()->gcLiveArrayBuffers;
-                firstView->setBufferLink(*bufList);
-                *bufList = &obj->as<ArrayBufferObject>();
-            } else {
-#ifdef DEBUG
-                bool found = false;
-                for (ArrayBufferObject *p = obj->compartment()->gcLiveArrayBuffers;
-                     p;
-                     p = GetViewList(p)->bufferLink())
-                {
-                    if (p == obj)
-                    {
-                        JS_ASSERT(!found);
-                        found = true;
-                    }
-                }
-#endif
-            }
-        }
-    }
-}
-
-void
-ArrayBufferObject::sweep(JSCompartment *compartment)
-{
-    ArrayBufferObject *buffer = compartment->gcLiveArrayBuffers;
-    JS_ASSERT(buffer != UNSET_BUFFER_LINK);
-    compartment->gcLiveArrayBuffers = nullptr;
-
-    while (buffer) {
-        ArrayBufferViewObject *viewsHead = GetViewList(buffer);
-        JS_ASSERT(viewsHead);
-
-        ArrayBufferObject *nextBuffer = viewsHead->bufferLink();
-        JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
-        viewsHead->setBufferLink(UNSET_BUFFER_LINK);
-
-        // Rebuild the list of views of the ArrayBufferObject, discarding dead
-        // views.  If there is only one view, it will have already been marked.
-        ArrayBufferViewObject *prevLiveView = nullptr;
-        ArrayBufferViewObject *view = viewsHead;
-        while (view) {
-            JS_ASSERT(buffer->compartment() == view->compartment());
-            ArrayBufferViewObject *nextView = view->nextView();
-            if (!IsObjectAboutToBeFinalized(&view)) {
-                view->setNextView(prevLiveView);
-                prevLiveView = view;
-            }
-            view = nextView;
-        }
-        SetViewList(buffer, prevLiveView);
-
-        buffer = nextBuffer;
-    }
-}
-
-void
-ArrayBufferObject::resetArrayBufferList(JSCompartment *comp)
-{
-    ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
-    JS_ASSERT(buffer != UNSET_BUFFER_LINK);
-    comp->gcLiveArrayBuffers = nullptr;
-
-    while (buffer) {
-        ArrayBufferViewObject *view = GetViewList(buffer);
-        JS_ASSERT(view);
-
-        ArrayBufferObject *nextBuffer = view->bufferLink();
-        JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
-
-        view->setBufferLink(UNSET_BUFFER_LINK);
-        buffer = nextBuffer;
-    }
-}
-
-/* static */ bool
-ArrayBufferObject::saveArrayBufferList(JSCompartment *comp, ArrayBufferVector &vector)
-{
-    ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
-    while (buffer) {
-        JS_ASSERT(buffer != UNSET_BUFFER_LINK);
-        if (!vector.append(buffer))
-            return false;
-
-        ArrayBufferViewObject *view = GetViewList(buffer);
-        JS_ASSERT(view);
-        buffer = view->bufferLink();
-    }
-    return true;
-}
-
-/* static */ void
-ArrayBufferObject::restoreArrayBufferLists(ArrayBufferVector &vector)
-{
-    for (ArrayBufferObject **p = vector.begin(); p != vector.end(); p++) {
-        ArrayBufferObject *buffer = *p;
-        JSCompartment *comp = buffer->compartment();
-        ArrayBufferViewObject *firstView = GetViewList(buffer);
-        JS_ASSERT(firstView);
-        JS_ASSERT(firstView->compartment() == comp);
-        JS_ASSERT(firstView->bufferLink() == UNSET_BUFFER_LINK);
-        firstView->setBufferLink(comp->gcLiveArrayBuffers);
-        comp->gcLiveArrayBuffers = buffer;
-    }
-}
-
-bool
-ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                     MutableHandleObject objp, MutableHandleShape propp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-
-    bool delegateResult = JSObject::lookupGeneric(cx, delegate, id, objp, propp);
-
-    /* If false, there was an error, so propagate it.
-     * Otherwise, if propp is non-null, the property
-     * was found. Otherwise it was not
-     * found so look in the prototype chain.
-     */
-    if (!delegateResult)
-        return false;
-
-    if (propp) {
-        if (objp == delegate)
-            objp.set(obj);
-        return true;
-    }
-
-    RootedObject proto(cx, obj->getProto());
-    if (!proto) {
-        objp.set(nullptr);
-        propp.set(nullptr);
-        return true;
-    }
-
-    return JSObject::lookupGeneric(cx, proto, id, objp, propp);
-}
-
-bool
-ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                      MutableHandleObject objp, MutableHandleShape propp)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return obj_lookupGeneric(cx, obj, id, objp, propp);
-}
-
-bool
-ArrayBufferObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                     MutableHandleObject objp, MutableHandleShape propp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-
-    /*
-     * If false, there was an error, so propagate it.
-     * Otherwise, if propp is non-null, the property
-     * was found. Otherwise it was not
-     * found so look in the prototype chain.
-     */
-    if (!JSObject::lookupElement(cx, delegate, index, objp, propp))
-        return false;
-
-    if (propp) {
-        if (objp == delegate)
-            objp.set(obj);
-        return true;
-    }
-
-    RootedObject proto(cx, obj->getProto());
-    if (proto)
-        return JSObject::lookupElement(cx, proto, index, objp, propp);
-
-    objp.set(nullptr);
-    propp.set(nullptr);
-    return true;
-}
-
-bool
-ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                     MutableHandleObject objp, MutableHandleShape propp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_lookupGeneric(cx, obj, id, objp, propp);
-}
-
-bool
-ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::DefineGeneric(cx, delegate, id, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_defineProperty(JSContext *cx, HandleObject obj,
-                                      HandlePropertyName name, HandleValue v,
-                                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
-                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
-                                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                  HandleId id, MutableHandleValue vp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::GetProperty(cx, delegate, receiver, id, vp);
-}
-
-bool
-ArrayBufferObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                   HandlePropertyName name, MutableHandleValue vp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    Rooted<jsid> id(cx, NameToId(name));
-    return baseops::GetProperty(cx, delegate, receiver, id, vp);
-}
-
-bool
-ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
-                                  HandleObject receiver, uint32_t index, MutableHandleValue vp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::GetElement(cx, delegate, receiver, index, vp);
-}
-
-bool
-ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
-                                  HandleObject receiver, HandleSpecialId sid,
-                                  MutableHandleValue vp)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_getGeneric(cx, obj, receiver, id, vp);
-}
-
-bool
-ArrayBufferObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                  MutableHandleValue vp, bool strict)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-
-    return baseops::SetPropertyHelper<SequentialExecution>(cx, delegate, obj, id, 0, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_setProperty(JSContext *cx, HandleObject obj,
-                                   HandlePropertyName name, MutableHandleValue vp, bool strict)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return obj_setGeneric(cx, obj, id, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_setElement(JSContext *cx, HandleObject obj,
-                                  uint32_t index, MutableHandleValue vp, bool strict)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-
-    return baseops::SetElementHelper(cx, delegate, obj, index, 0, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_setSpecial(JSContext *cx, HandleObject obj,
-                                  HandleSpecialId sid, MutableHandleValue vp, bool strict)
-{
-    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
-    return obj_setGeneric(cx, obj, id, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
-                                            HandleId id, unsigned *attrsp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::GetAttributes(cx, delegate, id, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
-                                            HandleId id, unsigned *attrsp)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::SetAttributes(cx, delegate, id, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                      bool *succeeded)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::DeleteProperty(cx, delegate, name, succeeded);
-}
-
-bool
-ArrayBufferObject::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                     bool *succeeded)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::DeleteElement(cx, delegate, index, succeeded);
-}
-
-bool
-ArrayBufferObject::obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                     bool *succeeded)
-{
-    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
-    if (!delegate)
-        return false;
-    return baseops::DeleteSpecial(cx, delegate, sid, succeeded);
-}
-
-bool
-ArrayBufferObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
-                                 MutableHandleValue statep, MutableHandleId idp)
-{
-    statep.setNull();
-    return true;
-}
-
-/*
- * ArrayBufferViewObject
- */
-
-inline void
-ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
-{
-    setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(buffer));
-    PostBarrierTypedArrayObject(this);
-}
-
-inline void
-ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view)
-{
-    setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(view));
-    PostBarrierTypedArrayObject(this);
-}
-
-/*
  * TypedArrayObject
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
 inline bool
@@ -1345,67 +255,31 @@ js::ToDoubleForTypedArray(JSContext *cx,
     // to a float array and then read back as integer. To work around this, we
     // always canonicalize NaN values in more-deterministic builds.
     *d = CanonicalizeNaN(*d);
 #endif
 
     return true;
 }
 
-/*
- * This method is used to trace TypedArrayObjects and DataViewObjects. We need
- * a custom tracer because some of an ArrayBufferViewObject's reserved slots
- * are weak references, and some need to be updated specially during moving
- * GCs.
- */
-/* static */ void
-ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
-{
-    HeapSlot &bufSlot = obj->getReservedSlotRef(BUFFER_SLOT);
-    MarkSlot(trc, &bufSlot, "typedarray.buffer");
-
-    /* Update obj's data slot if the array buffer moved. Note that during
-     * initialization, bufSlot may still be JSVAL_VOID. */
-    if (bufSlot.isObject()) {
-        ArrayBufferObject &buf = bufSlot.toObject().as<ArrayBufferObject>();
-        int32_t offset = obj->getReservedSlot(BYTEOFFSET_SLOT).toInt32();
-        obj->initPrivate(buf.dataPointer() + offset);
-    }
-
-    /* Update NEXT_VIEW_SLOT, if the view moved. */
-    IsSlotMarked(&obj->getReservedSlotRef(NEXT_VIEW_SLOT));
-}
-
 template<typename NativeType> static inline const int TypeIDOfType();
 template<> inline const int TypeIDOfType<int8_t>() { return ScalarTypeDescr::TYPE_INT8; }
 template<> inline const int TypeIDOfType<uint8_t>() { return ScalarTypeDescr::TYPE_UINT8; }
 template<> inline const int TypeIDOfType<int16_t>() { return ScalarTypeDescr::TYPE_INT16; }
 template<> inline const int TypeIDOfType<uint16_t>() { return ScalarTypeDescr::TYPE_UINT16; }
 template<> inline const int TypeIDOfType<int32_t>() { return ScalarTypeDescr::TYPE_INT32; }
 template<> inline const int TypeIDOfType<uint32_t>() { return ScalarTypeDescr::TYPE_UINT32; }
 template<> inline const int TypeIDOfType<float>() { return ScalarTypeDescr::TYPE_FLOAT32; }
 template<> inline const int TypeIDOfType<double>() { return ScalarTypeDescr::TYPE_FLOAT64; }
 template<> inline const int TypeIDOfType<uint8_clamped>() { return ScalarTypeDescr::TYPE_UINT8_CLAMPED; }
 
 template<typename ElementType>
 static inline JSObject *
 NewArray(JSContext *cx, uint32_t nelements);
 
-static inline void
-InitArrayBufferViewDataPointer(JSObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
-{
-    /*
-     * N.B. The base of the array's data is stored in the object's
-     * private data rather than a slot to avoid alignment restrictions
-     * on private Values.
-     */
-    obj->initPrivate(buffer->dataPointer() + byteOffset);
-    PostBarrierTypedArrayObject(obj);
-}
-
 namespace {
 
 template<typename NativeType>
 class TypedArrayObjectTemplate : public TypedArrayObject
 {
   public:
     typedef NativeType ThisType;
     typedef TypedArrayObjectTemplate<NativeType> ThisTypedArrayObject;
@@ -2616,38 +1490,16 @@ ArrayBufferObject::createTypedArrayFromB
 template<typename T>
 bool
 ArrayBufferObject::createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsArrayBuffer, createTypedArrayFromBufferImpl<T> >(cx, args);
 }
 
-void
-ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead)
-{
-    setNextView(viewsHead);
-
-    // Move the multiview buffer list link into this view since we're
-    // prepending it to the list.
-    setBufferLink(viewsHead->bufferLink());
-    viewsHead->setBufferLink(UNSET_BUFFER_LINK);
-}
-
-void
-ArrayBufferViewObject::neuter(JSContext *cx)
-{
-    if (is<DataViewObject>())
-        as<DataViewObject>().neuter();
-    else if (is<TypedArrayObject>())
-        as<TypedArrayObject>().neuter(cx);
-    else
-        as<TypedObject>().neuter(cx);
-}
-
 // this default implementation is only valid for integer types
 // less than 32-bits in size.
 template<typename NativeType>
 void
 TypedArrayObjectTemplate<NativeType>::copyIndexToValue(JSObject *tarray, uint32_t index,
                                                        MutableHandleValue vp)
 {
     JS_STATIC_ASSERT(sizeof(NativeType) < 4);
@@ -2762,17 +1614,17 @@ DataViewObject::create(JSContext *cx, ui
     }
 
     DataViewObject &dvobj = obj->as<DataViewObject>();
     dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
     dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
     dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
     dvobj.setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
     dvobj.setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(UNSET_BUFFER_LINK));
-    InitArrayBufferViewDataPointer(obj, arrayBuffer, byteOffset);
+    InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset);
     JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
 
     // Verify that the private slot is at the expected place
     JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT);
 
     arrayBuffer->as<ArrayBufferObject>().addView(&dvobj);
 
     return &dvobj;
@@ -3404,94 +2256,16 @@ TypedArrayObject::copyTypedArrayElement(
     }
 }
 
 /***
  *** JS impl
  ***/
 
 /*
- * ArrayBufferObject (base)
- */
-
-const Class ArrayBufferObject::protoClass = {
-    "ArrayBufferPrototype",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
-};
-
-const Class ArrayBufferObject::class_ = {
-    "ArrayBuffer",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_IMPLEMENTS_BARRIERS |
-    Class::NON_NATIVE |
-    JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
-    JS_PropertyStub,         /* addProperty */
-    JS_DeletePropertyStub,   /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,        /* finalize    */
-    nullptr,        /* call        */
-    nullptr,        /* hasInstance */
-    nullptr,        /* construct   */
-    ArrayBufferObject::obj_trace,
-    JS_NULL_CLASS_SPEC,
-    JS_NULL_CLASS_EXT,
-    {
-        ArrayBufferObject::obj_lookupGeneric,
-        ArrayBufferObject::obj_lookupProperty,
-        ArrayBufferObject::obj_lookupElement,
-        ArrayBufferObject::obj_lookupSpecial,
-        ArrayBufferObject::obj_defineGeneric,
-        ArrayBufferObject::obj_defineProperty,
-        ArrayBufferObject::obj_defineElement,
-        ArrayBufferObject::obj_defineSpecial,
-        ArrayBufferObject::obj_getGeneric,
-        ArrayBufferObject::obj_getProperty,
-        ArrayBufferObject::obj_getElement,
-        ArrayBufferObject::obj_getSpecial,
-        ArrayBufferObject::obj_setGeneric,
-        ArrayBufferObject::obj_setProperty,
-        ArrayBufferObject::obj_setElement,
-        ArrayBufferObject::obj_setSpecial,
-        ArrayBufferObject::obj_getGenericAttributes,
-        ArrayBufferObject::obj_setGenericAttributes,
-        ArrayBufferObject::obj_deleteProperty,
-        ArrayBufferObject::obj_deleteElement,
-        ArrayBufferObject::obj_deleteSpecial,
-        nullptr, nullptr, /* watch/unwatch */
-        nullptr,          /* slice */
-        ArrayBufferObject::obj_enumerate,
-        nullptr,          /* thisObject      */
-    }
-};
-
-const JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
-    JS_FN("slice", ArrayBufferObject::fun_slice, 2, JSFUN_GENERIC_NATIVE),
-    JS_FS_END
-};
-
-const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
-    JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
-    JS_FS_END
-};
-
-/*
  * TypedArrayObject boilerplate
  */
 
 #ifndef RELEASE_BUILD
 # define IMPL_TYPED_ARRAY_STATICS(_typedArray)                                     \
 const JSFunctionSpec _typedArray##Object::jsfuncs[] = {                            \
     JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0, 0),                          \
     JS_FN("subarray", _typedArray##Object::fun_subarray, 2, JSFUN_GENERIC_NATIVE), \
@@ -3984,153 +2758,22 @@ bool
 js::IsTypedArrayBuffer(HandleValue v)
 {
     return v.isObject() && v.toObject().is<ArrayBufferObject>();
 }
 
 /* JS Friend API */
 
 JS_FRIEND_API(bool)
-JS_IsArrayBufferObject(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    return obj ? obj->is<ArrayBufferObject>() : false;
-}
-
-JS_FRIEND_API(bool)
 JS_IsTypedArrayObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? obj->is<TypedArrayObject>() : false;
 }
 
-JS_FRIEND_API(bool)
-JS_IsArrayBufferViewObject(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    return obj ? obj->is<ArrayBufferViewObject>() : false;
-}
-
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferByteLength(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
-}
-
-JS_FRIEND_API(uint8_t *)
-JS_GetArrayBufferData(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj)
-        return nullptr;
-    return obj->as<ArrayBufferObject>().dataPointer();
-}
-
-JS_FRIEND_API(uint8_t *)
-JS_GetStableArrayBufferData(JSContext *cx, JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj)
-        return nullptr;
-
-    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-    if (!ArrayBufferObject::ensureNonInline(cx, buffer))
-        return nullptr;
-
-    return buffer->dataPointer();
-}
-
-JS_FRIEND_API(bool)
-JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj)
-{
-    if (!obj->is<ArrayBufferObject>()) {
-        JS_ReportError(cx, "ArrayBuffer object required");
-        return false;
-    }
-
-    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-    if (!ArrayBufferObject::neuterViews(cx, buffer))
-        return false;
-    buffer->neuter(cx);
-    return true;
-}
-
-JS_FRIEND_API(JSObject *)
-JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
-{
-    JS_ASSERT(nbytes <= INT32_MAX);
-    return ArrayBufferObject::create(cx, nbytes);
-}
-
-JS_PUBLIC_API(JSObject *)
-JS_NewArrayBufferWithContents(JSContext *cx, void *contents)
-{
-    JS_ASSERT(contents);
-    JSObject *obj = ArrayBufferObject::create(cx, 0);
-    if (!obj)
-        return nullptr;
-    js::ObjectElements *elements = reinterpret_cast<js::ObjectElements *>(contents);
-    obj->setDynamicElements(elements);
-    JS_ASSERT(GetViewList(&obj->as<ArrayBufferObject>()) == nullptr);
-
-#ifdef JSGC_GENERATIONAL
-    cx->runtime()->gcNursery.notifyNewElements(obj, elements);
-#endif
-    return obj;
-}
-
-JS_PUBLIC_API(bool)
-JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes,
-                               void **contents, uint8_t **data)
-{
-    js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes);
-    if (!header)
-        return false;
-
-    ArrayBufferObject::updateElementsHeader(header, nbytes);
-
-    *contents = header;
-    *data = reinterpret_cast<uint8_t*>(header->elements());
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_ReallocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void **contents, uint8_t **data)
-{
-    js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes, *contents);
-    if (!header)
-        return false;
-
-    ArrayBufferObject::initElementsHeader(header, nbytes);
-
-    *contents = header;
-    *data = reinterpret_cast<uint8_t*>(header->elements());
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_StealArrayBufferContents(JSContext *cx, HandleObject objArg, void **contents, uint8_t **data)
-{
-    JSObject *obj = CheckedUnwrap(objArg);
-    if (!obj)
-        return false;
-
-    if (!obj->is<ArrayBufferObject>()) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-        return false;
-    }
-
-    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-    if (!ArrayBufferObject::stealContents(cx, buffer, contents, data))
-        return false;
-
-    return true;
-}
-
 JS_FRIEND_API(uint32_t)
 JS_GetTypedArrayLength(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return 0;
     return obj->as<TypedArrayObject>().length();
 }
@@ -4294,70 +2937,8 @@ JS_GetDataViewData(JSObject *obj)
 JS_FRIEND_API(uint32_t)
 JS_GetDataViewByteLength(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return 0;
     return obj->as<DataViewObject>().byteLength();
 }
-
-JS_FRIEND_API(void *)
-JS_GetArrayBufferViewData(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj)
-        return nullptr;
-    return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
-                                     : obj->as<TypedArrayObject>().viewData();
-}
-
-JS_FRIEND_API(JSObject *)
-JS_GetArrayBufferViewBuffer(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj)
-        return nullptr;
-    return obj->as<ArrayBufferViewObject>().bufferObject();
-}
-
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferViewByteLength(JSObject *obj)
-{
-    obj = CheckedUnwrap(obj);
-    if (!obj)
-        return 0;
-    return obj->is<DataViewObject>()
-           ? obj->as<DataViewObject>().byteLength()
-           : obj->as<TypedArrayObject>().byteLength();
-}
-
-JS_FRIEND_API(JSObject *)
-JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
-{
-    if (!(obj = CheckedUnwrap(obj)))
-        return nullptr;
-    if (!(obj->is<ArrayBufferViewObject>()))
-        return nullptr;
-
-    *length = obj->is<DataViewObject>()
-              ? obj->as<DataViewObject>().byteLength()
-              : obj->as<TypedArrayObject>().byteLength();
-
-    *data = static_cast<uint8_t*>(obj->is<DataViewObject>()
-                                  ? obj->as<DataViewObject>().dataPointer()
-                                  : obj->as<TypedArrayObject>().viewData());
-    return obj;
-}
-
-JS_FRIEND_API(JSObject *)
-JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
-{
-    if (!(obj = CheckedUnwrap(obj)))
-        return nullptr;
-    if (!obj->is<ArrayBufferObject>())
-        return nullptr;
-
-    *length = obj->as<ArrayBufferObject>().byteLength();
-    *data = obj->as<ArrayBufferObject>().dataPointer();
-
-    return obj;
-}
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -4,273 +4,25 @@
  * 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 vm_TypedArrayObject_h
 #define vm_TypedArrayObject_h
 
 #include "jsobj.h"
 
-#include "builtin/TypedObjectSimple.h"
+#include "builtin/TypedObject.h"
 #include "gc/Barrier.h"
 #include "js/Class.h"
+#include "vm/ArrayBufferObject.h"
 
 typedef struct JSProperty JSProperty;
 
 namespace js {
 
-typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector;
-
-// The inheritance hierarchy for the various classes relating to typed arrays
-// is as follows.
-//
-// - JSObject
-//   - ArrayBufferObject
-//   - ArrayBufferViewObject
-//     - DataViewObject
-//     - TypedArrayObject
-//       - TypedArrayObjectTemplate
-//         - Int8ArrayObject
-//         - Uint8ArrayObject
-//         - ...
-//
-// Note that |TypedArrayObjectTemplate| is just an implementation detail that
-// makes implementing its various subclasses easier.
-
-class ArrayBufferViewObject;
-
-/*
- * ArrayBufferObject
- *
- * This class holds the underlying raw buffer that the various
- * ArrayBufferViewObject subclasses (DataViewObject and the TypedArrays)
- * access. It can be created explicitly and passed to an ArrayBufferViewObject
- * subclass, or can be created implicitly by constructing a TypedArrayObject
- * with a size.
- */
-class ArrayBufferObject : public JSObject
-{
-    static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
-    static bool fun_slice_impl(JSContext *cx, CallArgs args);
-
-  public:
-    static const Class class_;
-
-    static const Class protoClass;
-    static const JSFunctionSpec jsfuncs[];
-    static const JSFunctionSpec jsstaticfuncs[];
-
-    static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);
-
-    static bool fun_slice(JSContext *cx, unsigned argc, Value *vp);
-
-    static bool fun_isView(JSContext *cx, unsigned argc, Value *vp);
-
-    static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
-
-    static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, bool clear = true);
-
-    static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
-                                 uint32_t begin, uint32_t end);
-
-    static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
-    static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
-
-    template<typename T>
-    static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);
-
-    template<typename T>
-    static bool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);
-
-    static void obj_trace(JSTracer *trc, JSObject *obj);
-
-    static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                  MutableHandleObject objp, MutableHandleShape propp);
-    static bool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                   MutableHandleObject objp, MutableHandleShape propp);
-    static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                  MutableHandleObject objp, MutableHandleShape propp);
-    static bool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                  MutableHandleObject objp, MutableHandleShape propp);
-
-    static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-    static bool obj_defineProperty(JSContext *cx, HandleObject obj,
-                                   HandlePropertyName name, HandleValue v,
-                                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-    static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
-                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-    static bool obj_defineSpecial(JSContext *cx, HandleObject obj,
-                                  HandleSpecialId sid, HandleValue v,
-                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-
-    static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
-                               HandleId id, MutableHandleValue vp);
-
-    static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                HandlePropertyName name, MutableHandleValue vp);
-
-    static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
-                               uint32_t index, MutableHandleValue vp);
-
-    static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
-                               HandleSpecialId sid, MutableHandleValue vp);
-
-    static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                               MutableHandleValue vp, bool strict);
-    static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                MutableHandleValue vp, bool strict);
-    static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
-                               MutableHandleValue vp, bool strict);
-    static bool obj_setSpecial(JSContext *cx, HandleObject obj,
-                               HandleSpecialId sid, MutableHandleValue vp, bool strict);
-
-    static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
-                                         HandleId id, unsigned *attrsp);
-    static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
-                                         HandleId id, unsigned *attrsp);
-
-    static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                   bool *succeeded);
-    static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                  bool *succeeded);
-    static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                  bool *succeeded);
-
-    static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
-                              MutableHandleValue statep, MutableHandleId idp);
-
-    static void sweep(JSCompartment *rt);
-
-    static void resetArrayBufferList(JSCompartment *rt);
-    static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
-    static void restoreArrayBufferLists(ArrayBufferVector &vector);
-
-    static bool stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
-                              uint8_t **data);
-
-    static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) {
-        header->initializedLength = bytes;
-
-        // NB: one or both of these fields is clobbered by GetViewList to store
-        // the 'views' link. Set them to 0 to effectively initialize 'views'
-        // to nullptr.
-        header->length = 0;
-        header->capacity = 0;
-    }
-
-    static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) {
-        header->flags = 0;
-        updateElementsHeader(header, bytes);
-    }
-
-    static uint32_t headerInitializedLength(const js::ObjectElements *header) {
-        return header->initializedLength;
-    }
-
-    void addView(ArrayBufferViewObject *view);
-
-    void changeContents(JSContext *cx, ObjectElements *newHeader);
-
-    /*
-     * Ensure data is not stored inline in the object. Used when handing back a
-     * GC-safe pointer.
-     */
-    static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);
-
-    uint32_t byteLength() const {
-        return getElementsHeader()->initializedLength;
-    }
-
-    /*
-     * Neuter all views of an ArrayBuffer.
-     */
-    static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
-
-    inline uint8_t * dataPointer() const {
-        return (uint8_t *) elements;
-    }
-
-    /*
-     * Discard the ArrayBuffer contents. For asm.js buffers, at least, should
-     * be called after neuterViews().
-     */
-    void neuter(JSContext *cx);
-
-    /*
-     * Check if the arrayBuffer contains any data. This will return false for
-     * ArrayBuffer.prototype and neutered ArrayBuffers.
-     */
-    bool hasData() const {
-        return getClass() == &class_;
-    }
-
-    bool isAsmJSArrayBuffer() const {
-        return getElementsHeader()->isAsmJSArrayBuffer();
-    }
-    bool isNeutered() const {
-        return getElementsHeader()->isNeuteredBuffer();
-    }
-    static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
-    static bool neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
-    static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
-};
-
-/*
- * ArrayBufferViewObject
- *
- * Common definitions shared by all ArrayBufferViews.
- */
-
-class ArrayBufferViewObject : public JSObject
-{
-  protected:
-    /* Offset of view in underlying ArrayBufferObject */
-    static const size_t BYTEOFFSET_SLOT  = JS_TYPEDOBJ_SLOT_BYTEOFFSET;
-
-    /* Byte length of view */
-    static const size_t BYTELENGTH_SLOT  = JS_TYPEDOBJ_SLOT_BYTELENGTH;
-
-    /* Underlying ArrayBufferObject */
-    static const size_t BUFFER_SLOT      = JS_TYPEDOBJ_SLOT_OWNER;
-
-    /* ArrayBufferObjects point to a linked list of views, chained through this slot */
-    static const size_t NEXT_VIEW_SLOT   = JS_TYPEDOBJ_SLOT_NEXT_VIEW;
-
-    /*
-     * When ArrayBufferObjects are traced during GC, they construct a linked
-     * list of ArrayBufferObjects with more than one view, chained through this
-     * slot of the first view of each ArrayBufferObject.
-     */
-    static const size_t NEXT_BUFFER_SLOT = JS_TYPEDOBJ_SLOT_NEXT_BUFFER;
-
-  public:
-    JSObject *bufferObject() const {
-        return &getFixedSlot(BUFFER_SLOT).toObject();
-    }
-
-    ArrayBufferObject *bufferLink() {
-        return static_cast<ArrayBufferObject*>(getFixedSlot(NEXT_BUFFER_SLOT).toPrivate());
-    }
-
-    inline void setBufferLink(ArrayBufferObject *buffer);
-
-    ArrayBufferViewObject *nextView() const {
-        return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
-    }
-
-    inline void setNextView(ArrayBufferViewObject *view);
-
-    void prependToViews(ArrayBufferViewObject *viewsHead);
-
-    void neuter(JSContext *cx);
-
-    static void trace(JSTracer *trc, JSObject *obj);
-};
-
 /*
  * TypedArrayObject
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */