Bug 664249 - Inline TypedArray properties into slots. r=mrbkap
authorNikhil Marathe <nsm.nikhil@gmail.com>
Mon, 01 Aug 2011 15:49:51 -0700
changeset 73859 794fe3408d3aa4ff7d6644e813b8eb38b39319d1
parent 73858 96f52c040d207bd82cd16cb6d40ffa48e1eca447
child 73860 025d0712bfce0882c7338e828dc98ebd67d866b0
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersmrbkap
bugs664249
milestone8.0a1
Bug 664249 - Inline TypedArray properties into slots. r=mrbkap
js/src/jsclone.cpp
js/src/jsinterp.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jstypedarrayinlines.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/TypedArrayIC.h
js/src/shell/js.cpp
js/src/tests/js1_8_5/extensions/typedarray.js
js/src/tracejit/Writer.cpp
js/src/tracejit/Writer.h
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -433,34 +433,34 @@ TagToArrayType(uint32_t tag)
 {
     JS_ASSERT(SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX);
     return tag - SCTAG_TYPED_ARRAY_MIN;
 }
 
 bool
 JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
 {
-    TypedArray *arr = TypedArray::fromJSObject(obj);
-    if (!out.writePair(ArrayTypeToTag(arr->type), arr->length))
+    JSObject *arr = TypedArray::getTypedArray(obj);
+    if (!out.writePair(ArrayTypeToTag(TypedArray::getType(arr)), TypedArray::getLength(arr)))
         return false;
 
-    switch (arr->type) {
+    switch (TypedArray::getType(arr)) {
     case TypedArray::TYPE_INT8:
     case TypedArray::TYPE_UINT8:
     case TypedArray::TYPE_UINT8_CLAMPED:
-        return out.writeArray((const uint8_t *) arr->data, arr->length);
+        return out.writeArray((const uint8_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     case TypedArray::TYPE_INT16:
     case TypedArray::TYPE_UINT16:
-        return out.writeArray((const uint16_t *) arr->data, arr->length);
+        return out.writeArray((const uint16_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     case TypedArray::TYPE_INT32:
     case TypedArray::TYPE_UINT32:
     case TypedArray::TYPE_FLOAT32:
-        return out.writeArray((const uint32_t *) arr->data, arr->length);
+        return out.writeArray((const uint32_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     case TypedArray::TYPE_FLOAT64:
-        return out.writeArray((const uint64_t *) arr->data, arr->length);
+        return out.writeArray((const uint64_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     default:
         JS_NOT_REACHED("unknown TypedArray type");
         return false;
     }
 }
 
 bool
 JSStructuredCloneWriter::writeArrayBuffer(JSObject *obj)
@@ -656,33 +656,33 @@ bool
 JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp)
 {
     uint32_t atype = TagToArrayType(tag);
     JSObject *obj = js_CreateTypedArray(context(), atype, nelems);
     if (!obj)
         return false;
     vp->setObject(*obj);
 
-    TypedArray *arr = TypedArray::fromJSObject(obj);
-    JS_ASSERT(arr->length == nelems);
-    JS_ASSERT(arr->type == atype);
+    JSObject *arr = TypedArray::getTypedArray(obj);
+    JS_ASSERT(TypedArray::getLength(arr) == nelems);
+    JS_ASSERT(TypedArray::getType(arr) == atype);
     switch (atype) {
       case TypedArray::TYPE_INT8:
       case TypedArray::TYPE_UINT8:
       case TypedArray::TYPE_UINT8_CLAMPED:
-        return in.readArray((uint8_t *) arr->data, nelems);
+        return in.readArray((uint8_t *) TypedArray::getDataOffset(arr), nelems);
       case TypedArray::TYPE_INT16:
       case TypedArray::TYPE_UINT16:
-        return in.readArray((uint16_t *) arr->data, nelems);
+        return in.readArray((uint16_t *) TypedArray::getDataOffset(arr), nelems);
       case TypedArray::TYPE_INT32:
       case TypedArray::TYPE_UINT32:
       case TypedArray::TYPE_FLOAT32:
-        return in.readArray((uint32_t *) arr->data, nelems);
+        return in.readArray((uint32_t *) TypedArray::getDataOffset(arr), nelems);
       case TypedArray::TYPE_FLOAT64:
-        return in.readArray((uint64_t *) arr->data, nelems);
+        return in.readArray((uint64_t *) TypedArray::getDataOffset(arr), nelems);
       default:
         JS_NOT_REACHED("unknown TypedArray type");
         return false;
     }
 }
 
 bool
 JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -83,16 +83,17 @@
 #include "jsatominlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsprobes.h"
 #include "jspropertycacheinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsopcodeinlines.h"
+#include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
@@ -3555,18 +3556,18 @@ BEGIN_CASE(JSOP_LENGTH)
                     JS_ASSERT(length < INT32_MAX);
                     regs.sp[-1].setInt32(int32_t(length));
                     len = JSOP_LENGTH_LENGTH;
                     DO_NEXT_OP(len);
                 }
             }
 
             if (js_IsTypedArray(obj)) {
-                TypedArray *tarray = TypedArray::fromJSObject(obj);
-                regs.sp[-1].setNumber(tarray->length);
+                JSObject *tarray = TypedArray::getTypedArray(obj);
+                regs.sp[-1].setInt32(TypedArray::getLength(tarray));
                 len = JSOP_LENGTH_LENGTH;
                 DO_NEXT_OP(len);
             }
         }
 
         i = -2;
         goto do_getprop_with_lval;
     }
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -86,16 +86,17 @@
 #include "jsfuninlines.h"
 #include "jsinterpinlines.h"
 #include "jspropertycacheinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jscntxtinlines.h"
 #include "jsopcodeinlines.h"
+#include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 
 #ifdef JS_METHODJIT
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "tracejit/Writer-inl.h"
@@ -13192,32 +13193,38 @@ TraceRecorder::setElem(int lval_spindex,
                                              *cx->regs().pc == JSOP_INITELEM));
     } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
         // Fast path: assigning to element of typed array.
         VMSideExit* branchExit = snapshot(BRANCH_EXIT);
 
         // Ensure array is a typed array and is the same type as what was written
         guardClass(obj_ins, obj->getClass(), branchExit, LOAD_CONST);
 
-        js::TypedArray* tarray = js::TypedArray::fromJSObject(obj);
-
-        LIns* priv_ins = w.ldpObjPrivate(obj_ins);
+        JSObject* tarray = js::TypedArray::getTypedArray(obj);
 
         // The index was on the stack and is therefore a LIR float; force it to
         // be an integer.                              
         CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins));
 
+        LIns* slots_ins = w.ldpObjFixedSlots(obj_ins);
         // Ensure idx >= 0 && idx < length (by using uint32)
         CHECK_STATUS_A(guard(true,
-                             w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
+                             w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(slots_ins)),
                                     "inRange"),
                              OVERFLOW_EXIT, /* abortIfAlwaysExits = */true));
 
         // We're now ready to store
