Backed out changeset e35851f07b67 (bug 987508) for non-unified bustage.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 07 Apr 2014 15:49:48 -0400
changeset 195838 8b87a6adad143376550d552cef67d733ebdf6c4c
parent 195837 e43020f1f49118a99e8f381ead8cb791f421f88d
child 195839 7a1c696cade6bd7b80372dda80c86e6df7b3fc74
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs987508
milestone31.0a1
backs oute35851f07b6703bee6830b4ebcd2990f41629238
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
Backed out changeset e35851f07b67 (bug 987508) for non-unified bustage.
content/media/webaudio/AudioBuffer.cpp
js/src/gc/Nursery.cpp
js/src/jsapi-tests/testTypedArrays.cpp
js/src/jsfriendapi.h
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/ObjectImpl-inl.h
js/src/vm/ObjectImpl.h
js/src/vm/StructuredClone.cpp
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -192,17 +192,17 @@ AudioBuffer::GetChannelData(JSContext* a
 static already_AddRefed<ThreadSharedFloatArrayBufferList>
 StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
                                                      const nsTArray<JSObject*>& aJSArrays)
 {
   nsRefPtr<ThreadSharedFloatArrayBufferList> result =
     new ThreadSharedFloatArrayBufferList(aJSArrays.Length());
   for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
     JS::Rooted<JSObject*> arrayBuffer(aJSContext,
-                                      JS_GetArrayBufferViewBuffer(aJSContext, aJSArrays[i]));
+                                      JS_GetArrayBufferViewBuffer(aJSArrays[i]));
     uint8_t* stolenData = arrayBuffer
                           ? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer)
                           : nullptr;
     if (stolenData) {
       result->SetData(i, stolenData, reinterpret_cast<float*>(stolenData));
     } else {
       return nullptr;
     }
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -360,25 +360,16 @@ GetObjectAllocKindForCopy(JSRuntime *rt,
 
         size_t nelements = obj->getDenseCapacity();
         return GetBackgroundAllocKind(GetGCArrayKind(nelements));
     }
 
     if (obj->is<JSFunction>())
         return obj->as<JSFunction>().getAllocKind();
 
-    /*
-     * Typed arrays in the nursery may have a lazily allocated buffer, make
-     * sure there is room for the array's fixed data when moving the array.
-     */
-    if (obj->is<TypedArrayObject>() && !obj->as<TypedArrayObject>().buffer()) {
-        size_t nbytes = obj->as<TypedArrayObject>().byteLength();
-        return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes));
-    }
-
     AllocKind kind = GetGCObjectFixedSlotsKind(obj->numFixedSlots());
     JS_ASSERT(!IsBackgroundFinalized(kind));
     JS_ASSERT(CanBeFinalizedInBackground(kind, obj->getClass()));
     return GetBackgroundAllocKind(kind);
 }
 
 void *
 js::Nursery::allocateFromTenured(Zone *zone, AllocKind thingKind)
@@ -565,19 +556,16 @@ js::Nursery::moveObjectToTenured(JSObjec
      */
     if (src->is<ArrayObject>())
         srcSize = sizeof(ObjectImpl);
 
     js_memcpy(dst, src, srcSize);
     tenuredSize += moveSlotsToTenured(dst, src, dstKind);
     tenuredSize += moveElementsToTenured(dst, src, dstKind);
 
-    if (src->is<TypedArrayObject>())
-        dst->setPrivate(dst->fixedData(TypedArrayObject::FIXED_DATA_START));
-
     /* The shape's list head may point into the old object. */
     if (&src->shape_ == dst->shape_->listp)
         dst->shape_->listp = &dst->shape_;
 
     return tenuredSize;
 }
 
 size_t
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -104,17 +104,17 @@ TestArrayFromBuffer(JSContext *cx)
         RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1));
         CHECK(!notArray);
     }
 
     RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1));
     CHECK_EQUAL(JS_GetTypedArrayLength(array), elts);
     CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes);
-    CHECK_EQUAL(JS_GetArrayBufferViewBuffer(cx, array), (JSObject*) buffer);
+    CHECK_EQUAL(JS_GetArrayBufferViewBuffer(array), (JSObject*) buffer);
 
     Element *data;
     CHECK(data = GetData(array));
     CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer));
     CHECK_EQUAL((void*) data, (void*) bufdata);
 
     CHECK_EQUAL(*bufdata, 1);
     CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1427,17 +1427,17 @@ extern JS_FRIEND_API(void *)
 JS_GetArrayBufferViewData(JSObject *obj);
 
 /*
  * Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
  * neutered, this will still return the neutered buffer. |obj| must be an
  * object that would return true for JS_IsArrayBufferViewObject().
  */
 extern JS_FRIEND_API(JSObject *)
-JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj);
+JS_GetArrayBufferViewBuffer(JSObject *obj);
 
 /*
  * Set an ArrayBuffer's length to 0 and neuter all of its views.
  */
 extern JS_FRIEND_API(bool)
 JS_NeuterArrayBuffer(JSContext *cx, JS::HandleObject obj);
 
 /*
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1248,22 +1248,27 @@ NewObject(ExclusiveContext *cx, types::T
     JS_ASSERT_IF(parent, &parent->global() == cx->global());
 
     RootedTypeObject type(cx, type_);
 
     JSObject *metadata = nullptr;
     if (!NewObjectMetadata(cx, &metadata))
         return nullptr;
 
-    // For objects which can have fixed data following the object, only use
-    // enough fixed slots to cover the number of reserved slots in the object,
-    // regardless of the allocation kind specified.
-    size_t nfixed = ClassCanHaveFixedData(clasp)
-                    ? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
-                    : GetGCKindSlots(kind, clasp);
+    // Normally, the number of fixed slots given an object is the maximum
+    // permitted for its size class. For array buffers we only use enough to
+    // cover the class reservd slots, so that the remaining space in the
+    // object's allocation is available for the buffer's data.
+    size_t nfixed;
+    if (clasp == &ArrayBufferObject::class_) {
+        JS_STATIC_ASSERT(ArrayBufferObject::RESERVED_SLOTS == 4);
+        nfixed = ArrayBufferObject::RESERVED_SLOTS;
+    } else {
+        nfixed = GetGCKindSlots(kind, clasp);
+    }
 
     RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, type->proto(),
                                                       parent, metadata, nfixed));
     if (!shape)
         return nullptr;
 
     gc::InitialHeap heap = GetInitialHeap(newKind, clasp);
     JSObject *obj = JSObject::create(cx, kind, heap, shape, type);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -470,18 +470,17 @@ JSObject::setProto(JSContext *cx, JS::Ha
 
         if (!JSObject::getProto(cx, obj2, &obj2))
             return false;
     }
 
     return SetClassAndProto(cx, obj, obj->getClass(), proto, succeeded);
 }
 
-inline bool
-JSObject::isVarObj()
+inline bool JSObject::isVarObj()
 {
     if (is<js::DebugScopeObject>())
         return as<js::DebugScopeObject>().scope().isVarObj();
     return lastProperty()->hasObjectFlag(js::BaseShape::VAROBJ);
 }
 
 /* static */ inline JSObject *
 JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
@@ -491,17 +490,17 @@ JSObject::create(js::ExclusiveContext *c
     /*
      * Callers must use dynamicSlotsCount to size the initial slot array of the
      * object. We can't check the allocated capacity of the dynamic slots, but
      * make sure their presence is consistent with the shape.
      */
     JS_ASSERT(shape && type);
     JS_ASSERT(type->clasp() == shape->getObjectClass());
     JS_ASSERT(type->clasp() != &js::ArrayObject::class_);
-    JS_ASSERT_IF(!ClassCanHaveFixedData(type->clasp()),
+    JS_ASSERT_IF(type->clasp() != &js::ArrayBufferObject::class_,
                  js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
     JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
     JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
     JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
                                                 type->clasp()));
 
     const js::Class *clasp = type->clasp();
     size_t nDynamicSlots = 0;
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -626,17 +626,17 @@ ArrayBufferObject::create(JSContext *cx,
     }
     JS_ASSERT(obj->getClass() == &class_);
 
     JS_ASSERT(!gc::IsInsideNursery(cx->runtime(), obj));
 
     if (data) {
         obj->initialize(nbytes, data, OwnsData);
     } else {
-        void *data = obj->fixedData(reservedSlots);
+        void *data = &obj->fixedSlots()[reservedSlots];
         memset(data, 0, nbytes);
         obj->initialize(nbytes, data, DoesntOwnData);
     }
 
     return obj;
 }
 
 JSObject *
@@ -924,27 +924,16 @@ ArrayBufferViewObject::neuter(void *newD
     if (is<DataViewObject>())
         as<DataViewObject>().neuter(newData);
     else if (is<TypedArrayObject>())
         as<TypedArrayObject>().neuter(newData);
     else
         as<TypedObject>().neuter(newData);
 }
 
-/* static */ ArrayBufferObject *
-ArrayBufferViewObject::bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> thisObject)
-{
-    if (thisObject->is<TypedArrayObject>()) {
-        Rooted<TypedArrayObject *> typedArray(cx, &thisObject->as<TypedArrayObject>());
-        if (!TypedArrayObject::ensureHasBuffer(cx, typedArray))
-            return nullptr;
-    }
-    return &thisObject->getFixedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObject>();
-}
-
 /* JS Friend API */
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferViewObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? obj->is<ArrayBufferViewObject>() : false;
 }
