[INFER] Fix typed array merge botch, bug 678029.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 11 Aug 2011 09:42:41 -0700
changeset 76116 e5de9834cd1837c88a3d9d1706f3c72aeb401896
parent 76115 e0b67d8cc908ec54dd7d79255e50ee58ae579ba8
child 76117 3a7425b9623025ea6886589cd577cf27fbe0a8d7
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
bugs678029
milestone8.0a1
[INFER] Fix typed array merge botch, bug 678029.
js/src/jsapi.cpp
js/src/jsclone.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jstypedarrayinlines.h
js/src/methodjit/BaseAssembler.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1654,17 +1654,17 @@ static JSStdName standard_class_names[] 
 #endif
 
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
 #endif
 
     /* Typed Arrays */
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::fastClass},
+    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer), &js_ArrayBufferClass},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int8Array),    TYPED_ARRAY_CLASP(TYPE_INT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8Array),   TYPED_ARRAY_CLASP(TYPE_UINT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array),   TYPED_ARRAY_CLASP(TYPE_INT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint16Array),  TYPED_ARRAY_CLASP(TYPE_UINT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int32Array),   TYPED_ARRAY_CLASP(TYPE_INT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint32Array),  TYPED_ARRAY_CLASP(TYPE_UINT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -461,18 +461,18 @@ JSStructuredCloneWriter::writeTypedArray
         return false;
     }
 }
 
 bool
 JSStructuredCloneWriter::writeArrayBuffer(JSObject *obj)
 {
     obj = ArrayBuffer::getArrayBuffer(obj);
-    return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, ArrayBuffer::getByteLength(obj)) &&
-           out.writeBytes(ArrayBuffer::getDataOffset(obj), ArrayBuffer::getByteLength(obj));
+    return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, obj->arrayBufferByteLength()) &&
+           out.writeBytes(obj->arrayBufferDataOffset(), obj->arrayBufferByteLength());
 }
 
 bool
 JSStructuredCloneWriter::startObject(JSObject *obj)
 {
     JS_ASSERT(obj->isArray() || obj->isObject());
 
     /* Handle cycles in the object graph. */
@@ -686,18 +686,18 @@ JSStructuredCloneReader::readTypedArray(
 
 bool
 JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
 {
     JSObject *obj = js_CreateArrayBuffer(context(), nbytes);
     if (!obj)
         return false;
     vp->setObject(*obj);
-    JS_ASSERT(ArrayBuffer::getByteLength(obj) == nbytes);
-    return in.readArray(ArrayBuffer::getDataOffset(obj), nbytes);
+    JS_ASSERT(obj->arrayBufferByteLength() == nbytes);
+    return in.readArray(obj->arrayBufferDataOffset(), nbytes);
 }
 
 bool
 JSStructuredCloneReader::startRead(Value *vp)
 {
     uint32_t tag, data;
 
     if (!in.readPair(&tag, &data))
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3669,20 +3669,21 @@ JSObject::TradeGuts(JSContext *cx, JSObj
     /*
      * Regexp guts are more complicated -- we would need to migrate the
      * refcounted JIT code blob for them across compartments instead of just
      * swapping guts.
      */
     JS_ASSERT(!a->isRegExp() && !b->isRegExp());
 
     /*
-     * Callers should not try to swap dense arrays, these use a different slot
-     * representation from other objects.
+     * Callers should not try to swap dense arrays or ArrayBuffer objects,
+     * these use a different slot representation from other objects.
      */
     JS_ASSERT(!a->isDenseArray() && !b->isDenseArray());
+    JS_ASSERT(!a->isArrayBuffer() && !b->isArrayBuffer());
 
     /* Trade the guts of the objects. */
     const size_t size = a->structSize();
     if (size == b->structSize()) {
         /*
          * If the objects are the same size, then we make no assumptions about
          * whether they have dynamically allocated slots and instead just copy
          * them over wholesale.
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -311,23 +311,28 @@ class ValidateWriter;
  * is different for dense arrays vs. other objects.
  *
  * For dense arrays (arrays with only normal integer properties), the 'slots'
  * member points either to the fixed array or to a dynamic array, and in
  * all cases is indexed by the associated property (e.g. obj->slots[5] stores
  * the value for property '5'). If a dynamic array is in use, slots in the
  * fixed array are not used.
  *
- * For objects other than dense arrays, if the object has N fixed slots then
- * those are always the first N slots of the object. The dynamic slots pointer
- * is used if those fixed slots overflow, and stores all remaining slots.
- * The dynamic slots pointer is NULL if there is no slots overflow, and never
- * points to the object's fixed slots. Unlike dense arrays, the fixed slots
- * can always be accessed. Two objects with the same shape are guaranteed to
- * have the same number of fixed slots.
+ * ArrayBuffer objects may also use their fixed slots for storage in a similar
+ * manner to dense arrays. The fixed slots do not represent Values in such
+ * cases. (ArrayBuffers never have other properties added directly to them, as
+ * they delegate such attempts to another JSObject).
+ *
+ * For objects other than dense arrays and array buffers, if the object has N
+ * fixed slots then those are always the first N slots of the object. The
+ * dynamic slots pointer is used if those fixed slots overflow, and stores all
+ * remaining slots. The dynamic slots pointer is NULL if there is no slots
+ * overflow, and never points to the object's fixed slots. Unlike dense arrays,
+ * the fixed slots can always be accessed. Two objects with the same shape are
+ * guaranteed to have the same number of fixed slots.
  *
  * If you change this struct, you'll probably need to change the AccSet values
  * in jsbuiltins.h.
  */
 struct JSObject : js::gc::Cell {
     /*
      * TraceRecorder must be a friend because it generates code that
      * manipulates JSObjects, which requires peeking under any encapsulation.
@@ -959,16 +964,21 @@ struct JSObject : js::gc::Cell {
      * Check if after growing the dense array will be too sparse.
      * newElementsHint is an estimated number of elements to be added.
      */
     bool willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint);
 
     JSBool makeDenseArraySlow(JSContext *cx);
 
   public:
+    bool allocateArrayBufferSlots(JSContext *cx, uint32 size);
+    inline uint32 arrayBufferByteLength();
+    inline uint8 * arrayBufferDataOffset();
+
+  public:
     inline js::ArgumentsObject *asArguments();
     inline js::NormalArgumentsObject *asNormalArguments();
     inline js::StrictArgumentsObject *asStrictArguments();
 
   private:
     /*
      * Reserved slot structure for Call objects:
      *
@@ -1400,16 +1410,17 @@ struct JSObject : js::gc::Cell {
     inline bool isXMLId() const;
     inline bool isNamespace() const;
     inline bool isQName() const;
     inline bool isWeakMap() const;
 
     inline bool isProxy() const;
     inline bool isObjectProxy() const;
     inline bool isFunctionProxy() const;
+    inline bool isArrayBuffer() const;
 
     JS_FRIEND_API(bool) isWrapper() const;
     JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL);
 
     inline void initArrayClass();
 };
 
 /* Check alignment for any fixed slots allocated after the object. */
@@ -1503,17 +1514,17 @@ class JSValueArray {
 class ValueArray {
   public:
     js::Value *array;
     size_t length;
 
     ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
 };
 
-extern js::Class js_ArrayClass, js_SlowArrayClass;
+extern js::Class js_ArrayClass, js_SlowArrayClass, js_ArrayBufferClass;
 
 inline bool
 JSObject::isDenseArray() const
 {
     return getClass() == &js_ArrayClass;
 }
 
 inline bool
@@ -1523,16 +1534,22 @@ JSObject::isSlowArray() const
 }
 
 inline bool
 JSObject::isArray() const
 {
     return isDenseArray() || isSlowArray();
 }
 
+inline bool
+JSObject::isArrayBuffer() const
+{
+    return getClass() == &js_ArrayBufferClass;
+}
+
 extern js::Class js_ObjectClass;
 extern js::Class js_WithClass;
 extern js::Class js_BlockClass;
 
 inline bool JSObject::isObject() const { return getClass() == &js_ObjectClass; }
 inline bool JSObject::isWith() const   { return getClass() == &js_WithClass; }
 inline bool JSObject::isBlock() const  { return getClass() == &js_BlockClass; }
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -400,17 +400,17 @@ JSObject::finalizeKind() const
 {
     return js::gc::FinalizeKind(arenaHeader()->getThingKind());
 }
 
 inline bool
 JSObject::hasSlotsArray() const
 {
     JS_ASSERT_IF(!slots, !isDenseArray());
-    JS_ASSERT_IF(slots == fixedSlots(), isDenseArray());
+    JS_ASSERT_IF(slots == fixedSlots(), isDenseArray() || isArrayBuffer());
     return slots && slots != fixedSlots();
 }
 
 inline size_t
 JSObject::structSize() const
 {
     return (isFunction() && !getPrivate())
            ? sizeof(JSFunction)
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -68,16 +68,19 @@
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
+/* slots can only be upto 255 */
+static const uint8 ARRAYBUFFER_RESERVED_SLOTS = 16;
+
 static bool
 ValueIsLength(JSContext *cx, const Value &v, jsuint *len)
 {
     if (v.isInt32()) {
         int32_t i = v.toInt32();
         if (i < 0)
             return false;
         *len = i;
@@ -124,17 +127,17 @@ ArrayBuffer::getArrayBuffer(JSObject *ob
 JSBool
 ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JSObject *arrayBuffer = getArrayBuffer(obj);
     if (!arrayBuffer) {
         vp->setInt32(0);
         return true;
     }
-    vp->setInt32(jsint(ArrayBuffer::getByteLength(arrayBuffer)));
+    vp->setInt32(jsint(arrayBuffer->arrayBufferByteLength()));
     return true;
 }
 
 /*
  * new ArrayBuffer(byteLength)
  */
 JSBool
 ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp)
@@ -145,34 +148,42 @@ ArrayBuffer::class_constructor(JSContext
 
     JSObject *bufobj = create(cx, nbytes);
     if (!bufobj)
         return false;
     vp->setObject(*bufobj);
     return true;
 }
 
-static inline JSBool
-AllocateArrayBufferSlots(JSContext *cx, JSObject *obj, uint32 size)
+bool
+JSObject::allocateArrayBufferSlots(JSContext *cx, uint32 size)
 {
-    void *data = NULL;
-    if (size) {
-        data = cx->calloc_(size);
-        if (!data)
+    /*
+     * ArrayBuffer objects delegate added properties to another JSObject, so
+     * their internal layout can use the object's fixed slots for storage.
+     */
+    JS_ASSERT(isArrayBuffer() && !hasSlotsArray());
+
+    uint32 bytes = size + sizeof(Value);
+    if (size > sizeof(Value) * ARRAYBUFFER_RESERVED_SLOTS - sizeof(Value) ) {
+        Value *tmpslots = (Value *)cx->calloc_(bytes);
+        if (!tmpslots)
             return false;
+        slots = tmpslots;
+        /*
+         * Note that |bytes| may not be a multiple of |sizeof(Value)|, so
+         * |capacity * sizeof(Value)| may underestimate the size by up to
+         * |sizeof(Value) - 1| bytes.
+         */
+        capacity = bytes / sizeof(Value);
+    } else {
+        slots = fixedSlots();
+        memset(slots, 0, bytes);
     }
-
-    Value v;
-
-    v.setPrivate(data);
-    obj->setFixedSlot(ArrayBuffer::JSSLOT_ARRAY_DATA, v);
-
-    v.setPrivateUint32(size);
-    obj->setFixedSlot(ArrayBuffer::JSSLOT_ARRAY_BYTELENGTH, v);
-
+    *((uint32*)slots) = size;
     return true;
 }
 
 static JSObject *
 DelegateObject(JSContext *cx, JSObject *obj)
 {
     if (!obj->getPrivate()) {
         JSObject *delegate = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, obj->getProto(), NULL);
@@ -194,26 +205,27 @@ ArrayBuffer::create(JSContext *cx, int32
          * 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, NULL, JSMSG_BAD_ARRAY_LENGTH);
         return NULL;
     }
 
+    JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
+    obj->setSharedNonNativeMap();
+    obj->clasp = &js_ArrayBufferClass;
+
     /*
      * The first 8 bytes hold the length.
      * The rest of it is a flat data store for the array buffer.
      */
-    if (!AllocateArrayBufferSlots(cx, obj, nbytes))
+    if (!obj->allocateArrayBufferSlots(cx, nbytes))
         return NULL;
 
-    JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
-    obj->setSharedNonNativeMap();
-    obj->clasp = &ArrayBuffer::fastClass;
     return obj;
 }
 
 ArrayBuffer::~ArrayBuffer()
 {
 }
 
 void
@@ -277,17 +289,17 @@ ArrayBuffer::obj_defineProperty(JSContex
     return js_DefineProperty(cx, delegate, id, v, getter, setter, attrs);
 }
 
 JSBool
 ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     obj = getArrayBuffer(obj);
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
-        vp->setInt32(getByteLength(obj));
+        vp->setInt32(obj->arrayBufferByteLength());
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_GetProperty(cx, delegate, receiver, id, vp);
 }
@@ -926,17 +938,17 @@ class TypedArrayTemplate
     obj_typeOf(JSContext *cx, JSObject *obj)
     {
         return JSTYPE_OBJECT;
     }
 
     static JSObject *
     createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len)
     {
-        JS_ASSERT(bufobj->getClass() == &ArrayBuffer::fastClass);
+        JS_ASSERT(bufobj->isArrayBuffer());
         JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
         if (!obj)
             return NULL;
 
         /*
          * Specialize the type of the object on the current scripted location,
          * and mark the type as definitely a typed array.
          */
@@ -949,26 +961,27 @@ class TypedArrayTemplate
         obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
         obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
 
         /*
          * 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->setPrivate(ArrayBuffer::getDataOffset(bufobj) + byteOffset);
+        obj->setPrivate(bufobj->arrayBufferDataOffset() + byteOffset);
 
         obj->setSlot(FIELD_LENGTH, Int32Value(len));
         obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset));
         obj->setSlot(FIELD_BYTELENGTH, Int32Value(len * sizeof(NativeType)));
 
-        JS_ASSERT(ArrayBuffer::getByteLength(getBuffer(obj)) - getByteOffset(obj) >= getByteLength(obj));
-        JS_ASSERT(getByteOffset(obj) <= ArrayBuffer::getByteLength(getBuffer(obj)));
-        JS_ASSERT(ArrayBuffer::getDataOffset(getBuffer(obj)) <= getDataOffset(obj));
-        JS_ASSERT(getDataOffset(obj) <= offsetData(obj, ArrayBuffer::getByteLength(getBuffer(obj))));
+        DebugOnly<uint32> bufferByteLength = getBuffer(obj)->arrayBufferByteLength();
+        JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj));
+        JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
+        JS_ASSERT(getBuffer(obj)->arrayBufferDataOffset() <= getDataOffset(obj));
+        JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
 
         JS_ASSERT(obj->getClass() == slowClass());
         obj->setSharedNonNativeMap();
         obj->clasp = fastClass();
 
         // FIXME Bug 599008: make it ok to call preventExtensions here.
         obj->flags |= JSObject::NOT_EXTENSIBLE;
 
@@ -1196,29 +1209,29 @@ class TypedArrayTemplate
   public:
     static JSObject *
     createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
                                      int32 byteOffsetInt, int32 lengthInt)
     {
         JS_ASSERT(!js_IsTypedArray(other));
 
         /* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
-        if (other->getClass() == &ArrayBuffer::fastClass) {
+        if (other->isArrayBuffer()) {
             uint32 boffset = (byteOffsetInt < 0) ? 0 : uint32(byteOffsetInt);
 
-            if (boffset > ArrayBuffer::getByteLength(other) || boffset % sizeof(NativeType) != 0) {
+            if (boffset > other->arrayBufferByteLength() || boffset % sizeof(NativeType) != 0) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return NULL; // invalid byteOffset
             }
 
             uint32 len;
             if (lengthInt < 0) {
-                len = (ArrayBuffer::getByteLength(other) - boffset) / sizeof(NativeType);
-                if (len * sizeof(NativeType) != (ArrayBuffer::getByteLength(other) - boffset)) {
+                len = (other->arrayBufferByteLength() - boffset) / sizeof(NativeType);
+                if (len * sizeof(NativeType) != (other->arrayBufferByteLength() - boffset)) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_TYPED_ARRAY_BAD_ARGS);
                     return NULL; // given byte array doesn't map exactly to sizeof(NativeType)*N
                 }
             } else {
                 len = (uint32) lengthInt;
             }
 
@@ -1227,17 +1240,17 @@ class TypedArrayTemplate
             if (uint32(len) >= INT32_MAX / sizeof(NativeType) ||
                 uint32(boffset) >= INT32_MAX - arrayByteLength)
             {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return NULL; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
             }
 
-            if (arrayByteLength + boffset > ArrayBuffer::getByteLength(other)) {
+            if (arrayByteLength + boffset > other->arrayBufferByteLength()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return NULL; // boffset+len is too big for the arraybuffer
             }
 
             return createTypedArray(cx, other, boffset, len);
         }
 
@@ -1664,33 +1677,33 @@ TypedArrayTemplate<double>::copyIndexToV
 
 /*
  * ArrayBuffer (base)
  */
 
 Class ArrayBuffer::slowClass = {
     "ArrayBuffer",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(ArrayBuffer::JSSLOT_ARRAY_RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
     FinalizeStub
 };
 
-Class ArrayBuffer::fastClass = {
+Class js_ArrayBufferClass = {
     "ArrayBuffer",
     JSCLASS_HAS_PRIVATE |
     Class::NON_NATIVE |
-    JSCLASS_HAS_RESERVED_SLOTS(ArrayBuffer::JSSLOT_ARRAY_RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
@@ -1882,24 +1895,19 @@ Class TypedArray::slowClasses[TYPE_MAX] 
 };
 
 static JSObject *
 InitArrayBufferClass(JSContext *cx, GlobalObject *global)
 {
     JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBuffer::slowClass);
     if (!arrayBufferProto)
         return NULL;
-    arrayBufferProto->setPrivate(NULL);
-
-    /* Ensure ArrayBuffer.prototype is correctly empty. */
-    if (!AllocateArrayBufferSlots(cx, arrayBufferProto, 0))
-        return NULL;
 
     JSFunction *ctor =
-        global->createConstructor(cx, ArrayBuffer::class_constructor, &ArrayBuffer::fastClass,
+        global->createConstructor(cx, ArrayBuffer::class_constructor, &js_ArrayBufferClass,
                                   CLASS_ATOM(cx, ArrayBuffer), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, arrayBufferProto, ArrayBuffer::jsprops, NULL))
@@ -1940,40 +1948,40 @@ js_InitTypedArrayClasses(JSContext *cx, 
 
     return InitArrayBufferClass(cx, global);
 }
 
 JS_FRIEND_API(JSBool)
 js_IsArrayBuffer(JSObject *obj)
 {
     JS_ASSERT(obj);
-    return obj->getClass() == &ArrayBuffer::fastClass;
+    return obj->getClass() == &js_ArrayBufferClass;
 }
 
 namespace js {
 
 bool
 IsFastTypedArrayClass(const Class *clasp)
 {
     return &TypedArray::fastClasses[0] <= clasp &&
            clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX];
 }
 
 } // namespace js
 
 JSUint32
 JS_GetArrayBufferByteLength(JSObject *obj)
 {
-    return ArrayBuffer::getByteLength(obj);
+    return obj->arrayBufferByteLength();
 }
 
 uint8 *
 JS_GetArrayBufferData(JSObject *obj)
 {
-    return ArrayBuffer::getDataOffset(obj);
+    return obj->arrayBufferDataOffset();
 }
 
 JS_FRIEND_API(JSBool)
 js_IsTypedArray(JSObject *obj)
 {
     JS_ASSERT(obj);
     Class *clasp = obj->getClass();
     return IsFastTypedArrayClass(clasp);
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -52,17 +52,16 @@ namespace js {
  *
  * This class holds the underlying raw buffer that the TypedArray
  * subclasses access.  It can be created explicitly and passed to a
  * TypedArray subclass, or can be created implicitly by constructing a
  * TypedArray with a size.
  */
 struct JS_FRIEND_API(ArrayBuffer) {
     static Class slowClass;
-    static Class fastClass;
     static JSPropertySpec jsprops[];
 
     static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
     static JSBool class_constructor(JSContext *cx, uintN argc, Value *vp);
 
     static JSObject *create(JSContext *cx, int32 nbytes);
 
@@ -102,25 +101,16 @@ struct JS_FRIEND_API(ArrayBuffer) {
     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                   Value *statep, jsid *idp);
 
     static JSType
     obj_typeOf(JSContext *cx, JSObject *obj);
 
     static JSObject *
     getArrayBuffer(JSObject *obj);
-
-    static inline unsigned int getByteLength(JSObject *obj);
-
-    static inline uint8 * getDataOffset(JSObject *obj);
-
-    /* Reserved slots for array buffer objects. */
-    static const uint32 JSSLOT_ARRAY_BYTELENGTH = 0;
-    static const uint32 JSSLOT_ARRAY_DATA = 1;
-    static const uint32 JSSLOT_ARRAY_RESERVED_SLOTS = 2;
 };
 
 /*
  * TypedArray
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -39,29 +39,32 @@
 
 #ifndef jstypedarrayinlines_h
 #define jstypedarrayinlines_h
 
 #include "jsapi.h"
 #include "jsvalue.h"
 #include "jsobj.h"
 
-namespace js {
-inline JSUint32
-ArrayBuffer::getByteLength(JSObject *obj)
+inline uint32
+JSObject::arrayBufferByteLength()
 {
-    return obj->getFixedSlot(JSSLOT_ARRAY_BYTELENGTH).toPrivateUint32();
+    JS_ASSERT(isArrayBuffer());
+    return *((uint32*) slots);
 }
 
 inline uint8 *
-ArrayBuffer::getDataOffset(JSObject *obj)
+JSObject::arrayBufferDataOffset()
 {
-    return (uint8 *) obj->getFixedSlot(JSSLOT_ARRAY_DATA).toPrivate();
+    uint64 *base = ((uint64*)slots) + 1;
+    return (uint8*) base;
 }
 
+namespace js {
+
 static inline int32
 ClampIntForUint8Array(int32 x)
 {
     if (x < 0)
         return 0;
     if (x > 255)
         return 255;
     return x;
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -1256,17 +1256,17 @@ static const JSC::MacroAssembler::Regist
         /*
          * Write out the slots pointer before readjusting the result register,
          * as for dense arrays this is relative to the JSObject itself.
          */
         if (templateObject->isDenseArray()) {
             JS_ASSERT(!templateObject->initializedLength);
             addPtr(Imm32(-thingSize + sizeof(JSObject)), result);
             storePtr(result, Address(result, -sizeof(JSObject) + JSObject::offsetOfSlots()));
-            addPtr(Imm32(-sizeof(JSObject)), result);
+            addPtr(Imm32(-(int)sizeof(JSObject)), result);
         } else {
             JS_ASSERT(!templateObject->newType);
             addPtr(Imm32(-thingSize), result);
             storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
         }
 
         storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp)));
         storePtr(ImmPtr(templateObject->clasp), Address(result, offsetof(JSObject, clasp)));