Bug 1073836 - Remove byte offset slot and non-unsized uses of length from typed objects, r=nmatsakis.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 08 Oct 2014 09:38:09 -0700
changeset 233906 91914270690b322a326a2971c991cd81813dc67c
parent 233905 0cb0d9df5a8ef984bb47fb479c7727cebd838e1b
child 233907 71e05880cbb000beab99cee987147766bc82b915
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnmatsakis
bugs1073836
milestone35.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 1073836 - Remove byte offset slot and non-unsized uses of length from typed objects, r=nmatsakis.
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObjectConstants.h
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/LIR-Common.h
js/src/jit/Lowering.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
@@ -1457,40 +1457,49 @@ js_InitTypedObjectDummy(JSContext *cx, H
  * Typed objects
  */
 
 int32_t
 TypedObject::offset() const
 {
     if (is<InlineOpaqueTypedObject>())
         return 0;
-    return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET).toInt32();
+    return typedMem() - typedMemBase();
 }
 
 int32_t
 TypedObject::length() const
 {
-    MOZ_ASSERT(typeDescr().kind() == type::SizedArray ||
-               typeDescr().kind() == type::UnsizedArray);
-
-    if (is<InlineOpaqueTypedObject>())
+    if (typeDescr().is<SizedArrayTypeDescr>())
         return typeDescr().as<SizedArrayTypeDescr>().length();
-    return as<OutlineTypedObject>().length();
+    return as<OutlineTypedObject>().unsizedLength();
 }
 
 uint8_t *
 TypedObject::typedMem() const
 {
     MOZ_ASSERT(isAttached());
 
     if (is<InlineOpaqueTypedObject>())
         return as<InlineOpaqueTypedObject>().inlineTypedMem();
     return as<OutlineTypedObject>().outOfLineTypedMem();
 }
 