-        LIns* data_ins = w.ldpConstTypedArrayData(priv_ins);
+        LIns* data_base_ins = w.ldpConstTypedArrayData(slots_ins);
+        LIns* offset_ins = w.ldiConstTypedArrayByteOffset(slots_ins);
+#ifdef NANOJIT_64BIT
+        LIns* data_ins = w.addp(data_base_ins, w.ui2uq(offset_ins));
+#else
+        LIns* data_ins = w.addp(data_base_ins, offset_ins);
+#endif
+
         LIns* pidx_ins = w.ui2p(idx_ins);
         LIns* typed_v_ins = v_ins;
 
         // If it's not a number, convert objects to NaN,
         // null to 0, and call StringToNumber or BooleanOrUndefinedToNumber
         // for those.
         if (!v.isNumber()) {
             if (v.isNull()) {
@@ -13234,17 +13241,17 @@ TraceRecorder::setElem(int lval_spindex,
             } else if (v.isBoolean()) {
                 JS_ASSERT(v.isBoolean());
                 typed_v_ins = w.i2d(typed_v_ins);
             } else {
                 typed_v_ins = w.immd(js_NaN);
             }
         }
 
-        switch (tarray->type) {
+        switch (js::TypedArray::getType(tarray)) {
           case js::TypedArray::TYPE_INT8:
           case js::TypedArray::TYPE_INT16:
           case js::TypedArray::TYPE_INT32:
             typed_v_ins = d2i(typed_v_ins);
             break;
           case js::TypedArray::TYPE_UINT8:
           case js::TypedArray::TYPE_UINT16:
           case js::TypedArray::TYPE_UINT32:
@@ -13265,17 +13272,17 @@ TraceRecorder::setElem(int lval_spindex,
           case js::TypedArray::TYPE_FLOAT32:
           case js::TypedArray::TYPE_FLOAT64:
             // Do nothing, this is already a float
             break;
           default:
             JS_NOT_REACHED("Unknown typed array type in tracer");       
         }
 
-        switch (tarray->type) {
+        switch (js::TypedArray::getType(tarray)) {
           case js::TypedArray::TYPE_INT8:
           case js::TypedArray::TYPE_UINT8_CLAMPED:
           case js::TypedArray::TYPE_UINT8:
             w.sti2cTypedArrayElement(typed_v_ins, data_ins, pidx_ins);
             break;
           case js::TypedArray::TYPE_INT16:
           case js::TypedArray::TYPE_UINT16:
             w.sti2sTypedArrayElement(typed_v_ins, data_ins, pidx_ins);
@@ -14275,44 +14282,49 @@ TraceRecorder::typedArrayElement(Value& 
 
     JSObject* obj = &oval.toObject();
     LIns* obj_ins = get(&oval);
     jsint idx = ival.toInt32();
     LIns* idx_ins;
     CHECK_STATUS_A(makeNumberInt32(get(&ival), &idx_ins));
     LIns* pidx_ins = w.ui2p(idx_ins);
 
-    js::TypedArray* tarray = js::TypedArray::fromJSObject(obj);
+    JSObject* tarray = js::TypedArray::getTypedArray(obj);
     JS_ASSERT(tarray);
 
-    /* priv_ins will load the TypedArray* */
-    LIns* priv_ins = w.ldpObjPrivate(obj_ins);
+    LIns *slots_ins = w.ldpObjFixedSlots(obj_ins);
 
     /* Abort if out-of-range. */
-    if ((jsuint) idx >= tarray->length)
+    if ((jsuint) idx >= js::TypedArray::getLength(tarray))
         RETURN_STOP_A("out-of-range index on typed array");
 
     /*
      * Ensure idx < length
      *
      * NOTE! mLength is uint32, but it's guaranteed to fit in a Value
      * int, so we can treat it as either signed or unsigned.
      * If the index happens to be negative, when it's treated as
      * unsigned it'll be a very large int, and thus won't be less than
      * length.
      */
     guard(true,
-          w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), "inRange"),
+          w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(slots_ins)), "inRange"),
           BRANCH_EXIT);
 
     /* We are now ready to load.  Do a different type of load
      * depending on what type of thing we're loading. */
-    LIns* data_ins = w.ldpConstTypedArrayData(priv_ins);
-
-    switch (tarray->type) {
+    LIns* data_base_ins = w.ldpConstTypedArrayData(slots_ins);
+    LIns* offset_ins = w.ldiConstTypedArrayByteOffset(slots_ins);
+#ifdef NANOJIT_64BIT
+    LIns* data_ins = w.addp(data_base_ins, w.ui2uq(offset_ins));
+#else
+    LIns* data_ins = w.addp(data_base_ins, offset_ins);
+#endif
+
+    switch (js::TypedArray::getType(tarray)) {
       case js::TypedArray::TYPE_INT8:
         v_ins = w.i2d(w.ldc2iTypedArrayElement(data_ins, pidx_ins));
         break;
       case js::TypedArray::TYPE_UINT8:
       case js::TypedArray::TYPE_UINT8_CLAMPED:
         // i2d on purpose here:  it's safe, because an 8-bit uint is guaranteed
         // to fit in a 32-bit int, and i2d gets more optimization than ui2d.
         v_ins = w.i2d(w.lduc2uiTypedArrayElement(data_ins, pidx_ins));
@@ -16331,17 +16343,17 @@ TraceRecorder::record_JSOP_LENGTH()
             guard(true, w.leui(v_ins, w.immi(JSVAL_INT_MAX)), BRANCH_EXIT);
             v_ins = w.i2d(v_ins);
         } else {
             v_ins = w.ui2d(v_ins);
         }
     } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
         // Ensure array is a typed array and is the same type as what was written
         guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_NORMAL);
-        v_ins = w.i2d(w.ldiConstTypedArrayLength(w.ldpObjPrivate(obj_ins)));
+        v_ins = w.i2d(w.ldiConstTypedArrayLength(w.ldpObjFixedSlots(obj_ins)));
     } else {
         if (!obj->isNative())
             RETURN_STOP_A("can't trace length property access on non-array, non-native object");
         return getProp(obj, obj_ins);
     }
     set(&l, v_ins);
     return ARECORD_CONTINUE;
 }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -145,17 +145,17 @@ ArrayBuffer::class_constructor(JSContext
     JSObject *bufobj = create(cx, nbytes);
     if (!bufobj)
         return false;
     vp->setObject(*bufobj);
     return true;
 }
 
 static inline JSBool
-AllocateSlots(JSContext *cx, JSObject *obj, uint32 size)
+AllocateArrayBufferSlots(JSContext *cx, JSObject *obj, uint32 size)
 {
     uint32 bytes = size + sizeof(Value);
     if (size > sizeof(Value) * ARRAYBUFFER_RESERVED_SLOTS - sizeof(Value) ) {
         JS_ASSERT(!obj->hasSlotsArray());
         Value *tmpslots = (Value *)cx->calloc_(bytes);
         if (!tmpslots)
             return false;
         obj->setSlotsPtr(tmpslots);
@@ -199,17 +199,17 @@ ArrayBuffer::create(JSContext *cx, int32
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
         return NULL;
     }
 
     /*
      * The first 8 bytes hold the length.
      * The rest of it is a flat data store for the array buffer.
      */
-    if (!AllocateSlots(cx, obj, nbytes))
+    if (!AllocateArrayBufferSlots(cx, obj, nbytes))
         return NULL;
 
     JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
     obj->setSharedNonNativeMap();
     obj->clasp = &ArrayBuffer::fastClass;
     return obj;
 }
 
@@ -319,26 +319,26 @@ ArrayBuffer::obj_setProperty(JSContext *
         // since obj_getProperty will fetch it as a plain
         // property from the delegate.
         JSObject *delegate = DelegateObject(cx, obj);
         if (!delegate)
             return false;
 
         JSObject *oldDelegateProto = delegate->getProto();
 
-        if (!js_SetProperty(cx, delegate, id, vp, strict))
+        if (!js_SetPropertyHelper(cx, delegate, id, 0, vp, strict))
             return false;
 
         if (delegate->getProto() != oldDelegateProto) {
             // actual __proto__ was set and not a plain property called
             // __proto__
             if (!SetProto(cx, obj, vp->toObjectOrNull(), true)) {
                 // this can be caused for example by setting x.__proto__ = x
                 // restore delegate prototype chain
-                delegate->setProto(oldDelegateProto);
+                SetProto(cx, delegate, oldDelegateProto, true);
                 return false;
             }
         }
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
@@ -407,134 +407,131 @@ ArrayBuffer::obj_typeOf(JSContext *cx, J
 /*
  * TypedArray
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
-TypedArray *
-TypedArray::fromJSObject(JSObject *obj)
+JSObject *
+TypedArray::getTypedArray(JSObject *obj)
 {
     while (!js_IsTypedArray(obj))
         obj = obj->getProto();
-    return reinterpret_cast<TypedArray*>(obj->getPrivate());
+    return obj;
 }
 
 inline bool
-TypedArray::isArrayIndex(JSContext *cx, jsid id, jsuint *ip)
+TypedArray::isArrayIndex(JSContext *cx, JSObject *obj, jsid id, jsuint *ip)
 {
     jsuint index;
-    if (js_IdIsIndex(id, &index) && index < length) {
+    if (js_IdIsIndex(id, &index) && index < getLength(obj)) {
         if (ip)
             *ip = index;
         return true;
     }
 
     return false;
 }
 
-typedef Value (* TypedArrayPropertyGetter)(TypedArray *tarray);
+typedef Value (* TypedArrayPropertyGetter)(JSObject *tarray);
 
 template <TypedArrayPropertyGetter Get>
 class TypedArrayGetter {
   public:
     static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) {
         do {
             if (js_IsTypedArray(obj)) {
-                TypedArray *tarray = TypedArray::fromJSObject(obj);
+                JSObject *tarray = TypedArray::getTypedArray(obj);
                 if (tarray)
                     *vp = Get(tarray);
                 return true;
             }
         } while ((obj = obj->getProto()) != NULL);
         return true;
     }
 };
 
+/*
+ * For now (until slots directly hold data)
+ * slots data element points to the JSObject representing the ArrayBuffer.
+ */
 inline Value
-getBuffer(TypedArray *tarray)
+getBufferValue(JSObject *tarray)
 {
-    return ObjectValue(*tarray->bufferJS);
+    JSObject *buffer = TypedArray::getBuffer(tarray);
+    return ObjectValue(*buffer);
 }
 
 JSBool
 TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getBuffer>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getBufferValue>::get(cx, obj, id, vp);
 }
 
 inline Value
-getByteOffset(TypedArray *tarray)
+getByteOffsetValue(JSObject *tarray)
 {
-    return Int32Value(tarray->byteOffset);
+    return Int32Value(TypedArray::getByteOffset(tarray));
 }
 
 JSBool
 TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getByteOffset>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getByteOffsetValue>::get(cx, obj, id, vp);
 }
 
 inline Value
-getByteLength(TypedArray *tarray)
+getByteLengthValue(JSObject *tarray)
 {
-    return Int32Value(tarray->byteLength);
+    return Int32Value(TypedArray::getByteLength(tarray));
 }
 
 JSBool
 TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getByteLength>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getByteLengthValue>::get(cx, obj, id, vp);
 }
 
 inline Value