@@ -1053,23 +1042,22 @@ 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(JSContext *cx, JSObject *obj)
+JS_GetArrayBufferViewBuffer(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
-    Rooted<ArrayBufferViewObject *> viewObject(cx, &obj->as<ArrayBufferViewObject>());
-    return ArrayBufferViewObject::bufferObject(cx, viewObject);
+    return obj->as<ArrayBufferViewObject>().bufferObject();
 }
 
 JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferViewByteLength(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return 0;
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -235,17 +235,19 @@ class ArrayBufferViewObject : public JSO
 
     /* 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;
 
   public:
-    static ArrayBufferObject *bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> obj);
+    JSObject *bufferObject() const {
+        return &getFixedSlot(BUFFER_SLOT).toObject();
+    }
 
     ArrayBufferViewObject *nextView() const {
         return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
     }
 
     inline void setNextView(ArrayBufferViewObject *view);
 
     void neuter(void *newData);
--- a/js/src/vm/ObjectImpl-inl.h
+++ b/js/src/vm/ObjectImpl-inl.h
@@ -8,48 +8,25 @@
 #define vm_ObjectImpl_inl_h
 
 #include "vm/ObjectImpl.h"
 
 #include "jscntxt.h"
 #include "jsproxy.h"
 
 #include "vm/ProxyObject.h"
-#include "vm/TypedArrayObject.h"
-
-namespace js {
 
 /* static */ inline bool
-ObjectImpl::isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *extensible)
+js::ObjectImpl::isExtensible(ExclusiveContext *cx, js::Handle<ObjectImpl*> obj, bool *extensible)
 {
     if (obj->asObjectPtr()->is<ProxyObject>()) {
         if (!cx->shouldBeJSContext())
             return false;
         HandleObject h =
             HandleObject::fromMarkedLocation(reinterpret_cast<JSObject* const*>(obj.address()));
         return Proxy::isExtensible(cx->asJSContext(), h, extensible);
     }
 
     *extensible = obj->nonProxyIsExtensible();
     return true;
 }
 