+uint8_t *
+TypedObject::typedMemBase() const
+{
+    MOZ_ASSERT(isAttached());
+    MOZ_ASSERT(is<OutlineTypedObject>());
+
+    JSObject &owner = as<OutlineTypedObject>().owner();
+    if (owner.is<ArrayBufferObject>())
+        return owner.as<ArrayBufferObject>().dataPointer();
+    return owner.as<InlineOpaqueTypedObject>().inlineTypedMem();
+}
+
 bool
 TypedObject::isAttached() const
 {
     if (is<InlineOpaqueTypedObject>())
         return true;
     if (!as<OutlineTypedObject>().outOfLineTypedMem())
         return false;
     JSObject &owner = as<OutlineTypedObject>().owner();
@@ -1574,35 +1583,34 @@ OutlineTypedObject::createUnattachedWith
     if (!proto)
         return nullptr;
 
     RootedObject obj(cx, NewObjectWithClassProto(cx, clasp, proto, nullptr));
     if (!obj)
         return nullptr;
 
     obj->fakeNativeInitPrivate(nullptr);
-    obj->fakeNativeInitReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
-    obj->fakeNativeInitReservedSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(length));
-    obj->fakeNativeInitReservedSlot(JS_BUFVIEW_SLOT_OWNER, NullValue());
+    if (type->kind() == type::UnsizedArray)
+        obj->fakeNativeInitReservedSlot(LENGTH_SLOT, Int32Value(length));
+    obj->fakeNativeInitReservedSlot(OWNER_SLOT, NullValue());
 
     return &obj->as<OutlineTypedObject>();
 }
 
 void
 OutlineTypedObject::attach(JSContext *cx, ArrayBufferObject &buffer, int32_t offset)
 {
     MOZ_ASSERT(offset >= 0);
     MOZ_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
 
     if (!buffer.addView(cx, this))
         CrashAtUnhandlableOOM("TypedObject::attach");
 
     fakeNativeInitPrivate(buffer.dataPointer() + offset);
-    fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
-    fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(buffer));
+    fakeNativeSetReservedSlot(OWNER_SLOT, ObjectValue(buffer));
 }
 
 void
 OutlineTypedObject::attach(JSContext *cx, TypedObject &typedObj, int32_t offset)
 {
     MOZ_ASSERT(typedObj.isAttached());
 
     JSObject *owner = &typedObj;
@@ -1613,18 +1621,17 @@ OutlineTypedObject::attach(JSContext *cx
 
     if (owner->is<ArrayBufferObject>()) {
         attach(cx, owner->as<ArrayBufferObject>(), offset);
     } else {
         MOZ_ASSERT(owner->is<InlineOpaqueTypedObject>());
         fakeNativeInitPrivate(owner->as<InlineOpaqueTypedObject>().inlineTypedMem() + offset);
         PostBarrierTypedArrayObject(this);
 
-        fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
-        fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(*owner));
+        fakeNativeSetReservedSlot(OWNER_SLOT, ObjectValue(*owner));
     }
 }
 
 // Returns a suitable JS_TYPEDOBJ_SLOT_LENGTH value for an instance of
 // the type `type`. `type` must not be an unsized array.
 static int32_t
 TypedObjLengthFromType(TypeDescr &descr)
 {
@@ -1754,17 +1761,17 @@ OutlineTypedObject::obj_trace(JSTracer *
     // When this is called for compacting GC, the related objects we touch here
     // may not have had their slots updated yet. Note that this does not apply
     // to generational GC because these objects (type descriptors and
     // prototypes) are never allocated in the nursery.
     TypeDescr &descr = typedObj.maybeForwardedTypeDescr();
 
     // Mark the owner, watching in case it is moved by the tracer.
     JSObject *oldOwner = typedObj.maybeOwner();
-    gc::MarkSlot(trc, &typedObj.fakeNativeGetSlotRef(JS_BUFVIEW_SLOT_OWNER), "typed object owner");
+    gc::MarkSlot(trc, &typedObj.fakeNativeGetSlotRef(OWNER_SLOT), "typed object owner");
     JSObject *owner = typedObj.maybeOwner();
 
     uint8_t *mem = typedObj.outOfLineTypedMem();
 
     // Update the data pointer if the owner moved and the owner's data is
     // inline with it.
     if (owner != oldOwner &&
         (owner->is<InlineOpaqueTypedObject>() ||
@@ -1784,17 +1791,17 @@ OutlineTypedObject::obj_trace(JSTracer *
       case type::SizedArray:
       case type::Simd:
         descr.as<SizedTypeDescr>().traceInstances(trc, mem, 1);
         break;
 
       case type::UnsizedArray:
       {
         SizedTypeDescr &elemType = descr.as<UnsizedArrayTypeDescr>().maybeForwardedElementType();
-        elemType.traceInstances(trc, mem, typedObj.length());
+        elemType.traceInstances(trc, mem, typedObj.unsizedLength());
         break;
       }
     }
 }
 
 bool
 TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
                               MutableHandleObject objp, MutableHandleShape propp)
@@ -2315,17 +2322,17 @@ TypedObject::obj_enumerate(JSContext *cx
     }
 
     return true;
 }
 
 /* static */ size_t
 OutlineTypedObject::offsetOfOwnerSlot()
 {
-    return NativeObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_OWNER);
+    return NativeObject::getFixedSlotOffset(OWNER_SLOT);
 }
 
 /* static */ size_t
 OutlineTypedObject::offsetOfDataSlot()
 {
 #ifdef DEBUG
     // Compute offset of private data based on TransparentTypedObject;
     // both OpaqueOutlineTypedObject and TransparentTypedObject have the same
@@ -2333,27 +2340,21 @@ OutlineTypedObject::offsetOfDataSlot()
     gc::AllocKind allocKind = gc::GetGCObjectKind(&TransparentTypedObject::class_);
     size_t nfixed = gc::GetGCKindSlots(allocKind);
     MOZ_ASSERT(DATA_SLOT == nfixed - 1);
 #endif
 
     return NativeObject::getPrivateDataOffset(DATA_SLOT);
 }
 
-/* static */ size_t
-OutlineTypedObject::offsetOfByteOffsetSlot()
-{
-    return NativeObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_BYTEOFFSET);
-}
-
 void
 OutlineTypedObject::neuter(void *newData)
 {
-    fakeNativeSetSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(0));
-    fakeNativeSetSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
+    if (typeDescr().kind() == type::UnsizedArray)
+        fakeNativeSetSlot(LENGTH_SLOT, Int32Value(0));
     fakeNativeSetPrivate(newData);
 }
 
 /******************************************************************************
  * Inline typed objects
  */
 
 /* static */ InlineOpaqueTypedObject *