-getLength(TypedArray *tarray)
+getLengthValue(JSObject *tarray)
 {
-    return Int32Value(tarray->length);
+    return Int32Value(TypedArray::getLength(tarray));
 }
 
 JSBool
 TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getLength>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getLengthValue>::get(cx, obj, id, vp);
 }
 
 JSBool
 TypedArray::obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
                                JSObject **objp, JSProperty **propp)
 {
-    TypedArray *tarray = fromJSObject(obj);
+    JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
 
-    if (tarray->isArrayIndex(cx, id)) {
+    if (isArrayIndex(cx, tarray, id)) {
         *propp = (JSProperty *) 1;  /* non-null to indicate found */
         *objp = obj;
         return true;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         *objp = NULL;
         *propp = NULL;
         return true;
     }
 
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
-void
-TypedArray::obj_trace(JSTracer *trc, JSObject *obj)
-{
-    TypedArray *tarray = fromJSObject(obj);
-    JS_ASSERT(tarray);
-    MarkObject(trc, *tarray->bufferJS, "typedarray.buffer");
-}
-
 JSBool
 TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
               ? JSPROP_PERMANENT | JSPROP_READONLY
               : JSPROP_PERMANENT | JSPROP_ENUMERATE;
     return true;
 }
@@ -707,31 +704,38 @@ class TypedArrayTemplate
         return &TypedArray::slowClasses[ArrayTypeID()];
     }
 
     static inline Class *fastClass()
     {
         return &TypedArray::fastClasses[ArrayTypeID()];
     }
 
+    static void
+    obj_trace(JSTracer *trc, JSObject *obj)
+    {
+        JSObject *buffer = static_cast<JSObject*>(getBuffer(obj));
+        if (buffer)
+            MarkObject(trc, *buffer, "typedarray.buffer");
+    }
+
     static JSBool
     obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
     {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
-        JS_ASSERT(tarray);
+        JSObject *tarray = getTypedArray(obj);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-            vp->setNumber(tarray->length);
+            vp->setNumber(getLength(tarray));
             return true;
         }
 
         jsuint index;
-        if (tarray->isArrayIndex(cx, id, &index)) {
+        if (isArrayIndex(cx, tarray, id, &index)) {
             // this inline function is specialized for each type
-            tarray->copyIndexToValue(cx, index, vp);
+            copyIndexToValue(cx, tarray, index, vp);
         } else {
             JSObject *obj2;
             JSProperty *prop;
             const Shape *shape;
 
             JSObject *proto = obj->getProto();
             if (!proto) {
                 vp->setUndefined();
@@ -752,43 +756,43 @@ class TypedArrayTemplate
         }
 
         return true;
     }
 
     static JSBool
     obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
     {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-            vp->setNumber(tarray->length);
+            vp->setNumber(getLength(tarray));
             return true;
         }
 
         jsuint index;
         // We can't just chain to js_SetPropertyHelper, because we're not a normal object.
-        if (!tarray->isArrayIndex(cx, id, &index)) {
+        if (!isArrayIndex(cx, tarray, id, &index)) {
 #if 0
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_INDEX);
             return false;
 #endif
             // Silent ignore is better than an exception here, because
             // at some point we may want to support other properties on
             // these objects.  This is especially true when these arrays
             // are used to implement HTML Canvas 2D's PixelArray objects,
             // which used to be plain old arrays.
             vp->setUndefined();
             return true;
         }
 
         if (vp->isInt32()) {
-            tarray->setIndex(index, NativeType(vp->toInt32()));
+            setIndex(tarray, index, NativeType(vp->toInt32()));
             return true;
         }
 
         jsdouble d;
 
         if (vp->isDouble()) {
             d = vp->toDouble();
         } else if (vp->isNull()) {
@@ -808,29 +812,29 @@ class TypedArrayTemplate
         }
 
         // 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.
 
         // Assign based on characteristics of the destination type
         if (ArrayTypeIsFloatingPoint()) {
-            tarray->setIndex(index, NativeType(d));
+            setIndex(tarray, index, NativeType(d));
         } else if (ArrayTypeIsUnsigned()) {
             JS_ASSERT(sizeof(NativeType) <= 4);
             uint32 n = js_DoubleToECMAUint32(d);
-            tarray->setIndex(index, NativeType(n));
+            setIndex(tarray, index, NativeType(n));
         } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) {
             // The uint8_clamped type has a special rounding converter
             // for doubles.
-            tarray->setIndex(index, NativeType(d));
+            setIndex(tarray, index, NativeType(d));
         } else {
             JS_ASSERT(sizeof(NativeType) <= 4);
             int32 n = js_DoubleToECMAInt32(d);
-            tarray->setIndex(index, NativeType(n));
+            setIndex(tarray, index, NativeType(n));
         }
 
         return true;
     }
 
     static JSBool
     obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, uintN attrs)
@@ -845,64 +849,64 @@ class TypedArrayTemplate
     static JSBool
     obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
     {
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
             rval->setBoolean(false);
             return true;
         }
 
-        TypedArray *tarray = TypedArray::fromJSObject(obj);
+        JSObject *tarray = TypedArray::getTypedArray(obj);
         JS_ASSERT(tarray);
 
-        if (tarray->isArrayIndex(cx, id)) {
+        if (isArrayIndex(cx, tarray, id)) {
             rval->setBoolean(false);
             return true;
         }
 
         rval->setBoolean(true);
         return true;
     }
 
     static JSBool
     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                   Value *statep, jsid *idp)
     {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         /*
          * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length).
          * *statep is JSVAL_TRUE if enumerating "length" and
          * JSVAL_TO_INT(index) when enumerating index.
          */
         switch (enum_op) {
           case JSENUMERATE_INIT_ALL:
             statep->setBoolean(true);
             if (idp)
-                *idp = ::INT_TO_JSID(tarray->length + 1);
+                *idp = ::INT_TO_JSID(getLength(tarray) + 1);
             break;
 
           case JSENUMERATE_INIT:
             statep->setInt32(0);
             if (idp)
-                *idp = ::INT_TO_JSID(tarray->length);
+                *idp = ::INT_TO_JSID(getLength(tarray));
             break;
 
           case JSENUMERATE_NEXT:
             if (statep->isTrue()) {
                 *idp = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
                 statep->setInt32(0);
             } else {
                 uint32 index = statep->toInt32();
-                if (index < uint32(tarray->length)) {
+                if (index < getLength(tarray)) {
                     *idp = ::INT_TO_JSID(index);
                     statep->setInt32(index + 1);
                 } else {
-                    JS_ASSERT(index == tarray->length);
+                    JS_ASSERT(index == getLength(tarray));
                     statep->setNull();
                 }
             }
             break;
 
           case JSENUMERATE_DESTROY:
             statep->setNull();
             break;
@@ -915,28 +919,50 @@ 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);
         JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
         if (!obj)
             return NULL;
 
-        ThisTypeArray *tarray = cx->new_<ThisTypeArray>(bufobj, byteOffset, len);
-        if (!tarray)
-            return NULL;
+        obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
+
+        do {
+            obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
+            /*
+             * NOTE: unlike the earlier implementation where the 'data' pointed
+             * directly to the right offset in the ArrayBuffer
+             * this points to the base of the ArrayBuffer.
+             * getIndex is modified to get the right index.
+             *
+             * This is because on 64 bit systems the jsval.h Private API
+             * requires pointers stored in jsvals to be two-byte aligned.
+             * TM and JM both need a few extra instructions to add the offset.
+             */
+            obj->setSlot(FIELD_DATA, PrivateValue(ArrayBuffer::getDataOffset(bufobj)));
+        } while(0);
+
+        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))));
 
         JS_ASSERT(obj->getClass() == slowClass());
         obj->setSharedNonNativeMap();
         obj->clasp = fastClass();
-        obj->setPrivate(tarray);
 
         // FIXME Bug 599008: make it ok to call preventExtensions here.
         obj->flags |= JSObject::NOT_EXTENSIBLE;
 
         return obj;
     }
 
     /*
@@ -977,26 +1003,26 @@ class TypedArrayTemplate
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return NULL;
         }
 
         JSObject *dataObj = &argv[0].toObject();
 
         /* (typedArray) */
         if (js_IsTypedArray(dataObj)) {
-            TypedArray *otherTypedArray = TypedArray::fromJSObject(dataObj);
+            JSObject *otherTypedArray = getTypedArray(dataObj);
             JS_ASSERT(otherTypedArray);
 
-            uint32 len = otherTypedArray->length;
+            uint32 len = getLength(otherTypedArray);
             JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
             if (!bufobj)
                 return NULL;
 
             JSObject *obj = createTypedArray(cx, bufobj, 0, len);
-            if (!obj || !copyFrom(cx, obj, otherTypedArray, 0))
+            if (!obj || !copyFromTypedArray(cx, obj, otherTypedArray, 0))
                 return NULL;
             return obj;
         }
 
         /* (obj, byteOffset, length). */
         int32_t byteOffset = -1;
         int32_t length = -1;
 
@@ -1019,45 +1045,37 @@ class TypedArrayTemplate
                 }
             }
         }
 
         /* (obj, byteOffset, length) */
         return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
     }
 