-inline bool
-ClassCanHaveFixedData(const Class *clasp)
-{
-    // Normally, the number of fixed slots given an object is the maximum
-    // permitted for its size class. For array buffers and typed arrays we only
-    // use enough to cover the class reserved slots, so that the remaining
-    // space in the object's allocation is available for the buffer's data.
-    return clasp == &ArrayBufferObject::class_ || IsTypedArrayClass(clasp);
-}
-
-inline void *
-ObjectImpl::fixedData(size_t nslots) const
-{
-    JS_ASSERT(ClassCanHaveFixedData(getClass()));
-    JS_ASSERT(nslots == numFixedSlots() + (hasPrivate() ? 1 : 0));
-    return &fixedSlots()[nslots];
-}
-
-} // namespace js
-
 #endif /* vm_ObjectImpl_inl_h */
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -89,22 +89,23 @@ class ArrayObject;
  */
 template <ExecutionMode mode>
 extern bool
 ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
                Handle<ArrayObject*> obj, HandleId id,
                unsigned attrs, HandleValue value, bool setterIsStrict);
 
 /*
- * Elements header used for all objects. The elements component of such objects
- * offers an efficient representation for all or some of the indexed properties
- * of the object, using a flat array of Values rather than a shape hierarchy
- * stored in the object's slots. This structure is immediately followed by an
- * array of elements, with the elements member in an object pointing to the
- * beginning of that array (the end of this structure).
+ * Elements header used for all objects other than non-native objects (except
+ * for ArrayBufferObjects!!!) and typed arrays. The elements component of such
+ * objects offers an efficient representation for all or some of the indexed
+ * properties of the object, using a flat array of Values rather than a shape
+ * hierarchy stored in the object's slots. This structure is immediately
+ * followed by an array of elements, with the elements member in an object
+ * pointing to the beginning of that array (the end of this structure).
  * See below for usage of this structure.
  *
  * The sets of properties represented by an object's elements and slots
  * are disjoint. The elements contain only indexed properties, while the slots
  * can contain both named and indexed properties; any indexes in the slots are
  * distinct from those in the elements. If isIndexed() is false for an object,
  * all indexed properties (if any) are stored in the dense elements.
  *
@@ -143,24 +144,24 @@ ArraySetLength(typename ExecutionModeTra
  *
  * The initialized length of an object specifies the number of elements that
  * have been initialized. All elements above the initialized length are
  * holes in the object, and the memory for all elements between the initialized
  * length and capacity is left uninitialized. The initialized length is some
  * value less than or equal to both the object's length and the object's
  * capacity.
  *
- * There is flexibility in exactly the value the initialized length must hold,
- * e.g. if an array has length 5, capacity 10, completely empty, it is valid
- * for the initialized length to be any value between zero and 5, as long as
- * the in memory values below the initialized length have been initialized with
- * a hole value. However, in such cases we want to keep the initialized length
- * as small as possible: if the object is known to have no hole values below
- * its initialized length, then it is "packed" and can be accessed much faster
- * by JIT code.
+ * With inference enabled, there is flexibility in exactly the value the
+ * initialized length must hold, e.g. if an array has length 5, capacity 10,
+ * completely empty, it is valid for the initialized length to be any value
+ * between zero and 5, as long as the in memory values below the initialized
+ * length have been initialized with a hole value. However, in such cases we
+ * want to keep the initialized length as small as possible: if the object is
+ * known to have no hole values below its initialized length, then it is
+ * "packed" and can be accessed much faster by JIT code.
  *
  * Elements do not track property creation order, so enumerating the elements
  * of an object does not necessarily visit indexes in the order they were
  * created.
  */
 class ObjectElements
 {
   public:
@@ -282,17 +283,17 @@ IsObjectValueInCompartment(js::Value v, 
  * The |type_| member stores the type of the object, which contains its
  * prototype object and the possible types of its properties.
  *
  * The rest of the object stores its named properties and indexed elements.
  * These are stored separately from one another. Objects are followed by a
  * variable-sized array of values for inline storage, which may be used by
  * either properties of native objects (fixed slots), by elements (fixed
  * elements), or by other data for certain kinds of objects, such as
- * ArrayBufferObjects and TypedArrayObjects.
+ * ArrayBufferObjects.
  *
  * Two native objects with the same shape are guaranteed to have the same
  * number of fixed slots.
  *
  * Named property storage can be split between fixed slots and a dynamically
  * allocated array (the slots member). For an object with N fixed slots, shapes
  * with slots [0..N-1] are stored in the fixed slots, and the remainder are
  * stored in the dynamic array. If all properties fit in the fixed slots, the
@@ -821,23 +822,16 @@ class ObjectImpl : public gc::BarrieredC
     inline bool hasFixedElements() const {
         return elements == fixedElements();
     }
 
     inline bool hasEmptyElements() const {
         return elements == emptyObjectElements;
     }
 
-    /*
-     * Get a pointer to the unused data in the object's allocation immediately
-     * following this object, for use with objects which allocate a larger size
-     * class than they need and store non-elements data inline.
-     */
-    inline void *fixedData(size_t nslots) const;
-
     /* GC support. */
     static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
 
     inline void privateWriteBarrierPre(void **oldval);
 
     void privateWriteBarrierPost(void **pprivate) {
 #ifdef JSGC_GENERATIONAL
         shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell(reinterpret_cast<js::gc::Cell **>(pprivate));
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -808,20 +808,16 @@ JSStructuredCloneWriter::checkStack()
  * Int16Array views of the same ArrayBuffer, should the data bytes be
  * byte-swapped when writing or not? The Int8Array requires them to not be
  * swapped; the Int16Array requires that they are.
  */
 bool
 JSStructuredCloneWriter::writeTypedArray(HandleObject obj)
 {
     Rooted<TypedArrayObject*> tarr(context(), &obj->as<TypedArrayObject>());
-
-    if (!TypedArrayObject::ensureHasBuffer(context(), tarr))
-        return false;
-
     if (!out.writePair(SCTAG_TYPED_ARRAY_OBJECT, tarr->length()))
         return false;
     uint64_t type = tarr->type();
     if (!out.write(type))
         return false;
 
     // Write out the ArrayBuffer tag and contents
     RootedValue val(context(), TypedArrayObject::bufferValue(tarr));
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -101,35 +101,16 @@ TypedArrayObject::neuter(void *newData)
 }
 
 ArrayBufferObject *
 TypedArrayObject::sharedBuffer() const
 {
     return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<SharedArrayBufferObject>();
 }
 
-/* static */ bool
-TypedArrayObject::ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarray)
-{
-    if (tarray->buffer())
-        return true;
-
-    Rooted<ArrayBufferObject *> buffer(cx, ArrayBufferObject::create(cx, tarray->byteLength()));
-    if (!buffer)
-        return false;
-
-    buffer->addView(tarray);
-
-    memcpy(buffer->dataPointer(), tarray->viewData(), tarray->byteLength());
-    InitArrayBufferViewDataPointer(tarray, buffer, 0);
-
-    tarray->setSlot(BUFFER_SLOT, ObjectValue(*buffer));
-    return true;
-}
-
 /* static */ int
 TypedArrayObject::lengthOffset()
 {
     return JSObject::getFixedSlotOffset(LENGTH_SLOT);
 }
 
 /* static */ int
 TypedArrayObject::dataOffset()
@@ -201,23 +182,23 @@ class TypedArrayObjectTemplate : public 
 
     static const size_t BYTES_PER_ELEMENT = sizeof(ThisType);
 
     static inline const Class *protoClass()
     {
         return &TypedArrayObject::protoClasses[ArrayTypeID()];
     }
 
-    static inline const Class *instanceClass()
+    static inline const Class *fastClass()
     {
         return &TypedArrayObject::classes[ArrayTypeID()];
     }
 
     static bool is(HandleValue v) {
-        return v.isObject() && v.toObject().hasClass(instanceClass());
+        return v.isObject() && v.toObject().hasClass(fastClass());
     }
 
     static void
     setIndexValue(TypedArrayObject &tarray, uint32_t index, double d)
     {
         // If the array is an integer array, we only handle up to
         // 32-bit ints from this point on.  if we want to handle
         // 64-bit ints, we'll need some changes.
@@ -236,128 +217,123 @@ class TypedArrayObjectTemplate : public 
         } else {
             JS_ASSERT(sizeof(NativeType) <= 4);
             int32_t n = ToInt32(d);
             setIndex(tarray, index, NativeType(n));
         }
     }
 
     static TypedArrayObject *
-    makeProtoInstance(JSContext *cx, HandleObject proto, AllocKind allocKind)
+    makeProtoInstance(JSContext *cx, HandleObject proto)
     {
         JS_ASSERT(proto);
 
-        RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind));
+        RootedObject obj(cx, NewBuiltinClassInstance(cx, fastClass()));
         if (!obj)
             return nullptr;
 
         types::TypeObject *type = cx->getNewType(obj->getClass(), proto.get());
         if (!type)
             return nullptr;
         obj->setType(type);
 
         return &obj->as<TypedArrayObject>();
     }
 
     static TypedArrayObject *