@@ -2828,20 +2829,18 @@ js::SetTypedObjectOffset(ThreadSafeConte
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
     MOZ_ASSERT(args[1].isInt32());
 
     OutlineTypedObject &typedObj = args[0].toObject().as<OutlineTypedObject>();
     int32_t offset = args[1].toInt32();
 
     MOZ_ASSERT(typedObj.isAttached());
-    int32_t oldOffset = typedObj.offset();
-
-    typedObj.fakeNativeSetPrivate((typedObj.typedMem() - oldOffset) + offset);
-    typedObj.fakeNativeSetReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
+
+    typedObj.fakeNativeSetPrivate(typedObj.typedMemBase() + offset);
     args.rval().setUndefined();
     return true;
 }
 
 bool
 js::intrinsic_SetTypedObjectOffset(JSContext *cx, unsigned argc, Value *vp)
 {
     // Do not use JSNativeThreadSafeWrapper<> so that ion can reference
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -626,16 +626,17 @@ class TypedObject : public JSObject
 
     TypeDescr &maybeForwardedTypeDescr() const {
         return maybeForwardedTypedProto().maybeForwardedTypeDescr();
     }
 
     int32_t offset() const;
     int32_t length() const;
     uint8_t *typedMem() const;
+    uint8_t *typedMemBase() const;
     bool isAttached() const;
     bool maybeForwardedIsAttached() const;
 
     int32_t size() const {
         switch (typeDescr().kind()) {
           case type::Scalar:
           case type::Simd:
           case type::Reference:
@@ -678,45 +679,50 @@ class TypedObject : public JSObject
     static bool GetByteOffset(JSContext *cx, unsigned argc, Value *vp);
 };
 
 typedef Handle<TypedObject*> HandleTypedObject;
 
 class OutlineTypedObject : public TypedObject
 {
   public:
+    // The array buffer or inline array owning the memory for this object.
+    static const size_t OWNER_SLOT = 0;
+
+    // For unsized arrays, the length of the array.
+    static const size_t LENGTH_SLOT = 1;
+
+    // Slot holding the data pointer.
     static const size_t DATA_SLOT = 3;
 
     static size_t offsetOfOwnerSlot();
 
     // Each typed object contains a void* pointer pointing at the
     // binary data that it represents. (That data may be owned by this
     // object or this object may alias data owned by someone else.)
     // This function returns the offset in bytes within the object
     // where the `void*` pointer can be found. It is intended for use
     // by the JIT.
     static size_t offsetOfDataSlot();
 
-    // Offset of the byte offset slot.
-    static size_t offsetOfByteOffsetSlot();
-
     JSObject &owner() const {
-        return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObject();
+        return fakeNativeGetReservedSlot(OWNER_SLOT).toObject();
     }
 
     JSObject *maybeOwner() const {
-        return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObjectOrNull();
+        return fakeNativeGetReservedSlot(OWNER_SLOT).toObjectOrNull();
     }
 
     uint8_t *outOfLineTypedMem() const {
         return static_cast<uint8_t *>(fakeNativeGetPrivate(DATA_SLOT));
     }
 
-    int32_t length() const {
-        return fakeNativeGetReservedSlot(JS_BUFVIEW_SLOT_LENGTH).toInt32();
+    int32_t unsizedLength() const {
+        MOZ_ASSERT(typeDescr().is<UnsizedArrayTypeDescr>());
+        return fakeNativeGetReservedSlot(LENGTH_SLOT).toInt32();
     }
 
     // Helper for createUnattached()
     static OutlineTypedObject *createUnattachedWithClass(JSContext *cx,
                                                          const Class *clasp,
                                                          HandleTypeDescr type,
                                                          int32_t length);
 
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -82,38 +82,9 @@
 
 // These constants are for use exclusively in JS code.  In C++ code,
 // prefer SimdTypeRepresentation::TYPE_INT32 etc, since that allows
 // you to write a switch which will receive a warning if you omit a
 // case.
 #define JS_SIMDTYPEREPR_INT32         0
 #define JS_SIMDTYPEREPR_FLOAT32       1
 
-///////////////////////////////////////////////////////////////////////////
-// Slots for typed objects
-
-
-// Common to data view, typed arrays, and typed objects:
-#define JS_BUFVIEW_SLOT_BYTEOFFSET       0
-#define JS_BUFVIEW_SLOT_LENGTH           1 // see (*) below
-#define JS_BUFVIEW_SLOT_OWNER            2
-
-// Specific to data view:
-#define JS_DATAVIEW_SLOT_DATA            3 // see (**) below
-#define JS_DATAVIEW_SLOTS                3 // Number of slots for data views
-
-// Specific to typed arrays:
-#define JS_TYPEDARR_SLOT_DATA            3 // see (**) below
-#define JS_TYPEDARR_SLOTS                3 // Number of slots for typed arrays
-
-// (*) The interpretation of the JS_BUFVIEW_SLOT_LENGTH slot depends on
-// the kind of view:
-// - DataView: stores the length in bytes
-// - TypedArray: stores the array length
-// - TypedObject: for arrays, stores the array length, else 0
-
-// (**) This is the index of the slot that will be used for private data.
-// It is hardcoded here based on the GC Kind that will be assigned. It is
-// a function of the total number of slots, but it is non-trivial to encode
-// that function at compile-time, so we instead use a hardcoded constant
-// coupled with some handy assertions.
-
 #endif
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4984,17 +4984,17 @@ CodeGenerator::visitNeuterCheck(LNeuterC
     Register obj = ToRegister(lir->object());
     Register temp = ToRegister(lir->temp());
 
     Label inlineObject;
     masm.loadObjClass(obj, temp);
     masm.branchPtr(Assembler::Equal, temp, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
 
     masm.extractObject(Address(obj, OutlineTypedObject::offsetOfOwnerSlot()), temp);
-    masm.unboxInt32(Address(temp, ArrayBufferObject::flagsOffset()), temp);
+    masm.unboxInt32(Address(temp, ArrayBufferObject::offsetOfFlagsSlot()), temp);
 
     Imm32 flag(ArrayBufferObject::neuteredFlag());
     if (!bailoutTest32(Assembler::NonZero, temp, flag, lir->snapshot()))
         return false;
 
     masm.bind(&inlineObject);
 
     return true;
@@ -5038,55 +5038,36 @@ CodeGenerator::visitTypedObjectElements(
 }
 
 bool
 CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset *lir)
 {
     Register object = ToRegister(lir->object());
     Register offset = ToRegister(lir->offset());
     Register temp0 = ToRegister(lir->temp0());
-
-    // `offset` is an absolute offset into the base buffer. One way
-    // to implement this instruction would be load the base address
-    // from the buffer and add `offset`. But that'd be an extra load.
-    // We can instead load the current base pointer and current
-    // offset, compute the difference with `offset`, and then adjust
-    // the current base pointer. This is two loads but to adjacent
-    // fields in the same object, which should come in the same cache
-    // line.
-    //
-    // The C code I would probably write is the following:
-    //
-    // void SetTypedObjectOffset(TypedObject *obj, int32_t offset) {
-    //     int32_t temp0 = obj->byteOffset;
-    //     obj->pointer = obj->pointer - temp0 + offset;
-    //     obj->byteOffset = offset;
-    // }
-    //
-    // But what we actually compute is more like this, because it
-    // saves us a temporary to do it this way:
-    //
-    // void SetTypedObjectOffset(TypedObject *obj, int32_t offset) {
-    //     int32_t temp0 = obj->byteOffset;
-    //     obj->pointer = obj->pointer - (temp0 - offset);
-    //     obj->byteOffset = offset;
-    // }
-
-    // temp0 = typedObj->byteOffset;
-    masm.unboxInt32(Address(object, OutlineTypedObject::offsetOfByteOffsetSlot()), temp0);
-
-    // temp0 -= offset;
-    masm.subPtr(offset, temp0);
-
-    // obj->pointer -= temp0;
-    masm.subPtr(temp0, Address(object, OutlineTypedObject::offsetOfDataSlot()));
-
-    // obj->byteOffset = offset;
-    masm.storeValue(JSVAL_TYPE_INT32, offset,
-                    Address(object, OutlineTypedObject::offsetOfByteOffsetSlot()));
+    Register temp1 = ToRegister(lir->temp1());
+
+    // Compute the base pointer for the typed object's owner.
+    masm.extractObject(Address(object, OutlineTypedObject::offsetOfOwnerSlot()), temp0);
+
+    Label inlineObject, done;
+    masm.loadObjClass(temp0, temp1);
+    masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
+
+    masm.loadPrivate(Address(temp0, ArrayBufferObject::offsetOfDataSlot()), temp0);
+    masm.jump(&done);
+
+    masm.bind(&inlineObject);
+    masm.addPtr(ImmWord(InlineOpaqueTypedObject::offsetOfDataStart()), temp0);
+
+    masm.bind(&done);
+
+    // Compute the new data pointer and set it in the object.
+    masm.addPtr(offset, temp0);
+    masm.storePtr(temp0, Address(object, OutlineTypedObject::offsetOfDataSlot()));
 
     return true;
 }
 
 bool
 CodeGenerator::visitStringLength(LStringLength *lir)
 {
     Register input = ToRegister(lir->string());
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7219,29 +7219,31 @@ IonBuilder::checkTypedObjectIndexInBound
     int32_t lenOfAll;
     MDefinition *length;
     if (objPrediction.hasKnownArrayLength(&lenOfAll)) {
         length = constantInt(lenOfAll);
 
         // If we are not loading the length from the object itself,
         // then we still need to check if the object was neutered.
         *canBeNeutered = true;
-    } else {
-        MInstruction *lengthValue = MLoadFixedSlot::New(alloc(), obj, JS_BUFVIEW_SLOT_LENGTH);
+    } else if (objPrediction.kind() == type::UnsizedArray) {
+        MInstruction *lengthValue = MLoadFixedSlot::New(alloc(), obj, OutlineTypedObject::LENGTH_SLOT);
         current->add(lengthValue);
 
         MInstruction *length32 = MTruncateToInt32::New(alloc(), lengthValue);
         current->add(length32);
 
         length = length32;
 
         // If we are loading the length from the object itself,
         // then we do not need an extra neuter check, because the length
         // will have been set to 0 when the object was neutered.
         *canBeNeutered = false;
+    } else {
+        return false;
     }
 
     index = addBoundsCheck(idInt32, length);
 
     // Since we passed the bounds check, it is impossible for the
     // result of multiplication to overflow; so enable imul path.
     MMul *mul = MMul::New(alloc(), index, constantInt(elemSize),
                           MIRType_Int32, MMul::Integer);
@@ -7265,17 +7267,17 @@ IonBuilder::getElemTryScalarElemOfTypedO
     ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
     MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
 
     bool canBeNeutered;
     MDefinition *indexAsByteOffset;
     if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction,
                                        &indexAsByteOffset, &canBeNeutered))
     {
-        return false;
+        return true;
     }
 
     return pushScalarLoadFromTypedObject(emitted, obj, indexAsByteOffset, elemType, canBeNeutered);
 }
 
 bool
 IonBuilder::pushScalarLoadFromTypedObject(bool *emitted,
                                           MDefinition *obj,
@@ -7330,17 +7332,17 @@ IonBuilder::getElemTryComplexElemOfTyped
     MDefinition *type = loadTypedObjectType(obj);
     MDefinition *elemTypeObj = typeObjectForElementFromArrayStructType(type);
 
     bool canBeNeutered;
     MDefinition *indexAsByteOffset;
     if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction,
                                        &indexAsByteOffset, &canBeNeutered))
     {
-        return false;
+        return true;
     }
 
     return pushDerivedTypedObject(emitted, obj, indexAsByteOffset,
                                   elemPrediction, elemTypeObj, canBeNeutered);
 }
 
 bool
 IonBuilder::pushDerivedTypedObject(bool *emitted,
@@ -8120,17 +8122,17 @@ IonBuilder::setElemTryScalarElemOfTypedO
     ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
     MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
 
     bool canBeNeutered;
     MDefinition *indexAsByteOffset;
     if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction,
                                        &indexAsByteOffset, &canBeNeutered))
     {
-        return false;
+        return true;
     }
 
     // Store the element
     if (!storeScalarTypedObjectValue(obj, indexAsByteOffset, elemType, canBeNeutered, false, value))
         return false;
 
     current->push(value);
 
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -4138,38 +4138,43 @@ class LTypedObjectElements : public LIns
         return getOperand(0);
     }
     const MTypedObjectElements *mir() const {
         return mir_->toTypedObjectElements();
     }
 };
 
 // Load a typed array's elements vector.