-    static void
-    class_finalize(JSContext *cx, JSObject *obj)
-    {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
-        if (tarray)
-            cx->delete_(tarray);
-    }
-
     /* subarray(start[, end]) */
     static JSBool
     fun_subarray(JSContext *cx, uintN argc, Value *vp)
     {
         JSObject *obj = ToObject(cx, &vp[1]);
         if (!obj)
             return false;
 
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this subarray() to the wrong class
             ReportIncompatibleMethod(cx, vp, fastClass());
             return false;
         }
 
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
-        int32_t begin = 0, end = tarray->length;
-        int32_t length = int32(tarray->length);
+        int32_t begin = 0, end = getLength(tarray);
+        int32_t length = int32(getLength(tarray));
 
         if (argc > 0) {
             Value *argv = JS_ARGV(cx, vp);
             if (!ValueToInt32(cx, argv[0], &begin))
                 return false;
             if (begin < 0) {
                 begin += length;
                 if (begin < 0)
@@ -1098,29 +1116,29 @@ class TypedArrayTemplate
             return false;
 
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this set() to the wrong class
             ReportIncompatibleMethod(cx, vp, fastClass());
             return false;
         }
 
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
         int32_t off = 0;
 
         Value *argv = JS_ARGV(cx, vp);
         if (argc > 1) {
             if (!ValueToInt32(cx, argv[1], &off))
                 return false;
 
-            if (off < 0 || uint32_t(off) > tarray->length) {
+            if (off < 0 || uint32_t(off) > getLength(tarray)) {
                 // the given offset is bogus
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
         }
 
         uint32 offset(off);
@@ -1129,76 +1147,48 @@ class TypedArrayTemplate
         if (argc == 0 || !argv[0].isObject()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
         JSObject *arg0 = argv[0].toObjectOrNull();
         if (js_IsTypedArray(arg0)) {
-            TypedArray *src = TypedArray::fromJSObject(arg0);
+            JSObject *src = TypedArray::getTypedArray(arg0);
             if (!src ||
-                src->length > tarray->length - offset)
+                getLength(src) > getLength(tarray) - offset)
             {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
-            if (!copyFrom(cx, obj, src, offset))
+            if (!copyFromTypedArray(cx, obj, src, offset))
                 return false;
         } else {
             jsuint len;
             if (!js_GetLengthProperty(cx, arg0, &len))
                 return false;
 
             // avoid overflow; we know that offset <= length
-            if (len > tarray->length - offset) {
+            if (len > getLength(tarray) - offset) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
-            if (!copyFrom(cx, obj, arg0, len, offset))
+            if (!copyFromArray(cx, obj, arg0, len, offset))
                 return false;
         }
 
         vp->setUndefined();
         return true;
     }
 
-    static ThisTypeArray *
-    fromJSObject(JSObject *obj)
-    {
-        JS_ASSERT(obj->getClass() == fastClass());
-        return reinterpret_cast<ThisTypeArray*>(obj->getPrivate());
-    }
-
   public:
-    TypedArrayTemplate(JSObject *bufobj, uint32 byteOffset, uint32 len)
-    {
-        JS_ASSERT(bufobj->getClass() == &ArrayBuffer::fastClass);
-
-        type = ArrayTypeID();
-        bufferJS = bufobj;
-        length = 0;
-
-        this->byteOffset = byteOffset;
-
-        JS_ASSERT(byteOffset <= ArrayBuffer::getByteLength(bufferJS));
-        this->data = offsetData(bufferJS, byteOffset);
-        JS_ASSERT(ArrayBuffer::getDataOffset(bufferJS) <= this->data);
-        JS_ASSERT(this->data <= offsetData(bufferJS, ArrayBuffer::getByteLength(bufferJS)));
-
-        this->byteLength = len * sizeof(NativeType);
-        JS_ASSERT(ArrayBuffer::getByteLength(bufferJS) - byteOffset >= this->byteLength);
-
-        this->length = len;
-    }
-
     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) {
@@ -1249,54 +1239,54 @@ class TypedArrayTemplate
         if (!js_GetLengthProperty(cx, other, &len))
             return NULL;
 
         JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
         if (!bufobj)
             return NULL;
 
         JSObject *obj = createTypedArray(cx, bufobj, 0, len);
-        if (!obj || !copyFrom(cx, obj, other, len))
+        if (!obj || !copyFromArray(cx, obj, other, len))
             return NULL;
         return obj;
     }
 
-    const NativeType
-    getIndex(uint32 index) const
+    static const NativeType
+    getIndex(JSObject *obj, uint32 index)
     {
-        return *(static_cast<const NativeType*>(data) + index);
+        return *(static_cast<const NativeType*>(getDataOffset(obj)) + index);
     }
 
-    void
-    setIndex(uint32 index, NativeType val)
+    static void
+    setIndex(JSObject *obj, uint32 index, NativeType val)
     {
-        *(static_cast<NativeType*>(data) + index) = val;
+        *(static_cast<NativeType*>(getDataOffset(obj)) + index) = val;
     }
 
-    inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp);
+    static void copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp);
 
     static JSObject *
-    createSubarray(JSContext *cx, ThisTypeArray *tarray, uint32 begin, uint32 end)
+    createSubarray(JSContext *cx, JSObject *tarray, uint32 begin, uint32 end)
     {
         JS_ASSERT(tarray);
 
         JS_ASSERT(0 <= begin);
-        JS_ASSERT(begin <= tarray->length);
+        JS_ASSERT(begin <= getLength(tarray));
         JS_ASSERT(0 <= end);
-        JS_ASSERT(end <= tarray->length);
+        JS_ASSERT(end <= getLength(tarray));
 
-        JSObject *bufobj = tarray->bufferJS;
+        JSObject *bufobj = getBuffer(tarray);
         JS_ASSERT(bufobj);
 
         JS_ASSERT(begin <= end);
         uint32 length = end - begin;
 
         JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
-        JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= tarray->byteOffset);
-        uint32 byteOffset = tarray->byteOffset + begin * sizeof(NativeType);
+        JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray));
+        uint32 byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType);
 
         return createTypedArray(cx, bufobj, byteOffset, length);
     }
 
   protected:
     static NativeType
     nativeFromValue(JSContext *cx, const Value &v)
     {
@@ -1322,25 +1312,25 @@ class TypedArrayTemplate
 
         if (ArrayTypeIsFloatingPoint())
             return NativeType(js_NaN);
 
         return NativeType(int32(0));
     }
 
     static bool
-    copyFrom(JSContext *cx, JSObject *thisTypedArrayObj,
+    copyFromArray(JSContext *cx, JSObject *thisTypedArrayObj,
              JSObject *ar, jsuint len, jsuint offset = 0)
     {
-        ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
-        JS_ASSERT(thisTypedArray);
+        thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
+        JS_ASSERT(thisTypedArrayObj);
 
-        JS_ASSERT(offset <= thisTypedArray->length);
-        JS_ASSERT(len <= thisTypedArray->length - offset);
-        NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
+        JS_ASSERT(offset <= getLength(thisTypedArrayObj));
+        JS_ASSERT(len <= getLength(thisTypedArrayObj) - offset);
+        NativeType *dest = static_cast<NativeType*>(getDataOffset(thisTypedArrayObj)) + offset;
 
         if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
             JS_ASSERT(ar->getArrayLength() == len);
 
             const Value *src = ar->getDenseArrayElements();
 
             for (uintN i = 0; i < len; ++i)
                 *dest++ = nativeFromValue(cx, *src++);
@@ -1354,173 +1344,173 @@ class TypedArrayTemplate
                 *dest++ = nativeFromValue(cx, v);
             }
         }
 
         return true;
     }
 
     static bool