-    makeTypedInstance(JSContext *cx, uint32_t len, AllocKind allocKind)
+    makeTypedInstance(JSContext *cx, uint32_t len)
     {
         if (len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_TYPE_BYTE_LENGTH) {
-            return &NewBuiltinClassInstance(cx, instanceClass(), allocKind,
+            return &NewBuiltinClassInstance(cx, fastClass(),
                                             SingletonObject)->as<TypedArrayObject>();
         }
 
         jsbytecode *pc;
         RootedScript script(cx, cx->currentScript(&pc));
         NewObjectKind newKind = script
-                                ? UseNewTypeForInitializer(script, pc, instanceClass())
+                                ? UseNewTypeForInitializer(script, pc, fastClass())
                                 : GenericObject;
-        RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind, newKind));
+        RootedObject obj(cx, NewBuiltinClassInstance(cx, fastClass(), newKind));
         if (!obj)
             return nullptr;
 
         if (script) {
             if (!types::SetInitializerObjectType(cx, script, pc, obj, newKind))
                 return nullptr;
         }
 
         return &obj->as<TypedArrayObject>();
     }
 
     static JSObject *
-    makeInstance(JSContext *cx, Handle<ArrayBufferObject *> buffer, uint32_t byteOffset, uint32_t len,
+    makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len,
                  HandleObject proto)
     {
-        JS_ASSERT_IF(!buffer, byteOffset == 0);
-
-        gc::AllocKind allocKind = buffer
-                                  ? GetGCObjectKind(instanceClass())
-                                  : AllocKindForLazyBuffer(len * sizeof(NativeType));
-
         Rooted<TypedArrayObject*> obj(cx);
         if (proto)
-            obj = makeProtoInstance(cx, proto, allocKind);
+            obj = makeProtoInstance(cx, proto);
         else
-            obj = makeTypedInstance(cx, len, allocKind);
+            obj = makeTypedInstance(cx, len);
         if (!obj)
             return nullptr;
+        JS_ASSERT_IF(obj->isTenured(),
+                     obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND);
 
         obj->setSlot(TYPE_SLOT, Int32Value(ArrayTypeID()));
-        obj->setSlot(BUFFER_SLOT, ObjectOrNullValue(buffer));
-
-        if (buffer) {
-            InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
-        } else {
-            void *data = obj->fixedData(FIXED_DATA_START);
-            obj->initPrivate(data);
-            memset(data, 0, len * sizeof(NativeType));
-        }
-
+        obj->setSlot(BUFFER_SLOT, ObjectValue(*bufobj));
+
+        Rooted<ArrayBufferObject *> buffer(cx, &AsArrayBuffer(bufobj));
+
+        InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
         obj->setSlot(LENGTH_SLOT, Int32Value(len));
         obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
         obj->setSlot(BYTELENGTH_SLOT, Int32Value(len * sizeof(NativeType)));
         obj->setSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
 
+        js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(),
+                                                       obj->getProto(), obj->getParent(), obj->getMetadata(),
+                                                       gc::FINALIZE_OBJECT8_BACKGROUND);
+        if (!empty)
+            return nullptr;
+        obj->setLastPropertyInfallible(empty);
+
 #ifdef DEBUG
-        if (buffer) {
-            uint32_t arrayByteLength = obj->byteLength();
-            uint32_t arrayByteOffset = obj->byteOffset();
-            uint32_t bufferByteLength = buffer->byteLength();
-            JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
-            JS_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
-            JS_ASSERT(arrayByteOffset <= bufferByteLength);
-        }
+        uint32_t bufferByteLength = buffer->byteLength();
+        uint32_t arrayByteLength = obj->byteLength();
+        uint32_t arrayByteOffset = obj->byteOffset();
+        JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
+        JS_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
+        JS_ASSERT(arrayByteOffset <= bufferByteLength);
 
         // Verify that the private slot is at the expected place
         JS_ASSERT(obj->numFixedSlots() == DATA_SLOT);
 #endif
 