-class LSetTypedObjectOffset : public LInstructionHelper<0, 2, 1>
+class LSetTypedObjectOffset : public LInstructionHelper<0, 2, 2>
 {
   public:
     LIR_HEADER(SetTypedObjectOffset)
 
     LSetTypedObjectOffset(const LAllocation &object,
                           const LAllocation &offset,
-                          const LDefinition &temp0)
+                          const LDefinition &temp0,
+                          const LDefinition &temp1)
     {
         setOperand(0, object);
         setOperand(1, offset);
         setTemp(0, temp0);
+        setTemp(1, temp1);
     }
     const LAllocation *object() {
         return getOperand(0);
     }
     const LAllocation *offset() {
         return getOperand(1);
     }
     const LDefinition *temp0() {
         return getTemp(0);
     }
+    const LDefinition *temp1() {
+        return getTemp(1);
+    }
 };
 
 // Check whether a typed object has a neutered owner buffer.
 class LNeuterCheck : public LInstructionHelper<0, 1, 1>
 {
   public:
     LIR_HEADER(NeuterCheck)
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2496,17 +2496,17 @@ LIRGenerator::visitTypedObjectElements(M
 }
 
 bool
 LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset *ins)
 {
     return add(new(alloc()) LSetTypedObjectOffset(
                    useRegister(ins->object()),
                    useRegister(ins->offset()),
-                   temp()),
+                   temp(), temp()),
                ins);
 }
 
 bool
 LIRGenerator::visitInitializedLength(MInitializedLength *ins)
 {
     MOZ_ASSERT(ins->elements()->type() == MIRType_Elements);
     return define(new(alloc()) LInitializedLength(useRegisterAtStart(ins->elements())), ins);
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -278,19 +278,22 @@ class ArrayBufferObject : public ArrayBu
                                 bool usesSignalHandlers);
     static bool prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObject*> buffer);
     static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
 
     static void finalize(FreeOp *fop, JSObject *obj);
 
     static BufferContents createMappedContents(int fd, size_t offset, size_t length);
 