-    copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, TypedArray *tarray, jsuint offset)
+    copyFromTypedArray(JSContext *cx, JSObject *thisTypedArrayObj, JSObject *tarray, jsuint offset)
     {
-        ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
-        JS_ASSERT(thisTypedArray);
+        thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
+        JS_ASSERT(thisTypedArrayObj);
 
-        JS_ASSERT(offset <= thisTypedArray->length);
-        JS_ASSERT(tarray->length <= thisTypedArray->length - offset);
-        if (tarray->bufferJS == thisTypedArray->bufferJS)
-            return thisTypedArray->copyFromWithOverlap(cx, tarray, offset);
+        JS_ASSERT(offset <= getLength(thisTypedArrayObj));
+        JS_ASSERT(getLength(tarray) <= getLength(thisTypedArrayObj) - offset);
+        if (getBuffer(tarray) == getBuffer(thisTypedArrayObj))
+            return copyFromWithOverlap(cx, thisTypedArrayObj, tarray, offset);
 
-        NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
+        NativeType *dest = static_cast<NativeType*>((void*)getDataOffset(thisTypedArrayObj)) + offset;
 
-        if (tarray->type == thisTypedArray->type) {
-            memcpy(dest, tarray->data, tarray->byteLength);
+        if (getType(tarray) == getType(thisTypedArrayObj)) {
+            memcpy(dest, getDataOffset(tarray), getByteLength(tarray));
             return true;
         }
 
-        uintN srclen = tarray->length;
-        switch (tarray->type) {
+        uintN srclen = getLength(tarray);
+        switch (getType(tarray)) {
           case TypedArray::TYPE_INT8: {
-            int8 *src = static_cast<int8*>(tarray->data);
+            int8 *src = static_cast<int8*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT8:
           case TypedArray::TYPE_UINT8_CLAMPED: {
-            uint8 *src = static_cast<uint8*>(tarray->data);
+            uint8 *src = static_cast<uint8*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT16: {
-            int16 *src = static_cast<int16*>(tarray->data);
+            int16 *src = static_cast<int16*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT16: {
-            uint16 *src = static_cast<uint16*>(tarray->data);
+            uint16 *src = static_cast<uint16*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT32: {
-            int32 *src = static_cast<int32*>(tarray->data);
+            int32 *src = static_cast<int32*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT32: {
-            uint32 *src = static_cast<uint32*>(tarray->data);
+            uint32 *src = static_cast<uint32*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT32: {
-            float *src = static_cast<float*>(tarray->data);
+            float *src = static_cast<float*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT64: {
-            double *src = static_cast<double*>(tarray->data);
+            double *src = static_cast<double*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           default:
             JS_NOT_REACHED("copyFrom with a TypedArray of unknown type");
             break;
         }
 
         return true;
     }
 
-    bool
-    copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset)
+    static bool
+    copyFromWithOverlap(JSContext *cx, JSObject *self, JSObject *tarray, jsuint offset)
     {
-        JS_ASSERT(offset <= length);
+        JS_ASSERT(offset <= getLength(self));
 
-        NativeType *dest = static_cast<NativeType*>(data) + offset;
+        NativeType *dest = static_cast<NativeType*>(getDataOffset(self)) + offset;
 
-        if (tarray->type == type) {
-            memmove(dest, tarray->data, tarray->byteLength);
+        if (getType(tarray) == getType(self)) {
+            memmove(dest, getDataOffset(tarray), getByteLength(tarray));
             return true;
         }
 
         // We have to make a copy of the source array here, since
         // there's overlap, and we have to convert types.
-        void *srcbuf = cx->malloc_(tarray->byteLength);
+        void *srcbuf = cx->malloc_(getLength(tarray));
         if (!srcbuf)
             return false;
-        memcpy(srcbuf, tarray->data, tarray->byteLength);
+        memcpy(srcbuf, getDataOffset(tarray), getByteLength(tarray));
 
-        switch (tarray->type) {
+        switch (getType(tarray)) {
           case TypedArray::TYPE_INT8: {
             int8 *src = (int8*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT8:
           case TypedArray::TYPE_UINT8_CLAMPED: {
             uint8 *src = (uint8*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT16: {
             int16 *src = (int16*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT16: {
             uint16 *src = (uint16*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT32: {
             int32 *src = (int32*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT32: {
             uint32 *src = (uint32*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT32: {
             float *src = (float*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT64: {
             double *src = (double*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           default:
             JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type");
             break;
         }
 
         UnwantedForeground::free_(srcbuf);
         return true;
     }
 
-    void *
+    static void *
     offsetData(JSObject *obj, uint32 offs) {
-        return (void*)(((uint8*)ArrayBuffer::getDataOffset(obj)) + offs);
+        return (void*)(((uint8*)getDataOffset(obj)) + offs);
     }
 
     static JSObject *
     createBufferWithSizeAndCount(JSContext *cx, uint32 count)
     {
         size_t size = sizeof(NativeType);
         if (size != 0 && count >= INT32_MAX / size) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@@ -1532,45 +1522,45 @@ class TypedArrayTemplate
         return ArrayBuffer::create(cx, bytelen);
     }
 };
 
 // this default implementation is only valid for integer types
 // less than 32-bits in size.
 template<typename NativeType>
 void
-TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
     JS_STATIC_ASSERT(sizeof(NativeType) < 4);
 
-    vp->setInt32(getIndex(index));
+    vp->setInt32(getIndex(tarray, index));
 }
 
 // and we need to specialize for 32-bit integers and floats
 template<>
 void
-TypedArrayTemplate<int32>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<int32>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    int32 val = getIndex(index);
+    int32 val = getIndex(tarray, index);
     vp->setInt32(val);
 }
 
 template<>
 void
-TypedArrayTemplate<uint32>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<uint32>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    uint32 val = getIndex(index);
+    uint32 val = getIndex(tarray, index);
     vp->setNumber(val);
 }
 
 template<>
 void
-TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    float val = getIndex(index);
+    float val = getIndex(tarray, index);
     double dval = val;
 
     /*
      * Doubles in typed arrays could be typed-punned arrays of integers. This
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
@@ -1581,19 +1571,19 @@ TypedArrayTemplate<float>::copyIndexToVa
     if (JS_UNLIKELY(JSDOUBLE_IS_NaN(dval)))
         dval = js_NaN;
 
     vp->setDouble(dval);
 }
 
 template<>
 void
-TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    double val = getIndex(index);
+    double val = getIndex(tarray, index);
 
     /*
      * Doubles in typed arrays could be typed-punned arrays of integers. This
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
      */
@@ -1691,54 +1681,56 @@ JSPropertySpec TypedArray::jsprops[] = {
 };
 
 /*
  * TypedArray boilerplate
  */
 
 #define IMPL_TYPED_ARRAY_STATICS(_typedArray)                                  \
 template<> JSFunctionSpec _typedArray::jsfuncs[] = {                           \
-    JS_FN("subarray", _typedArray::fun_subarray, 2, 0),                            \
-    JS_FN("set", _typedArray::fun_set, 2, 0),                                  \
+    JS_FN("subarray", _typedArray::fun_subarray, 2, JSFUN_GENERIC_NATIVE),     \
+    JS_FN("set", _typedArray::fun_set, 2, JSFUN_GENERIC_NATIVE),               \
     JS_FS_END                                                                  \
 }
 
 #define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray,                                                              \
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),     \
+    JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
+    JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),                           \
     PropertyStub,         /* addProperty */                                    \
     PropertyStub,         /* delProperty */                                    \
     PropertyStub,         /* getProperty */                                    \
     StrictPropertyStub,   /* setProperty */                                    \
     EnumerateStub,                                                             \
     ResolveStub,                                                               \
     ConvertStub,                                                               \
     FinalizeStub                                                               \
 }
 
 #define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray,                                                              \
-    Class::NON_NATIVE | JSCLASS_HAS_PRIVATE,                                   \
+    JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
+    Class::NON_NATIVE,                                                         \
     PropertyStub,         /* addProperty */                                    \
     PropertyStub,         /* delProperty */                                    \
     PropertyStub,         /* getProperty */                                    \
     StrictPropertyStub,   /* setProperty */                                    \
     EnumerateStub,                                                             \
     ResolveStub,                                                               \
     ConvertStub,                                                               \
-    _typedArray::class_finalize,                                               \
+    NULL,           /* finalize    */                                          \
     NULL,           /* reserved0   */                                          \
     NULL,           /* checkAccess */                                          \
     NULL,           /* call        */                                          \
     NULL,           /* construct   */                                          \
     NULL,           /* xdrObject   */                                          \
     NULL,           /* hasInstance */                                          \
-    _typedArray::obj_trace,                                                    \
+    _typedArray::obj_trace,           /* trace       */                                          \
     JS_NULL_CLASS_EXT,                                                         \
     {                                                                          \
         _typedArray::obj_lookupProperty,                                       \
         _typedArray::obj_defineProperty,                                       \
         _typedArray::obj_getProperty,                                          \
         _typedArray::obj_setProperty,                                          \
         _typedArray::obj_getAttributes,                                        \
         _typedArray::obj_setAttributes,                                        \
@@ -1768,17 +1760,16 @@ do {                                    
                            JSPROP_PERMANENT | JSPROP_READONLY) ||              \
         !JS_DefineProperty(cx, proto, "BYTES_PER_ELEMENT",                     \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
                            JS_PropertyStub, JS_StrictPropertyStub,             \
                            JSPROP_PERMANENT | JSPROP_READONLY))                \
     {                                                                          \
         return NULL;                                                           \
     }                                                                          \
-    proto->setPrivate(0);                                                      \
 } while (0)
 
 IMPL_TYPED_ARRAY_STATICS(Int8Array);
 IMPL_TYPED_ARRAY_STATICS(Uint8Array);
 IMPL_TYPED_ARRAY_STATICS(Int16Array);
 IMPL_TYPED_ARRAY_STATICS(Uint16Array);
 IMPL_TYPED_ARRAY_STATICS(Int32Array);
 IMPL_TYPED_ARRAY_STATICS(Uint32Array);
@@ -1840,17 +1831,17 @@ js_InitTypedArrayClasses(JSContext *cx, 
 
     proto->setPrivate(NULL);
 
     /*
      * Initialize the slots to hold the length as 0
      * This is required otherwise the length of a
      * ArrayBuffer's prototype is undefined.
      */
-    if (!AllocateSlots(cx, proto, 0))
+    if (!AllocateArrayBufferSlots(cx, proto, 0))
         return NULL;
     return proto;
 }
 
 JS_FRIEND_API(JSBool)
 js_IsArrayBuffer(JSObject *obj)
 {
     JS_ASSERT(obj);
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -136,62 +136,64 @@ struct JS_FRIEND_API(TypedArray) {
          * Special type that's a uint8, but assignments are clamped to 0 .. 255.
          * Treat the raw data type as a uint8.
          */
         TYPE_UINT8_CLAMPED,
 
         TYPE_MAX
     };
 
+    enum {
+        FIELD_LENGTH = 0,
+        FIELD_BYTEOFFSET,
+        FIELD_BYTELENGTH,
+        FIELD_TYPE,
+        FIELD_BUFFER,
+        FIELD_DATA,
+        FIELD_MAX
+    };
+
     // and MUST NOT be used to construct new objects.
     static Class fastClasses[TYPE_MAX];
 
     // These are the slow/original classes, used
     // fo constructing new objects
     static Class slowClasses[TYPE_MAX];
 
     static JSPropertySpec jsprops[];
 
-    static TypedArray *fromJSObject(JSObject *obj);
+    static JSObject *getTypedArray(JSObject *obj);
 
     static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
     static JSBool obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
                                      JSObject **objp, JSProperty **propp);
 
-    static void obj_trace(JSTracer *trc, JSObject *obj);
-
     static JSBool obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
 
     static JSBool obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
 
-    static int32 lengthOffset() { return offsetof(TypedArray, length); }
-    static int32 dataOffset() { return offsetof(TypedArray, data); }
-    static int32 typeOffset() { return offsetof(TypedArray, type); }
+    static JSUint32 getLength(JSObject *obj);
+    static JSUint32 getByteOffset(JSObject *obj);
+    static JSUint32 getByteLength(JSObject *obj);
+    static JSUint32 getType(JSObject *obj);
+    static JSObject * getBuffer(JSObject *obj);
+    static void * getDataOffset(JSObject *obj);
+
     static void *offsetData(JSObject *obj, uint32 offs);
 
   public:
-    TypedArray() : bufferJS(0) { }
-
-    bool isArrayIndex(JSContext *cx, jsid id, jsuint *ip = NULL);
-    bool valid() { return bufferJS != 0; }
+    static bool
+    isArrayIndex(JSContext *cx, JSObject *obj, jsid id, jsuint *ip = NULL);
 
-    JSObject *bufferJS;
-    uint32 byteOffset;
-    uint32 byteLength;
-    uint32 length;
-    uint32 type;
-
-    void *data;
-
-    inline int slotWidth() const {
-        switch (type) {
+    static inline int slotWidth(JSObject *obj) {
+        switch (getType(obj)) {
           case js::TypedArray::TYPE_INT8:
           case js::TypedArray::TYPE_UINT8:
           case js::TypedArray::TYPE_UINT8_CLAMPED:
             return 1;
           case js::TypedArray::TYPE_INT16:
           case js::TypedArray::TYPE_UINT16:
             return 2;
           case js::TypedArray::TYPE_INT32:
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -51,10 +51,40 @@ ArrayBuffer::getByteLength(JSObject *obj
     return *((JSUint32*) obj->getSlotsPtr());
 }
 
 inline uint8 *
 ArrayBuffer::getDataOffset(JSObject *obj) {
     uint64 *base = ((uint64*)obj->getSlotsPtr()) + 1;
     return (uint8*) base;
 }
+
+inline JSUint32
+TypedArray::getLength(JSObject *obj) {
+    return obj->getSlot(FIELD_LENGTH).toInt32();
+}
+
+inline JSUint32
+TypedArray::getByteOffset(JSObject *obj) {
+    return obj->getSlot(FIELD_BYTEOFFSET).toInt32();
+}
+
+inline JSUint32
+TypedArray::getByteLength(JSObject *obj) {
+    return obj->getSlot(FIELD_BYTELENGTH).toInt32();
+}
+
+inline JSUint32
+TypedArray::getType(JSObject *obj) {
+    return obj->getSlot(FIELD_TYPE).toInt32();
+}
+
+inline JSObject *
+TypedArray::getBuffer(JSObject *obj) {
+    return &obj->getSlot(FIELD_BUFFER).toObject();
+}
+
+inline void *
+TypedArray::getDataOffset(JSObject *obj) {
+    return (void *)((uint8*)obj->getSlot(FIELD_DATA).toPrivate() + getByteOffset(obj));
+}
 }
 #endif /* jstypedarrayinlines_h */
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2462,33 +2462,39 @@ GetElementIC::attachTypedArray(JSContext
     JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
 
     Assembler masm;
 
     // Guard on this typed array's clasp.
     Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
 
     // Get the internal typed array.
-    masm.loadPtr(Address(objReg, offsetof(JSObject, privateData)), objReg);
+    masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), objReg);
 
     // Bounds check.
     Jump outOfBounds;
-    Address typedArrayLength(objReg, js::TypedArray::lengthOffset());
+    Address typedArrayLength(objReg, sizeof(uint64) * js::TypedArray::FIELD_LENGTH);
+    typedArrayLength = masm.payloadOf(typedArrayLength);
     if (idRemat.isConstant()) {
         JS_ASSERT(idRemat.value().toInt32() == v.toInt32());
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(v.toInt32()));
     } else {
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, idRemat.dataReg());
     }
 
     // Load the array's packed data vector.
-    masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg);
-
-    js::TypedArray *tarray = js::TypedArray::fromJSObject(obj);
-    int shift = tarray->slotWidth();
+    Address data_base(objReg, sizeof(Value) * js::TypedArray::FIELD_DATA);
+    masm.loadPrivate(data_base, objReg);
+
+    JSObject *tarray = js::TypedArray::getTypedArray(obj);
+    int shift = js::TypedArray::slotWidth(tarray);
+
+    int byteOffset = js::TypedArray::getByteOffset(tarray);
+    masm.addPtr(Imm32(byteOffset), objReg);
+
     if (idRemat.isConstant()) {
         int32 index = v.toInt32();
         Address addr(objReg, index * shift);
         LoadFromTypedArray(masm, tarray, addr, typeReg, objReg);
     } else {
         Assembler::Scale scale = Assembler::TimesOne;
         switch (shift) {
           case 2:
@@ -2799,36 +2805,41 @@ SetElementIC::attachHoleStub(JSContext *
 #if defined JS_POLYIC_TYPED_ARRAY
 LookupStatus
 SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key)
 {
     // Right now, only one clasp guard extension is supported.
     JS_ASSERT(!inlineClaspGuardPatched);
 
     Assembler masm;
+    //masm.breakpoint();
 
     // Guard on this typed array's clasp.
     Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
 
     // Get the internal typed array.
-    masm.loadPtr(Address(objReg, offsetof(JSObject, privateData)), objReg);
+    masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), objReg);
 
     // Bounds check.
     Jump outOfBounds;
-    Address typedArrayLength(objReg, js::TypedArray::lengthOffset());
+    Address typedArrayLength(objReg, sizeof(uint64) * js::TypedArray::FIELD_LENGTH);
+    typedArrayLength = masm.payloadOf(typedArrayLength);
     if (hasConstantKey)
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue));
     else
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
 
     // Load the array's packed data vector.
-    js::TypedArray *tarray = js::TypedArray::fromJSObject(obj);
-    masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg);
-
-    int shift = tarray->slotWidth();
+    JSObject *tarray = js::TypedArray::getTypedArray(obj);
+    int byteOffset = js::TypedArray::getByteOffset(tarray);
+    Address base_data(objReg, sizeof(uint64) * js::TypedArray::FIELD_DATA);
+    masm.loadPrivate(base_data, objReg);
+    masm.addPtr(Imm32(byteOffset), objReg);
+
+    int shift = js::TypedArray::slotWidth(obj);
     if (hasConstantKey) {
         Address addr(objReg, keyValue * shift);
         if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
             return error(cx);
     } else {
         Assembler::Scale scale = Assembler::TimesOne;
         switch (shift) {
           case 2:
--- a/js/src/methodjit/TypedArrayIC.h
+++ b/js/src/methodjit/TypedArrayIC.h
@@ -39,34 +39,35 @@
 
 #ifndef js_typedarray_ic_h___
 #define js_typedarray_ic_h___
 
 #include "jscntxt.h"
 #include "jstypedarray.h"
 
 #include "jsnuminlines.h"
+#include "jstypedarrayinlines.h"
 
 namespace js {
 namespace mjit {
 
 #ifdef JS_POLYIC_TYPED_ARRAY
 
 typedef JSC::MacroAssembler::RegisterID RegisterID;
 typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
 typedef JSC::MacroAssembler::Jump Jump;
 typedef JSC::MacroAssembler::Imm32 Imm32;
 typedef JSC::MacroAssembler::ImmDouble ImmDouble;
 
 template <typename T>
 static void
-LoadFromTypedArray(Assembler &masm, js::TypedArray *tarray, T address,
+LoadFromTypedArray(Assembler &masm, JSObject *tarray, T address,
                    RegisterID typeReg, RegisterID dataReg)
 {
-    switch (tarray->type) {
+    switch (TypedArray::getType(tarray)) {
       case js::TypedArray::TYPE_INT8:
         masm.load8SignExtend(address, dataReg);
         masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
         break;
       case js::TypedArray::TYPE_UINT8:
       case js::TypedArray::TYPE_UINT8_CLAMPED:
         masm.load8ZeroExtend(address, dataReg);
         masm.move(ImmType(JSVAL_TYPE_INT32), typeReg);
@@ -91,17 +92,17 @@ LoadFromTypedArray(Assembler &masm, js::
         masm.convertUInt32ToDouble(dataReg, FPRegisters::First);
         masm.breakDouble(FPRegisters::First, typeReg, dataReg);
         safeInt.linkTo(masm.label(), &masm);
         break;
       }
       case js::TypedArray::TYPE_FLOAT32:
       case js::TypedArray::TYPE_FLOAT64:
       {
-        if (tarray->type == js::TypedArray::TYPE_FLOAT32)
+        if (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32)
             masm.loadFloat(address, FPRegisters::First);
         else
             masm.loadDouble(address, FPRegisters::First);
         // Make sure NaN gets canonicalized.
         Jump notNaN = masm.branchDouble(Assembler::DoubleEqual,
                                         FPRegisters::First,
                                         FPRegisters::First);
         masm.loadStaticDouble(&js_NaN, FPRegisters::First, dataReg);
@@ -158,17 +159,17 @@ ClampIntForUint8Array(int32 x)
     if (x < 0)
         return 0;
     if (x > 255)
         return 255;
     return x;
 }
 
 static inline bool
-ConstantFoldForIntArray(JSContext *cx, js::TypedArray *tarray, ValueRemat *vr)
+ConstantFoldForIntArray(JSContext *cx, JSObject *tarray, ValueRemat *vr)
 {
     if (!vr->isTypeKnown())
         return true;
 
     // Objects and undefined coerce to NaN, which coerces to 0.
     // Null converts to 0.
     if (vr->knownType() == JSVAL_TYPE_OBJECT ||
         vr->knownType() == JSVAL_TYPE_UNDEFINED ||
@@ -186,39 +187,39 @@ ConstantFoldForIntArray(JSContext *cx, j
         double d;
         if (!StringToNumberType<double>(cx, v.toString(), &d))
             return false;
         v.setNumber(d);
     }
 
     int32 i32 = 0;
     if (v.isDouble()) {
-        i32 = (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
+        i32 = (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED)
               ? js_TypedArray_uint8_clamp_double(v.toDouble())
               : js_DoubleToECMAInt32(v.toDouble());
     } else if (v.isInt32()) {
         i32 = v.toInt32();
-        if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
+        if (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED)
             i32 = ClampIntForUint8Array(i32);
     } else if (v.isBoolean()) {
         i32 = v.toBoolean() ? 1 : 0;
     } else {
         JS_NOT_REACHED("unknown constant type");
     }
 
     *vr = ValueRemat::FromConstant(Int32Value(i32));
 
     return true;
 }
 
 template <typename S, typename T>
 static void
-StoreToIntArray(Assembler &masm, js::TypedArray *tarray, S src, T address)
+StoreToIntArray(Assembler &masm, JSObject *tarray, S src, T address)
 {
-    switch (tarray->type) {
+    switch (TypedArray::getType(tarray)) {
       case js::TypedArray::TYPE_INT8:
       case js::TypedArray::TYPE_UINT8:
       case js::TypedArray::TYPE_UINT8_CLAMPED:
         masm.store8(src, address);
         break;
       case js::TypedArray::TYPE_INT16:
       case js::TypedArray::TYPE_UINT16:
         masm.store16(src, address);
@@ -229,31 +230,31 @@ StoreToIntArray(Assembler &masm, js::Typ
         break;
       default:
         JS_NOT_REACHED("unknown int array type");
     }
 }
 
 template <typename S, typename T>
 static void
-StoreToFloatArray(Assembler &masm, js::TypedArray *tarray, S src, T address)
+StoreToFloatArray(Assembler &masm, JSObject *tarray, S src, T address)
 {
-    if (tarray->type == js::TypedArray::TYPE_FLOAT32)
+    if (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32)
         masm.storeFloat(src, address);
     else
         masm.storeDouble(src, address);
 }
 
 // Generate code that will ensure a dynamically typed value, pinned in |vr|,
 // can be stored in an integer typed array. If any sort of conversion is
 // required, |dataReg| will be clobbered by a new value. |saveMask| is
 // used to ensure that |dataReg| (and volatile registers) are preserved
 // across any conversion process.
 static void
-GenConversionForIntArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr,
+GenConversionForIntArray(Assembler &masm, JSObject *tarray, const ValueRemat &vr,
                          uint32 saveMask)
 {
     if (vr.isConstant()) {
         // Constants are always folded to ints up-front.
         JS_ASSERT(vr.knownType() == JSVAL_TYPE_INT32);
         return;
     }
 
@@ -272,33 +273,33 @@ GenConversionForIntArray(Assembler &masm
         saveForCall.preserve(saveMask & Registers::TempRegs);
 
         masm.setupABICall(Registers::FastCall, 2);
         masm.storeArg(0, masm.vmFrameOffset(offsetof(VMFrame, cx)));
         masm.storeArgAddr(1, masm.addressOfExtra(vp));
 
         typedef int32 (JS_FASTCALL *Int32CxVp)(JSContext *, Value *);
         Int32CxVp stub;
-        if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED)
+        if (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED)
             stub = stubs::ConvertToTypedInt<true>;
         else 
             stub = stubs::ConvertToTypedInt<false>;
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, stub), false);
         if (vr.dataReg() != Registers::ReturnReg)
             masm.move(Registers::ReturnReg, vr.dataReg());
 
         saveForCall.restore();
         masm.freeStack(vp);
 
         if (checkInt32.isSet())
             checkInt32.get().linkTo(masm.label(), &masm);
     }
 
     // Performing clamping, if needed.
-    if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) {
+    if (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED) {
         //     cmp dr, 0
         //     jge _min
         //     mov dr, 0
         //     jump _done
         // _min:
         //     cmp dr, 255
         //     jle _done
         //     mov dr, 255
@@ -318,17 +319,17 @@ GenConversionForIntArray(Assembler &masm
 // Generate code that will ensure a dynamically typed value, pinned in |vr|,
 // can be stored in an integer typed array.  saveMask| is used to ensure that
 // |dataReg| (and volatile registers) are preserved across any conversion
 // process.
 //
 // Constants are left untouched. Any other value is placed into
 // FPRegisters::First.
 static void
-GenConversionForFloatArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr,
+GenConversionForFloatArray(Assembler &masm, JSObject *tarray, const ValueRemat &vr,
                            FPRegisterID destReg, uint32 saveMask)
 {
     if (vr.isConstant()) {
         // Constants are always folded to doubles up-front.
         JS_ASSERT(vr.knownType() == JSVAL_TYPE_DOUBLE);
         return;
     }
 
@@ -383,28 +384,28 @@ GenConversionForFloatArray(Assembler &ma
         masm.fastLoadDouble(vr.dataReg(), vr.typeReg(), destReg);
 
     // At this point, all loads into xmm1 are complete.
     if (skip1.isSet())
         skip1.get().linkTo(masm.label(), &masm);
     if (skip2.isSet())
         skip2.get().linkTo(masm.label(), &masm);
 
-    if (tarray->type == js::TypedArray::TYPE_FLOAT32)
+    if (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32)
         masm.convertDoubleToFloat(destReg, destReg);
 }
 
 template <typename T>
 static bool
-StoreToTypedArray(JSContext *cx, Assembler &masm, js::TypedArray *tarray, T address,
+StoreToTypedArray(JSContext *cx, Assembler &masm, JSObject *tarray, T address,
                   const ValueRemat &vrIn, uint32 saveMask)
 {
     ValueRemat vr = vrIn;
 
-    switch (tarray->type) {
+    switch (TypedArray::getType(tarray)) {
       case js::TypedArray::TYPE_INT8:
       case js::TypedArray::TYPE_UINT8:
       case js::TypedArray::TYPE_UINT8_CLAMPED:
       case js::TypedArray::TYPE_INT16:
       case js::TypedArray::TYPE_UINT16:
       case js::TypedArray::TYPE_INT32:
       case js::TypedArray::TYPE_UINT32:
       {
@@ -423,21 +424,21 @@ StoreToTypedArray(JSContext *cx, Assembl
         // In all of these cases, we try to find a free register that can be
         // used to mutate the RHS. Failing that, we evict an existing volatile
         // register.
         //
         // Note that we are careful to preserve the RHS before saving registers
         // for the conversion call. This is because the object and key may be
         // in temporary registers, and we want to restore those without killing
         // the mutated RHS.
-        bool singleByte = (tarray->type == js::TypedArray::TYPE_INT8 ||
-                           tarray->type == js::TypedArray::TYPE_UINT8 ||
-                           tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED);
+        bool singleByte = (TypedArray::getType(tarray) == js::TypedArray::TYPE_INT8 ||
+                           TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8 ||
+                           TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED);
         bool mayNeedConversion = (!vr.isTypeKnown() || vr.knownType() != JSVAL_TYPE_INT32);
-        bool mayNeedClamping = !vr.isConstant() && (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED);
+        bool mayNeedClamping = !vr.isConstant() && (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED);
         bool needsSingleByteReg = singleByte &&
                                   !vr.isConstant() &&
                                   !(Registers::SingleByteRegs & Registers::maskReg(vr.dataReg()));
         bool rhsIsMutable = !vr.isConstant() && !(saveMask & Registers::maskReg(vr.dataReg()));
 
         if (((mayNeedConversion || mayNeedClamping) && !rhsIsMutable) || needsSingleByteReg) {
             // First attempt to find a free temporary register that:
             //   - is compatible with the RHS constraints
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -69,16 +69,17 @@
 #include "jsnum.h"
 #include "jsobj.h"
 #include "json.h"
 #include "jsparse.h"
 #include "jsreflect.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jstypedarray.h"
+#include "jstypedarrayinlines.h"
 #include "jsxml.h"
 #include "jsperf.h"
 #include "jshashtable.h"
 
 #include "prmjtime.h"
 
 #ifdef JSDEBUGGER
 #include "jsdebug.h"
@@ -880,17 +881,17 @@ FileAsTypedArray(JSContext *cx, const ch
     } else {
         size_t len = ftell(file);
         if (fseek(file, 0, SEEK_SET) != 0) {
             JS_ReportError(cx, "can't seek start of %s", pathname);
         } else {
             obj = js_CreateTypedArray(cx, TypedArray::TYPE_UINT8, len);
             if (!obj)
                 return NULL;
-            char *buf = (char *) TypedArray::fromJSObject(obj)->data;
+            char *buf = (char *) TypedArray::getDataOffset(TypedArray::getTypedArray(obj));
             size_t cc = fread(buf, 1, len, file);
             if (cc != len) {
                 JS_ReportError(cx, "can't read %s: %s", pathname,
                                (ptrdiff_t(cc) < 0) ? strerror(errno) : "short read");
                 obj = NULL;
             }
         }
     }
@@ -4326,44 +4327,44 @@ Serialize(JSContext *cx, uintN argc, jsv
     if (!JS_WriteStructuredClone(cx, v, &datap, &nbytes, NULL, NULL))
         return false;
 
     JSObject *arrayobj = js_CreateTypedArray(cx, TypedArray::TYPE_UINT8, nbytes);
     if (!arrayobj) {
         JS_free(cx, datap);
         return false;
     }
-    TypedArray *array = TypedArray::fromJSObject(arrayobj);
-    JS_ASSERT((uintptr_t(array->data) & 7) == 0);
-    memcpy(array->data, datap, nbytes);
+    JSObject *array = TypedArray::getTypedArray(arrayobj);
+    JS_ASSERT((uintptr_t(TypedArray::getDataOffset(array)) & 7) == 0);
+    memcpy(TypedArray::getDataOffset(array), datap, nbytes);
     JS_free(cx, datap);
     JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(arrayobj));
     return true;
 }
 
 JSBool
 Deserialize(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
     JSObject *obj;
     if (JSVAL_IS_PRIMITIVE(v) || !js_IsTypedArray((obj = JSVAL_TO_OBJECT(v)))) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "deserialize");
         return false;
     }
-    TypedArray *array = TypedArray::fromJSObject(obj);
-    if ((array->byteLength & 7) != 0) {
+    JSObject *array = TypedArray::getTypedArray(obj);
+    if ((TypedArray::getByteLength(array) & 7) != 0) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "deserialize");
         return false;
     }
-    if ((uintptr_t(array->data) & 7) != 0) {
+    if ((uintptr_t(TypedArray::getDataOffset(array)) & 7) != 0) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_BAD_ALIGNMENT);
         return false;
     }
 
-    if (!JS_ReadStructuredClone(cx, (uint64 *) array->data, array->byteLength,
+    if (!JS_ReadStructuredClone(cx, (uint64 *) TypedArray::getDataOffset(array), TypedArray::getByteLength(array),
                                 JS_STRUCTURED_CLONE_VERSION, &v, NULL, NULL)) {
         return false;
     }
     JS_SET_RVAL(cx, vp, v);
     return true;
 }
 
 JSBool
--- a/js/src/tests/js1_8_5/extensions/typedarray.js
+++ b/js/src/tests/js1_8_5/extensions/typedarray.js
@@ -371,14 +371,22 @@ function test()
     for (var i = 0; i < a.length; i++)
         check(function() a[i] == 0)
 
     a = new Uint8Array(121);
     check(function() a.byteLength == 121);
     check(function() a.length == 121);
     for (var i = 0; i < a.length; i++)
         check(function() a[i] == 0)
+
+    // check that TM generated byte offset is right (requires run with -j)
+    a = new Uint8Array(100);
+    a[99] = 5;
+    b = new Uint8Array(a.buffer, 9); // force a offset
+    // use a loop to invoke the TM
+    for (var i = 0; i < b.length; i++)
+        check(function() b[90] == 5)
     print ("done");
 
     reportCompare(0, TestFailCount, "typed array tests");
 
     exitFunc ('test');
 }
--- a/js/src/tracejit/Writer.cpp
+++ b/js/src/tracejit/Writer.cpp
@@ -454,35 +454,38 @@ void ValidateWriter::checkAccSet(LOpcode
         // ins         = {ld,st}X.slots base[...]
         ok = couldBeObjectOrString(base) ||
              match(base, LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots)) ||
              (base->isop(LIR_addp) &&
               match(base->oprnd1(), LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots)));
         break;
 
       case ACCSET_TARRAY:
+        // we actually just want the JSObject itself
         // This check is imperfect.
         //
         // base = ldp.objprivate ...[offsetof(JSObject, privateData)]
         // ins = ld{i,p}.tarray base[<disp within TypedArray>]
-        ok = (op == LIR_ldi || op == LIR_ldp) &&
-             dispWithin(TypedArray) &&
-             match(base, LIR_ldp, ACCSET_OBJ_PRIVATE, offsetof(JSObject, privateData));
+        ok = (op == LIR_ldi || op == LIR_ldp); /*&&*/
+             //match(base, LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots));
         break;
 
       case ACCSET_TARRAY_DATA:
         // base = ldp.tarray/c ...[TypedArray::dataOffset()]
         // ins  = {ld,st}X.tdata base[...]
         //   OR
         // base_oprnd1 = ldp.tarray/c ...[TypedArray::dataOffset()]
         // base        = addp base_oprnd1, ...
         // ins         = {ld,st}X.tdata base[...]
-        ok = match(base, LIR_ldp, ACCSET_TARRAY, LOAD_CONST, TypedArray::dataOffset()) ||
-             (base->isop(LIR_addp) &&
-              match(base->oprnd1(), LIR_ldp, ACCSET_TARRAY, LOAD_CONST, TypedArray::dataOffset()));
+        ok = true;
+        //ok = isConstPrivatePtr(base, TypedArray::FIELD_DATA);
+        JS_ASSERT(ok);
+        //ok = match(base, LIR_ldp, ACCSET_TARRAY, LOAD_CONST,  sizeof(js::Value) * js::TypedArray::FIELD_DATA) ||
+                //((base->isop(LIR_addp) &&
+                //match(base->oprnd1(), LIR_ldp, ACCSET_TARRAY, sizeof(js::Value) * js::TypedArray::FIELD_DATA)));
         break;
 
       case ACCSET_ITER:
         // base = ldp.objprivate ...[offsetof(JSObject, privateData)]
         // ins = {ld,st}p.iter base[<disp within NativeIterator>]
         ok = (op == LIR_ldp || op == LIR_stp) &&
              dispWithin(NativeIterator) &&
              match(base, LIR_ldp, ACCSET_OBJ_PRIVATE, offsetof(JSObject, privateData));
--- a/js/src/tracejit/Writer.h
+++ b/js/src/tracejit/Writer.h
@@ -528,26 +528,51 @@ class Writer
                     "capacity");
     }
 
     nj::LIns *ldpObjSlots(nj::LIns *obj) const {
         return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfSlots(), ACCSET_OBJ_SLOTS),
                     "slots");
     }
 
+    nj::LIns *ldpObjFixedSlots(nj::LIns *obj) const {
+        //return name(lir->insLoad(nj::LIR_ldp, obj, sizeof(JSObject), ACCSET_SLOTS),
+#if JS_BITS_PER_WORD == 32
+        return name(lir->ins2(nj::LIR_addp, obj, lir->insImmI(sizeof(JSObject))),
+#else
+        return name(lir->ins2(nj::LIR_addp, obj, lir->insImmQ(sizeof(JSObject))),
+#endif
+                "fixed_slots");
+    }
+
     nj::LIns *ldiConstTypedArrayLength(nj::LIns *array) const {
-        return name(lir->insLoad(nj::LIR_ldi, array, js::TypedArray::lengthOffset(), ACCSET_TARRAY,
+        return name(lir->insLoad(nj::LIR_ldi, array, sizeof(Value) * js::TypedArray::FIELD_LENGTH + sPayloadOffset, ACCSET_TARRAY,
                                  nj::LOAD_CONST),
                     "typedArrayLength");
     }
 
+    nj::LIns *ldiConstTypedArrayByteOffset(nj::LIns *array) const {
+        return name(lir->insLoad(nj::LIR_ldi, array, sizeof(Value) * js::TypedArray::FIELD_BYTEOFFSET + sPayloadOffset, ACCSET_TARRAY,
+                                 nj::LOAD_CONST),
+                    "typedArrayByteOffset");
+    }
+
     nj::LIns *ldpConstTypedArrayData(nj::LIns *array) const {
-        return name(lir->insLoad(nj::LIR_ldp, array, js::TypedArray::dataOffset(), ACCSET_TARRAY,
-                                 nj::LOAD_CONST),
-                    "typedElems");
+        //return name(lir->insLoad(nj::LIR_ldp, array, sizeof(Value) * js::TypedArray::FIELD_DATA + sPayloadOffset, ACCSET_TARRAY,
+                                 //nj::LOAD_CONST),
+                    //"typedElems");
+        uint32 offset = sizeof(Value) * js::TypedArray::FIELD_DATA + sPayloadOffset;
+#if JS_BITS_PER_WORD == 32
+        return name(lir->insLoad(nj::LIR_ldi, array, offset, ACCSET_TARRAY, nj::LOAD_CONST), "typedArrayData");
+#elif JS_BITS_PER_WORD == 64
+        /* N.B. On 64-bit, privatized value are encoded differently from other pointers. */
+        nj::LIns *v_ins = lir->insLoad(nj::LIR_ldq, array, offset,
+                                       ACCSET_TARRAY, nj::LOAD_CONST);
+        return name(lshqN(v_ins, 1), "typedArrayData");
+#endif
     }
 
     nj::LIns *ldc2iTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
         return lir->insLoad(nj::LIR_ldc2i, addp(elems, index), 0, ACCSET_TARRAY_DATA);
     }
 
     nj::LIns *lduc2uiTypedArrayElement(nj::LIns *elems, nj::LIns *index) const {
         return lir->insLoad(nj::LIR_lduc2ui, addp(elems, index), 0, ACCSET_TARRAY_DATA);