-        if (buffer)
-            buffer->addView(obj);
+        buffer->addView(obj);
 
         return obj;
     }
 
     static JSObject *
-    makeInstance(JSContext *cx, Handle<ArrayBufferObject *> bufobj, uint32_t byteOffset, uint32_t len)
+    makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len)
     {
         RootedObject nullproto(cx, nullptr);
         return makeInstance(cx, bufobj, byteOffset, len, nullproto);
     }
 
     /*
      * new [Type]Array(length)
      * new [Type]Array(otherTypedArray)
      * new [Type]Array(JSArray)
      * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
      */
     static bool
     class_constructor(JSContext *cx, unsigned argc, Value *vp)
     {
-        /* N.B. this is a constructor for protoClass, not instanceClass! */
+        /* N.B. this is a constructor for protoClass, not fastClass! */
         CallArgs args = CallArgsFromVp(argc, vp);
         JSObject *obj = create(cx, args);
         if (!obj)
             return false;
         args.rval().setObject(*obj);
         return true;
     }
 
@@ -415,17 +391,17 @@ class TypedArrayObjectTemplate : public 
             }
         }
 
         Rooted<JSObject*> proto(cx, nullptr);
         return fromBuffer(cx, dataObj, byteOffset, length, proto);
     }
 
     static bool IsThisClass(HandleValue v) {
-        return v.isObject() && v.toObject().hasClass(instanceClass());
+        return v.isObject() && v.toObject().hasClass(fastClass());
     }
 
     template<Value ValueGetter(TypedArrayObject *tarr)>
     static bool
     GetterImpl(JSContext *cx, CallArgs args)
     {
         JS_ASSERT(IsThisClass(args.thisv()));
         args.rval().set(ValueGetter(&args.thisv().toObject().as<TypedArrayObject>()));
@@ -439,68 +415,48 @@ class TypedArrayObjectTemplate : public 
     static bool
     Getter(JSContext *cx, unsigned argc, Value *vp)
     {
         CallArgs args = CallArgsFromVp(argc, vp);
         return CallNonGenericMethod<ThisTypedArrayObject::IsThisClass,
                                     ThisTypedArrayObject::GetterImpl<ValueGetter> >(cx, args);
     }
 
+    // Define an accessor for a read-only property that invokes a native getter
+    template<Value ValueGetter(TypedArrayObject *tarr)>
     static bool
-    BufferGetterImpl(JSContext *cx, CallArgs args)
-    {
-        JS_ASSERT(IsThisClass(args.thisv()));
-        Rooted<TypedArrayObject *> tarray(cx, &args.thisv().toObject().as<TypedArrayObject>());
-        if (!ensureHasBuffer(cx, tarray))
-            return false;
-        args.rval().set(bufferValue(tarray));
-        return true;
-    }
-
-    // BufferGetter is a function that lazily constructs the array buffer for a
-    // typed array before fetching it.
-    static bool
-    BufferGetter(JSContext *cx, unsigned argc, Value *vp)
-    {
-        CallArgs args = CallArgsFromVp(argc, vp);
-        return CallNonGenericMethod<ThisTypedArrayObject::IsThisClass,
-                                    ThisTypedArrayObject::BufferGetterImpl>(cx, args);
-    }
-
-    // Define an accessor for a read-only property that invokes a native getter
-    static bool
-    DefineGetter(JSContext *cx, HandleObject proto, PropertyName *name, Native native)
+    DefineGetter(JSContext *cx, PropertyName *name, HandleObject proto)
     {
         RootedId id(cx, NameToId(name));
         unsigned flags = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
 
         Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
-        JSObject *getter = NewFunction(cx, NullPtr(), native, 0,
+        JSObject *getter = NewFunction(cx, NullPtr(), Getter<ValueGetter>, 0,
                                        JSFunction::NATIVE_FUN, global, NullPtr());
         if (!getter)
             return false;
 
         return DefineNativeProperty(cx, proto, id, UndefinedHandleValue,
                                     JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr,
                                     flags, 0, 0);
     }
 
     static
     bool defineGetters(JSContext *cx, HandleObject proto)
     {
-        if (!DefineGetter(cx, proto, cx->names().length, Getter<lengthValue>))
+        if (!DefineGetter<lengthValue>(cx, cx->names().length, proto))
             return false;
 
-        if (!DefineGetter(cx, proto, cx->names().buffer, BufferGetter))
+        if (!DefineGetter<bufferValue>(cx, cx->names().buffer, proto))
             return false;
 
-        if (!DefineGetter(cx, proto, cx->names().byteLength, Getter<byteLengthValue>))
+        if (!DefineGetter<byteLengthValue>(cx, cx->names().byteLength, proto))
             return false;
 
-        if (!DefineGetter(cx, proto, cx->names().byteOffset, Getter<byteOffsetValue>))
+        if (!DefineGetter<byteOffsetValue>(cx, cx->names().byteOffset, proto))
             return false;
 
         return true;
     }
 
     /* subarray(start[, end]) */
     static bool
     fun_subarray_impl(JSContext *cx, CallArgs args)
@@ -710,17 +666,17 @@ class TypedArrayObjectTemplate : public 
                  * Rather than hack some crazy solution together, implement
                  * this all using a private helper function, created when
                  * ArrayBufferObject was initialized and cached in the global.
                  * This reuses all the existing cross-compartment crazy so we
                  * don't have to do anything *uniquely* crazy here.
                  */
 
                 Rooted<JSObject*> proto(cx);
-                if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &proto))
+                if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(fastClass()), &proto))
                     return nullptr;
 
                 InvokeArgs args(cx);
                 if (!args.init(3))
                     return nullptr;
 
                 args.setCallee(cx->compartment()->maybeGlobal()->createArrayFromBuffer<NativeType>());
                 args.setThis(ObjectValue(*bufobj));