-    static size_t flagsOffset() {
+    static size_t offsetOfFlagsSlot() {
         return getFixedSlotOffset(FLAGS_SLOT);
     }
+    static size_t offsetOfDataSlot() {
+        return getFixedSlotOffset(DATA_SLOT);
+    }
 
     static uint32_t neuteredFlag() { return NEUTERED_BUFFER; }
 
   protected:
     enum OwnsState {
         DoesntOwnData = 0,
         OwnsData = 1,
     };
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1864,32 +1864,32 @@ js_InitArrayBufferClass(JSContext *cx, H
 TypedArrayObject::isOriginalLengthGetter(Native native)
 {
     return native == TypedArray_lengthGetter;
 }
 
 const Class DataViewObject::protoClass = {
     "DataViewPrototype",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(TypedArrayLayout::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
 const Class DataViewObject::class_ = {
     "DataView",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_IMPLEMENTS_BARRIERS |
-    JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(TypedArrayLayout::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -40,32 +40,32 @@ class TypedArrayLayout
     const bool isShared_;
     const bool isNeuterable_;
     const Class *firstClass_;
     const Class *maxClass_;
 
   public:
     TypedArrayLayout(bool isShared, bool isNeuterable, const Class *firstClass, const Class *maxClass);
 
-    // Slot containing length of the view in number of typed elements.
-    static const size_t LENGTH_SLOT = JS_BUFVIEW_SLOT_LENGTH;
+    // Underlying (Shared)ArrayBufferObject.
+    static const size_t BUFFER_SLOT = 0;
 
-    // Underlying (Shared)ArrayBufferObject.
-    static const size_t BUFFER_SLOT = JS_BUFVIEW_SLOT_OWNER;
+    // Slot containing length of the view in number of typed elements.
+    static const size_t LENGTH_SLOT = 1;
 
     // Offset of view within underlying (Shared)ArrayBufferObject.
-    static const size_t BYTEOFFSET_SLOT = JS_BUFVIEW_SLOT_BYTEOFFSET;
+    static const size_t BYTEOFFSET_SLOT = 2;
 
-    static const size_t RESERVED_SLOTS = JS_TYPEDARR_SLOTS;
+    static const size_t RESERVED_SLOTS = 3;
 
     // The raw pointer to the buffer memory, the "private" value.
     //
     // This offset is exposed for performance reasons - so that it
     // need not be looked up on accesses.
-    static const size_t DATA_SLOT = JS_TYPEDARR_SLOT_DATA;
+    static const size_t DATA_SLOT = 3;
 
     static int lengthOffset();
     static int dataOffset();
 
     bool isSharedMemory() const { return isShared_; }
     bool isNeuterable() const { return isNeuterable_; }
     const Class *addressOfFirstClass() const { return firstClass_; }
     const Class *addressOfMaxClass() const { return maxClass_; }
@@ -298,19 +298,16 @@ TypedArrayShift(Scalar::Type viewType)
         return 3;
       default:;
     }
     MOZ_CRASH("Unexpected array type");
 }
 
 class DataViewObject : public NativeObject
 {
-    static const size_t RESERVED_SLOTS = JS_DATAVIEW_SLOTS;
-    static const size_t DATA_SLOT      = JS_DATAVIEW_SLOT_DATA;
-
   private:
     static const Class protoClass;
 
     static bool is(HandleValue v) {
         return v.isObject() && v.toObject().hasClass(&class_);
     }
 
     template <typename NativeType>