@@ -734,96 +690,74 @@ class TypedArrayObjectTemplate : public 
             }
         }
 
         if (!IsArrayBuffer(bufobj)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // must be arrayBuffer
         }
 
-        Rooted<ArrayBufferObject *> buffer(cx, &AsArrayBuffer(bufobj));
-
-        if (byteOffset > buffer->byteLength() || byteOffset % sizeof(NativeType) != 0) {
+        ArrayBufferObject &buffer = AsArrayBuffer(bufobj);
+
+        if (byteOffset > buffer.byteLength() || byteOffset % sizeof(NativeType) != 0) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // invalid byteOffset
         }
 
         uint32_t len;
         if (lengthInt == -1) {
-            len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
-            if (len * sizeof(NativeType) != buffer->byteLength() - byteOffset) {
+            len = (buffer.byteLength() - byteOffset) / sizeof(NativeType);
+            if (len * sizeof(NativeType) != buffer.byteLength() - byteOffset) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N
             }
         } else {
             len = uint32_t(lengthInt);
         }
 
         // Go slowly and check for overflow.
         uint32_t arrayByteLength = len * sizeof(NativeType);
         if (len >= INT32_MAX / sizeof(NativeType) || byteOffset >= INT32_MAX - arrayByteLength) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // overflow when calculating byteOffset + len * sizeof(NativeType)
         }
 
-        if (arrayByteLength + byteOffset > buffer->byteLength()) {
+        if (arrayByteLength + byteOffset > buffer.byteLength()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // byteOffset + len is too big for the arraybuffer
         }
 
-        return makeInstance(cx, buffer, byteOffset, len, proto);
-    }
-
-    static bool
-    maybeCreateArrayBuffer(JSContext *cx, uint32_t nelements, MutableHandle<ArrayBufferObject *> buffer)
-    {
-        // Make sure that array elements evenly divide into the inline buffer's
-        // size, for the test below.
-        JS_STATIC_ASSERT((INLINE_BUFFER_LIMIT / sizeof(NativeType)) * sizeof(NativeType) == INLINE_BUFFER_LIMIT);
-
-        if (nelements <= INLINE_BUFFER_LIMIT / sizeof(NativeType)) {
-            // The array's data can be inline, and the buffer created lazily.
-            return true;
-        }
-
-        if (nelements >= INT32_MAX / sizeof(NativeType)) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
-                                 JSMSG_NEED_DIET, "size and count");
-            return false;
-        }
-
-        buffer.set(ArrayBufferObject::create(cx, nelements * sizeof(NativeType)));
-        return !!buffer;
+        return makeInstance(cx, bufobj, byteOffset, len, proto);
     }
 
     static JSObject *
     fromLength(JSContext *cx, uint32_t nelements)
     {
-        Rooted<ArrayBufferObject *> buffer(cx);
-        if (!maybeCreateArrayBuffer(cx, nelements, &buffer))
+        RootedObject buffer(cx, createBufferWithSizeAndCount(cx, nelements));
+        if (!buffer)
             return nullptr;
         return makeInstance(cx, buffer, 0, nelements);
     }
 
     static JSObject *
     fromArray(JSContext *cx, HandleObject other)
     {
         uint32_t len;
         if (other->is<TypedArrayObject>()) {
             len = other->as<TypedArrayObject>().length();
         } else if (!GetLengthProperty(cx, other, &len)) {
             return nullptr;
         }
 
-        Rooted<ArrayBufferObject *> buffer(cx);
-        if (!maybeCreateArrayBuffer(cx, len, &buffer))
+        RootedObject bufobj(cx, createBufferWithSizeAndCount(cx, len));
+        if (!bufobj)
             return nullptr;
 
-        RootedObject obj(cx, makeInstance(cx, buffer, 0, len));
+        RootedObject obj(cx, makeInstance(cx, bufobj, 0, len));
         if (!obj || !copyFromArray(cx, obj, other, len))
             return nullptr;
         return obj;
     }
 
     static const NativeType
     getIndex(JSObject *obj, uint32_t index)
     {
@@ -842,20 +776,17 @@ class TypedArrayObjectTemplate : public 
     static JSObject *
     createSubarray(JSContext *cx, HandleObject tarrayArg, uint32_t begin, uint32_t end)
     {
         Rooted<TypedArrayObject*> tarray(cx, &tarrayArg->as<TypedArrayObject>());
 
         JS_ASSERT(begin <= tarray->length());
         JS_ASSERT(end <= tarray->length());
 
-        if (!ensureHasBuffer(cx, tarray))
-            return nullptr;
-
-        Rooted<ArrayBufferObject *> bufobj(cx, tarray->buffer());
+        RootedObject bufobj(cx, tarray->buffer());
         JS_ASSERT(bufobj);
 
         JS_ASSERT(begin <= end);
         uint32_t length = end - begin;
 
         JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
         uint32_t arrayByteOffset = tarray->byteOffset();
         JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= arrayByteOffset);
@@ -1129,16 +1060,30 @@ class TypedArrayObjectTemplate : public 
           }
           default:
             MOZ_ASSUME_UNREACHABLE("copyFromWithOverlap with a TypedArrayObject of unknown type");
         }
 
         js_free(srcbuf);
         return true;
     }
+
+    static JSObject *
+    createBufferWithSizeAndCount(JSContext *cx, uint32_t count)
+    {
+        size_t size = sizeof(NativeType);
+        if (size != 0 && count >= INT32_MAX / size) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
+                                 JSMSG_NEED_DIET, "size and count");
+            return nullptr;
+        }
+
+        uint32_t bytelen = size * count;
+        return ArrayBufferObject::create(cx, bytelen);
+    }
 };
 
 class Int8ArrayObject : public TypedArrayObjectTemplate<int8_t> {
   public:
     enum { ACTUAL_TYPE = ScalarTypeDescr::TYPE_INT8 };
     static const JSProtoKey key = JSProto_Int8Array;
     static const JSFunctionSpec jsfuncs[];
 };
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -35,55 +35,34 @@ class TypedArrayObject : public ArrayBuf
     static const size_t TYPE_SLOT      = JS_TYPEDOBJ_SLOT_TYPE_DESCR;
     static const size_t RESERVED_SLOTS = JS_TYPEDOBJ_SLOTS;
     static const size_t DATA_SLOT      = JS_TYPEDOBJ_SLOT_DATA;
 
   public:
     static const Class classes[ScalarTypeDescr::TYPE_MAX];
     static const Class protoClasses[ScalarTypeDescr::TYPE_MAX];
 
-    static const size_t FIXED_DATA_START = DATA_SLOT + 1;
-
-    // For typed arrays which can store their data inline, the array buffer
-    // object is created lazily.
-    static const uint32_t INLINE_BUFFER_LIMIT =
-        (JSObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
-
-    static gc::AllocKind
-    AllocKindForLazyBuffer(size_t nbytes)
-    {
-        JS_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
-        int dataSlots = (nbytes - 1) / sizeof(Value) + 1;
-        JS_ASSERT(int(nbytes) <= dataSlots * int(sizeof(Value)));
-        return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
-    }
-
     static Value bufferValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTEOFFSET_SLOT);
     }
     static Value byteLengthValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTELENGTH_SLOT);
     }
     static Value lengthValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(LENGTH_SLOT);
     }
 
-    static bool
-    ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarray);
-
     ArrayBufferObject *sharedBuffer() const;
     ArrayBufferObject *buffer() const {
-        JSObject *obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
-        if (!obj)
-            return nullptr;
-        if (obj->is<ArrayBufferObject>())
-            return &obj->as<ArrayBufferObject>();
+        JSObject &obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObject();
+        if (obj.is<ArrayBufferObject>())
+            return &obj.as<ArrayBufferObject>();
         return sharedBuffer();
     }
     uint32_t byteOffset() const {
         return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
     uint32_t byteLength() const {
         return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
@@ -244,30 +223,34 @@ class DataViewObject : public ArrayBuffe
     }
 
     static Value byteLengthValue(DataViewObject *view) {
         Value v = view->getReservedSlot(BYTELENGTH_SLOT);
         JS_ASSERT(v.toInt32() >= 0);
         return v;
     }
 
-    static Value bufferValue(DataViewObject *view) {
-        return view->getReservedSlot(BUFFER_SLOT);
-    }
-
     uint32_t byteOffset() const {
         return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
     }
 
     uint32_t byteLength() const {
         return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
     }
 
+    bool hasBuffer() const {
+        return getReservedSlot(BUFFER_SLOT).isObject();
+    }
+
     ArrayBufferObject &arrayBuffer() const {
-        return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
+        return getReservedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObject>();
+    }
+
+    static Value bufferValue(DataViewObject *view) {
+        return view->hasBuffer() ? ObjectValue(view->arrayBuffer()) : UndefinedValue();
     }
 
     void *dataPointer() const {
         return getPrivate();
     }
 
     static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
     static bool constructWithProto(JSContext *cx, unsigned argc, Value *vp);